欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

【总结】C++高性能服务器日志系统

时间:2023-04-30

C++高性能服务器

日志系统

前言

本文内容:日志系统 所属专栏:Linux高性能服务器 作者主页:紫荆鱼 创作时间:2022-2-26

返回目录(建议收藏):Linux C++高性能服务器Sylar跟写


[文章目录]

日志系统

1、运行展示2、遇到的困难3、代码 1、运行展示

最下面为输出格式日志信息

2、遇到的困难


这是困惑我1个月的问题,但是我发现代码的逻辑一点也没有问题,于是我百度“段错误(核心已转储)”是什么原因造成的:

栈溢出:于是我ulimit改变栈的大小,但是无效!内存泄漏: 我想到的是智能指针shared_ptr可能没有及时释放,导致内存泄漏,于是我排查了很久,发现一切正常阿。这一次我真的疯了,TM难道有野指针?内核段访问:不可能是这个原因,我彻底疯了。

我慢慢按照执行的顺序排查,发现“段错误点”,如下代码:

//m_formatter是LogFormatter的对象m_formatter->format(std::cout, logger, level, event);

我发现对象调用public function居然无法访问数据成员,天哪!难道代码也六亲不认? 这个问题困惑我3天时间,于是我怀疑:

shared_from_this()

返回的是另一个对象,但是要访问的是另一个对象的数据,造成越界访问,于是我很坚信就是这个错误,就这样有花掉我很多时间。最后依然无效。

最后方案:太搞笑了,我把

m_formatter.reset(new LogFormatter("%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"));

在构造函数中初始化了另一个类的m_formatter。这下我终于明白了!

3、代码

1.CMake

