一、日志消息格式化设计
- 日志格式化模块的作用:对日志消息进行格式化,并且组织成指定格式的字符串。
%d ⽇期
%T 缩进
%t 线程id
%p ⽇志级别
%c ⽇志器名称
%f ⽂件名
%l ⾏号
%m ⽇志消息
%n 换⾏
如:[2024-07-09 17:04][root][1234567][main.c:99][FATAL]:\t创建套接字失败…\n
格式化字符串控制了日志的输出格式
定义格式化字符,是为了让日志系统进行日志格式化更加的灵活方便。
成员:
1.格式化字符串(用户定义的输出格式格式)
2.格式化子项数组(对格式化字符串进行解析,保存了日志消息要素的排序)
不同的格式化子项,会从日志消息中取出指定的元素,转化为字符串。
[%d{%H:%M:%S}][%f:%l]%m%n
格式化子项:
其他信息(非格式化字符)子项:[
日期子项:%H%M%S
其他信息子项:]
其他信息子项:[
文件名子项:main.c
其他信息子项::
行号信息子项:99
其他信息子项:]
消息主体子项:吃饭睡觉打豆豆
换行子项:\n[12:40;50][main.c:99]吃饭睡觉打豆豆\n
1.1 格式化子项类的定义和实现
- 格式化子项的实现思想:从日志消息中取出指定的元素,追加到一块内存空间中。
设计思想:
1.抽象出一个格式化子项的基类
2.基于基类,派生出不同的格式化子项子类:
主体消息、日志等级、时间子项、文件名、行号、日志器名称、线程ID、制表符、换行、非格式化的原始字符串。
这样就可以在父类中定义父类指针的数组,指向不同的格式化子项子类的对象。
FormatItem类主要负责日志消息子项的获取及格式化。其包含以下子类:
- MsgFormatItem :表示要从LogMsg中取出有效⽇志数据
- LevelFormatItem:表示要从LogMsg中取出⽇志等级
- NameFormatItem :表示要从LogMsg中取出⽇志器名称
- ThreadFormatItem :表示要从LogMsg中取出线程ID
- TimeFormatItem:表示要从LogMsg中取出时间戳并按照指定格式进行格式化
- CFileFormatItem :表示要从LogMsg中取出源码所在⽂件名
- CLineFormatItem :表示要从LogMsg中取出源码所在⾏号
- TabFormatItem :表示⼀个制表符缩进
- NLineFormatItem :表示⼀个换行
- OtherFormatItem :表示⾮格式化的原始字符串
- 首先搭架子,定义抽象的格式化子项的基类
//抽象格式化子类基类
class FormatItem{
//c++17语法与typedef作用一样
using ptr=std::shared_ptr<FormatItem>;
//纯虚函数
virtual void format(std::ostream &out,const LogMsg &msg)=0;
}
- 在基类的基础上,派生出格式化子项的子类
#ifndef __M_FORMAT_H__
#define __M_FORMAT_H__
//日志消息格式化模块
#include <ctime>
#include "level.hpp"
#include "message.hpp"
namespace logslearn{
//抽象格式化子类基类
class FormatItem{
//c++17语法与typedef作用一样
using ptr=std::shared_ptr<FormatItem>;
//纯虚函数
virtual void format(std::ostream &out,const LogMsg &msg)=0;
};
//派生出格式化子项的子类:主体消息、日志等级、时间子项、文件名、行号、日志器名称、线程ID、制表符、换行、非格式化的原始字符串
//主体消息
class MsgFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<msg._payload;
}
};
//日志等级
class LevelFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<loglevel::tostring(msg._level);
}
};
//时间子项
class TimeFormatItem:public FormatItem{
public:
//默认构造函数,设置时间的默认格式
TimeFormatItem(const std::string &fmt="%H:%M:%S"):_time_fmt(fmt){
}
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
struct tm t;
localtime_r(&msg._ctime,&t);
char tmp[32]={
0};
strftime(tmp,31,_time_fmt.c_str(),&t);
out<<tmp;
}
private:
std::string _time_fmt;//默认的时间格式
};
//文件名
class FileFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<msg._file;
}
};
//行号
class LineFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<msg._line;
}
};
//日志器名称
class LoggerFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<msg._logger;
}
};
//线程ID
class ThreadFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<msg._tid;
}
};
//制表符
class TabFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<"\t";
}
};
//换行
class NLineFormatItem:public FormatItem{
public:
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<"\n";
}
};
//非格式化的原始字符串
class OtherFormatItem:public FormatItem{
public:
//设置默认构造函数
OtherFormatItem(std::string &str):_str(str){
}
//虚函数进行重写
void format(std::ostream &out,const LogMsg &msg) override{
out<<_str;
}
private:
std::string _str;
};
}
#endif
1.2 格式化类的定义和实现
- 确定框架,设计格式化类,设计需要的成员,需要完成的功能。
/*
格式化类的定义和实现
%d 表示日期 ,包含子格式{%H%M%S}
%t 表示线程id
%c 表示⽇志器名称
%f 表示源码⽂件名
%l 表示源码⾏号
%p 表示⽇志级别
%T 表示制表符缩进
%m 表示主体消息
%n 表示换⾏
*/
class Formatter{
public:
//构造默认函数
Formatter(const std::string &pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):_pattern(pattern){
}
//对msg进行格式化
void format(std::ostream &out,const LogMsg &msg);
std::string format();
//对格式化规则字符进行解析
bool parsePatern();
private:
//根据不同的格式化字符创建不同的格式化子项对象
FormatItem::ptr createItem(const std::string &key,const std::string &val);
private:
std::string _pattern;//格式化规则字符串
std::vector<logslearn::FormatItem::ptr> _items;//格式化字符串解析出的格式化子项
};
- 对格式化的功能接口进行设计
#ifndef __M_FORMAT_H__
#define __M_FORMAT_H__
// 日志消息格式化模块
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <ctime>
#include <vector>
#include <assert.h>
#include <sstream>
namespace logslearn
{
// 抽象格式化子类基类
class FormatItem
{
public:
// c++17语法与typedef作用一样
using ptr = std::shared_ptr<FormatItem>;
// 纯虚函数
virtual void format(std::ostream &out,cons