[C++]——同步异步日志系统(5)

一、日志消息格式化设计

  1. 日志格式化模块的作用:对日志消息进行格式化,并且组织成指定格式的字符串。

%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. 格式化子项的实现思想:从日志消息中取出指定的元素,追加到一块内存空间中。
    设计思想:
    1.抽象出一个格式化子项的基类
    2.基于基类,派生出不同的格式化子项子类:
    主体消息、日志等级、时间子项、文件名、行号、日志器名称、线程ID、制表符、换行、非格式化的原始字符串。
    这样就可以在父类中定义父类指针的数组,指向不同的格式化子项子类的对象。

FormatItem类主要负责日志消息子项的获取及格式化。其包含以下子类:

  • MsgFormatItem :表示要从LogMsg中取出有效⽇志数据
  • LevelFormatItem:表示要从LogMsg中取出⽇志等级
  • NameFormatItem :表示要从LogMsg中取出⽇志器名称
  • ThreadFormatItem :表示要从LogMsg中取出线程ID
  • TimeFormatItem:表示要从LogMsg中取出时间戳并按照指定格式进行格式化
  • CFileFormatItem :表示要从LogMsg中取出源码所在⽂件名
  • CLineFormatItem :表示要从LogMsg中取出源码所在⾏号
  • TabFormatItem :表示⼀个制表符缩进
  • NLineFormatItem :表示⼀个换行
  • OtherFormatItem :表示⾮格式化的原始字符串
  1. 首先搭架子,定义抽象的格式化子项的基类
  //抽象格式化子类基类
    class FormatItem{
   
        //c++17语法与typedef作用一样
        using ptr=std::shared_ptr<FormatItem>;
        //纯虚函数
        virtual void format(std::ostream &out,const LogMsg &msg)=0;
    }
  1. 在基类的基础上,派生出格式化子项的子类
#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 格式化类的定义和实现

  1. 确定框架,设计格式化类,设计需要的成员,需要完成的功能。
/*
 格式化类的定义和实现
 %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;//格式化字符串解析出的格式化子项
};
  1. 对格式化的功能接口进行设计
#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
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值