CMAKE_MINIMUM_REQUIRED(VERSION 3.16.3)PROJECT(angel)SET(CMAKE_VERBOSE_MAKEFILE ON)SET(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -rdynamic -O0 -ggdb -std=c++11 -Wall -Wno-deprecated -Werror -Wno-unused-function")SET(LIB_SRC angel/log.cpp )ADD_LIBRARY(angel SHARED ${LIB_SRC})#ADD_LIBRARY(angel_static STATIC ${LIB_SRC})#SET_TARGET_PROPERTIES(angel_static PROPERTIES OUTPUT_NAME "angel")ADD_EXECUTABLE(test tests/log_test.cpp)ADD_DEPENDENCIES(test angel)TARGET_link_LIBRARIES(test angel)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

log、h

#ifndef __ANGEL_LOG_H__#define __ANGEL_LOG_H__#include #include #include #include #include #include #include #include #include #include "singleton.h"#define ANGEL_LOG_ROOT() angel::LoggerMgr::GetInstance()->getRoot()namespace angel{class Logger; //日志级别类class LogLevel{public:enum Level{ UNKNOW = 0,DEBUG = 1,INFO =2,WARN =3,ERROR = 4,FATAL = 5}; //日志级别转化为文本输出 static const char* ToString(LogLevel::Level level); //文本转化为日志级别 static LogLevel::Level FromString(const std::string& str);};//日志事件类class LogEvent{public:typedef std::shared_ptr ptr; LogEvent(std::shared_ptr logger,LogLevel::Level level ,const char* file, int32_t line, uint32_t elapse ,uint32_t thread_id, uint32_t fiber_id, uint64_t time ,const std::string& thread_name); const char* getFile() const {return m_file;} int32_t getLine() const {return m_line;} uint32_t getElapse() const {return m_elapse;} uint32_t getThreadId() const {return m_threadId;} uint32_t getFiberId() const {return m_fiberId;} uint64_t getTime() const {return m_time;} const std::string& getThreadName() {return m_threadName;} std::stringstream& getSS() {return m_ss;} std::string getContent() const {return m_ss.str();} std::shared_ptr getLogger() const {return m_logger;} LogLevel::Level getLevel() const {return m_level;} //格式化写入日志 void format(const char* fmt, ...); void format(const char* fmt, va_list al); private:const char* m_file = nullptr; //文件名int32_t m_line = 0; //行号uint32_t m_elapse = 0; //进程启动起的毫秒数 uint32_t m_threadId = 0; //线程iduint32_t m_fiberId =0; //携程iduint64_t m_time = 0; //时间戳std::string m_threadName; //线程名称 std::stringstream m_ss; //日志内容流 std::shared_ptr m_logger; //日志器 LogLevel::Level m_level; //日志等级};//日志格式器//默认格式 "%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"class LogFormatter{public:typedef std::shared_ptr ptr;LogFormatter(const std::string& pattern); std::string format(std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event); std::ostream& format(std::ostream& ofs, std::shared_ptr logger,LogLevel::Level level, LogEvent::ptr event);public:class FormatItem{public:typedef std::shared_ptr ptr;virtual ~FormatItem(){} //格式化日志流virtual void format(std::ostream& os, std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event) = 0;}; //初始化解析日志模板 void init(); bool isError() const {return m_error;} //返回日志模板 const std::string getPattern() const {return m_pattern;}private: //日志模板 std::string m_pattern; //日志格式解析std::vector m_items; bool m_error = false;};//日志输出地类class LogAppender{ friend class Logger;public:typedef std::shared_ptr ptr;virtual ~LogAppender(){} //写入日志virtual void log(std::shared_ptr logger,LogLevel::Level level,LogEvent::ptr event,LogFormatter::ptr m_temp) = 0; //更改日志格式器void setFormatter(LogFormatter::ptr val); //获取日志格式器LogFormatter::ptr getFormatter(); //获取日志级别 LogLevel::Level getLevel() const {return m_level;}//设置日志级别 void setLevel(LogLevel::Level val) {m_level = val;}protected: //日志级别LogLevel::Level m_level = LogLevel::DEBUG; //是否有日志格式器 bool m_hasFormatter = false; //日志格式器LogFormatter::ptr m_formatter;};//日志器class Logger : public std::enable_shared_from_this{ friend class LoggerManager;public:typedef std::shared_ptr ptr;Logger(const std::string& name = "root"); //写日志void log(LogLevel::Level level, LogEvent::ptr event);//写不同级别的日志void debug(LogEvent::ptr event);void info(LogEvent::ptr event);void warn(LogEvent::ptr event);void error(LogEvent::ptr event);void fatal(LogEvent::ptr event);void addAppender(LogAppender::ptr appender);void delAppender(LogAppender::ptr appender); void clearAppender();LogLevel::Level getLevel() const {return m_level;}void setLevel(LogLevel::Level val){m_level = val;} const std::string& getName() const {return m_name;} //设置日志格式器 void setFormatter(LogFormatter::ptr val); //设置日志格式模板 void setFormatter(const std::string& val); //获取日志格式器 LogFormatter::ptr getFormatter();private:std::string m_name;//日志名称LogLevel::Level m_level;//日志级别std::list m_appenders;//Appender集合 LogFormatter::ptr m_formatter; //日志格式器 Logger::ptr m_root; //主日志器};//日志输出到控制台class StdoutLogAppender: public LogAppender{public:typedef std::shared_ptr ptr; void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event,LogFormatter::ptr m_temp);private:};//日志输出到文件class FileLogAppender: public LogAppender{public:typedef std::shared_ptr ptr; FileLogAppender(const std::string& filename);void log(Logger::ptr logger, LogLevel::Level level,LogEvent::ptr event,LogFormatter::ptr m_temp);bool reopen();private: //文件路径std::string m_filename; //文件流std::ofstream m_filestream; //上次重新打开的时间 uint64_t m_lastTime = 0; };class LoggerManager{public: LoggerManager(); //获取日志器 Logger::ptr getLogger(const std::string& name); void init(); Logger::ptr getRoot() const {return m_root;}private: //日志器容器 std::map m_loggers; //主日志器 Logger::ptr m_root;};//日志器管理类单例模式typedef angel::Singleton LoggerMgr;}#endif

log.cpp

#include "log.h"#include #include #include #include #include #include #include namespace angel{const char* LogLevel::ToString(LogLevel::Level level){ switch(level) {#define XX(name) case LogLevel::name: return #name; break; XX(DEBUG); XX(INFO); XX(WARN); XX(ERROR); XX(FATAL); #undef XX default: return "UNKNOW"; } return "UNKNOW";}LogLevel::Level LogLevel::FromString(const std::string& str){#define XX(level, v) if(str == #v) { return LogLevel::level; } XX(DEBUG, debug); XX(INFO, info); XX(WARN, warn); XX(ERROR, error); XX(FATAL, fatal); XX(DEBUG, DEBUG); XX(INFO, INFO); XX(WARN, WARN); XX(ERROR, ERROR); XX(FATAL, FATAL); return LogLevel::UNKNOW;#undef XX};class MessageFormatItem : public LogFormatter::FormatItem{public: MessageFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getContent();}};class LevelFormatItem : public LogFormatter::FormatItem{public: LevelFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << LogLevel::ToString(level);}};class ElapseFormatItem : public LogFormatter::FormatItem{public: ElapseFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getElapse();}};class NameFormatItem : public LogFormatter::FormatItem{public: NameFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getLogger()->getName();}};class ThreadIdFormatItem : public LogFormatter::FormatItem{public: ThreadIdFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getThreadId();}};class ThreadNameFormatItem : public LogFormatter::FormatItem {public: ThreadNameFormatItem(const std::string& str = "") {} void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override { os << event->getThreadName(); }};class FiberIdFormatItem : public LogFormatter::FormatItem{public: FiberIdFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getFiberId();}};class DateTimeFormatItem : public LogFormatter::FormatItem{public: DateTimeFormatItem(const std::string& format = "%Y:%m:%d %H:%M:%S"):m_format(format) { if(m_format.empty()){ m_format = "%Y-%m-%d %H-%M-%S"; } }void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ struct tm tm; time_t time = event->getTime(); localtime_r(&time, &tm); char buf[64]; strftime(buf, sizeof(buf), m_format.c_str(), &tm); os << buf;}private: std::string m_format;};class FilenameFormatItem : public LogFormatter::FormatItem{public: FilenameFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getFile();}};class LineFormatItem : public LogFormatter::FormatItem{public: LineFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << event->getLine();}};class newlineFormatItem : public LogFormatter::FormatItem{public: newlineFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << std::endl;}};class StringFormatItem : public LogFormatter::FormatItem{public: StringFormatItem(const std::string& str) : m_string(str){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << m_string;}private: std::string m_string;};class TabFormatItem : public LogFormatter::FormatItem{public: TabFormatItem(const std::string& str = ""){}void format(std::ostream& os,Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override{ os << "t";}private: std::string m_string;};LogEvent::LogEvent(std::shared_ptr logger,LogLevel::Level level ,const char* file, int32_t line, uint32_t elapse ,uint32_t thread_id, uint32_t fiber_id, uint64_t time ,const std::string& thread_name) :m_file(file) ,m_line(line) ,m_elapse(elapse) ,m_threadId(thread_id) ,m_fiberId(fiber_id) ,m_time(time) ,m_threadName(thread_name) ,m_logger(logger) ,m_level(level){}void LogEvent::format(const char* fmt, ...){ va_list al; va_start(al, fmt); format(fmt, al); va_end(al);}void LogEvent::format(const char* fmt, va_list al){ char* buf = nullptr; int len = vasprintf(&buf, fmt, al); if(len != -1) { m_ss << std::string(buf, len); free(buf); }}Logger::Logger(const std::string& name) :m_name(name) ,m_level(LogLevel::DEBUG) { m_formatter.reset(new LogFormatter("%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"));}void Logger::addAppender(LogAppender::ptr appender){m_appenders.push_back(appender);}void Logger::delAppender(LogAppender::ptr appender){for(auto it = m_appenders.begin(); it != m_appenders.end(); ++it){if(*it ==appender){m_appenders.erase(it);break;}}}void Logger::log(LogLevel::Level level,LogEvent::ptr event){ if(level >= m_level) { auto self = shared_from_this(); if(!m_appenders.empty()) { for(auto& i : m_appenders) { i->log(self, level, event,m_formatter); } } else if(m_root) { m_root->log(level, event); } }}void Logger::setFormatter(LogFormatter::ptr val){ }void Logger::setFormatter(const std::string& val){}void Logger::debug(LogEvent::ptr event){log(LogLevel::DEBUG,event);}void Logger::info(LogEvent::ptr event){log(LogLevel::INFO,event);}void Logger::warn(LogEvent::ptr event){log(LogLevel::WARN,event);}void Logger::error(LogEvent::ptr event){log(LogLevel::ERROR,event);}void Logger::fatal(LogEvent::ptr event){log(LogLevel::FATAL,event);}LogFormatter::LogFormatter(const std::string& pattern):m_pattern(pattern){init();}std::string LogFormatter::format(std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event){std::stringstream ss;for(auto& i : m_items){i->format(ss, logger, level, event);}return ss.str();}std::ostream& LogFormatter::format(std::ostream& ofs,std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event){ for(auto& i : m_items) { i->format(ofs, logger, level, event); } return ofs;}//%xxx %xxx{xxx} %%//默认格式 "%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"void LogFormatter::init() { //str, format, type std::vector > vec; std::string nstr; for(size_t i = 0; i < m_pattern.size(); ++i) { if(m_pattern[i] != '%') { nstr.append(1, m_pattern[i]); continue; } if((i + 1) < m_pattern.size()) { if(m_pattern[i + 1] == '%') { nstr.append(1, '%'); continue; } } size_t n = i + 1; int fmt_status = 0; size_t fmt_begin = 0; std::string str; std::string fmt; while(n < m_pattern.size()) { if(!fmt_status && (!isalpha(m_pattern[n]) && m_pattern[n] != '{' && m_pattern[n] != '}')) { str = m_pattern.substr(i + 1, n - i - 1); break; } if(fmt_status == 0) { if(m_pattern[n] == '{') { str = m_pattern.substr(i + 1, n - i - 1); //std::cout << "*" << str << std::endl; fmt_status = 1; //解析格式 fmt_begin = n; ++n; continue; } } else if(fmt_status == 1) { if(m_pattern[n] == '}') { fmt = m_pattern.substr(fmt_begin + 1, n - fmt_begin - 1); //std::cout << "#" << fmt << std::endl; fmt_status = 0; ++n; break; } } ++n; if(n == m_pattern.size()) { if(str.empty()) { str = m_pattern.substr(i + 1); } } } if(fmt_status == 0) { if(!nstr.empty()) { vec.push_back(std::make_tuple(nstr, std::string(), 0)); nstr.clear(); } vec.push_back(std::make_tuple(str, fmt, 1)); i = n - 1; } else if(fmt_status == 1) { std::cout << "pattern parse error: " << m_pattern << " - " << m_pattern.substr(i) << std::endl; m_error = true; vec.push_back(std::make_tuple("<>", fmt, 0)); } } if(!nstr.empty()) { vec.push_back(std::make_tuple(nstr, "", 0)); } static std::map > s_format_items = {#define XX(str, C) {#str, [](const std::string& fmt) { return FormatItem::ptr(new C(fmt));}} XX(m, MessageFormatItem), //m:消息 XX(p, LevelFormatItem), //p:日志级别 XX(r, ElapseFormatItem), //r:累计毫秒数 XX(c, NameFormatItem), //c:日志名称 XX(t, ThreadIdFormatItem), //t:线程id XX(n, newlineFormatItem), //n:换行 XX(d, DateTimeFormatItem), //d:时间 XX(f, FilenameFormatItem), //f:文件名 XX(l, LineFormatItem), //l:行号 XX(T, TabFormatItem), //T:Tab XX(F, FiberIdFormatItem), //F:协程id XX(N, ThreadNameFormatItem), //N:线程名称#undef XX }; for(auto& i : vec) { if(std::get<2>(i) == 0) { m_items.push_back(FormatItem::ptr(new StringFormatItem(std::get<0>(i)))); } else { auto it = s_format_items.find(std::get<0>(i)); if(it == s_format_items.end()) { m_items.push_back(FormatItem::ptr(new StringFormatItem("<(i) + ">>"))); m_error = true; } else { m_items.push_back(it->second(std::get<1>(i))); } } //std::cout << "(" << std::get<0>(i) << ") - (" << std::get<1>(i) << ") - (" << std::get<2>(i) << ")" << std::endl; } //std::cout << m_items.size() << std::endl; }FileLogAppender::FileLogAppender(const std::string& filename) :m_filename(filename){reopen();}bool FileLogAppender::reopen(){if(m_filestream){m_filestream.close();}m_filestream.open(m_filename);return !!m_filestream;}void FileLogAppender::log(std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event,LogFormatter::ptr m_temp){ if(level >= m_level) { uint64_t now = event->getTime(); if(now >= (m_lastTime + 3)) { reopen(); m_lastTime = now; } if(!m_formatter->format(m_filestream, logger, level, event)) { std::cout << "error" << std::endl; } }}void StdoutLogAppender::log(std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event,LogFormatter::ptr m_temp){if(level >= m_level){ m_formatter = m_temp; m_formatter->format(std::cout, logger, level, event); }}LoggerManager::LoggerManager() { m_root.reset(new Logger); m_root->addAppender(LogAppender::ptr(new StdoutLogAppender)); m_loggers[m_root->m_name] = m_root; init();}Logger::ptr LoggerManager::getLogger(const std::string& name) { auto it = m_loggers.find(name); if(it != m_loggers.end()) { return it->second; } Logger::ptr logger(new Logger(name)); logger->m_root = m_root; m_loggers[name] = logger; return logger;}struct LogAppenderDefine { int type = 0; //1 File, 2 Stdout LogLevel::Level level = LogLevel::UNKNOW; std::string formatter; std::string file; bool operator==(const LogAppenderDefine& oth) const { return type == oth.type && level == oth.level && formatter == oth.formatter && file == oth.file; }};void LoggerManager::init() {}}

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。