文件:log.h log.cpp
讲师:sylar;b站视频:https://www.bilibili.com/video/BV184411s7qF?from=search&seid=11872876667245634701&spm_id_from=333.337.0.0
流程:
LogEventWrap可以得到LogEvent的内容流,直接输入内容。LogEventWrap在析构的时候,对日志时间进行了处理。
LogEventWrap内容输入->LogEventWrap::m_event->LogEvent::m_logger->Logger::log()->LogAppender::log()->LogAppender::m_formatter->LogFormatter::m_items->输出
类:
注:只列出其中主要函数
Logger:日志器
class Logger{
public:
Logger(const std::string& name);
//日志事件处理函数
void log(LogLevel::Level level,LogEvent::ptr event);
private:
std::string m_name; //日志名称
LogLevel::Level m_level; //日志级别
std::list<LogAppender::ptr> m_appenders; //日志输出地
};
LogLevel:日志级别
class LogLevel{
public:
enum Level{
UNKNOW=0,
DEBUG,
INFO,
WARN,
ERROR,
FATAL
};
};
LogAppender:日志输出地(基类)
class LogAppender{
public:
//基类
virtual ~LogAppender();
//日志时间处理函数
virtual void log(std::shared_ptr<Logger> logger,
LogLevel::Level level,LogEvent::ptr event);
private:
LogLevel::Level m_level; //日志级别
LogFormatter::ptr m_formatter; //日志格式
};
StdLogAppender:标准输出地(继承m_level,m_formatter)
class StdLogAppender:public LogAppender{
public:
//重载基类虚函数
void log(std::shared_ptr<Logger> logger,
LogLevel::Level level,LogEvent::ptr event)override;
};
FileLogAppender:文件输出地(继承m_level,m_formatter)
class FileLogAppender:public LogAppender{
public:
FileLogAppender(const std::string& filename);
//日志时间处理函数
void log(std::shared_ptr<Logger> logger,
LogLevel::Level level,LogEvent::ptr event)override;
//文件重打开
bool reopen();
private:
std::string m_filename; //文件名
std::ofstream m_filestream; //文件流
uint64_t m_time=0; //重打开时间
};
LogFormatter:日志格式
class LogFormatter{
public:
//默认日志格式 T(Tab键)
//时间-T-线程id-T-线程名-T-协程id-T-日志级别-T-日志名称-T-文件名-:-行号-T-消息内容-换行
LogFormatter(const std::string& pattern=
"%d%T%t%T%N%T%F%T%p%T%c%T%f:%l%T%m%n);
//嵌套类(基类)
class FormatItem{
virtual ~FormatItem();
//对应消息处理(纯虚函数)
virtual void format(std::ostream& os
,std::shared_ptr<Logger> logger
,LogLevel::Level
,LogEvent::ptr event)=0;
};
void format(std::ostream& os
,std::shared_ptr<Logger>
,LogLevel::Level level
,LogEvent::ptr event);
//对格式的初始化
void init();
private:
std::string m_pattern; //格式
std::list<FormatItem::ptr> m_items; //每一个item对应格式中的一项
};
LogEvent:日志事件
class LogEvent{
public:
LogEvent(std::shared_ptr<Logger> logger,LogLevel::Level level,const char* file,
int32_t line,uint32_t elapse,uint32_t threadId,
uint32_t fiberId,uint64_t cur_time,const std::string& threadName);
//多参数输入内容
void format(const char* fmt,...);
void format(const char* fmt,va_list al);
private:
std::shared_ptr<Logger> m_logger; //日志器
LogLevel::Level m_level; //日志级别
const char* m_file=nullptr; //文件路径
int32_t m_line=0; //行数
uint32_t m_elapse=0; //消耗的毫秒数
uint32_t m_threadId=0; //线程id
uint32_t m_fiberId=0; //协程id
uint64_t m_time=0; //时间
std::stringstream m_ss; //流
std::string m_threadName; //线程名
};
LogEventWrap:日志时间包装
class LogEventWrap{
public:
LogEventWrap(LogEvent::ptr event);
//重要:在析构中做了重要的事情
~LogEventWrap();
//返回日志时间的内容
std::stringstream& getSS(){ return m_event->getSS();}
private:
LogEvent::ptr m_event; //日志时间
};
FormatItem子类:(只列出两个)
class LevelFormatItem: public LogFormatter::FormatItem{
public:
//os文件流或标准输出流
void format(std::ostream& os,
std::shared_ptr<Logger> logger,LogLevel::Level level,
LogEvent::ptr event){
os<<LogLevel::ToString(level);
}
};
class MessageFormatItem: public LogFormatter::FormatItem{
public:
void format(std::ostream& os,
std::shared_ptr<Logger> logger,LogLevel::Level level,
LogEvent::ptr event){
os<<event->getContent();
}
};
LogManager:日志管理类
class LogManager{
public:
//自动初始化一个root日志器
LogManager();
void init();
private:
//日志器集合
std::unordered_map<std::string,Logger::ptr> m_loggers;
Logger::ptr m_root;
};
日志系统难点:
1.时间格式:
#include<time.h>
const char* getTimeFormat(){
//时间格式(区分大小写) 年-月-日 时-分-秒
const std::string timeFormat="%Y-%m-%d %H:%M:%s";
time_t cur=time(0); //当前时间
struct tm t; //存储cur分解出的年月日等
localtime_r(&cur,&t); //将cur分解
char buf[64];
//按照格式生成字符串
strftime(buf,sizeof(buf),timeFormat.c_str(),&t);
return buf;
}
2.函数传可变参数(本人不太会,待更新)
va_start获取第一个可变参数的地址
va_arg得到下一个参数
va_end
3.输出地
标准输出:std::cout
文件输出:
//标准输出也属于ostream类
std::ostream& fileStream;
char* fileName="system_log.txt";
fileStream.open(fileName);