日志系统——日志格式化模块设计

一,模块主要成员

该模块的主要作用是对日志消息进行格式化,将日志消息组织成制定格式的字符串

该模块主要成员有两个:1.格式化字符串。 2.格式化子项数组

1.1 格式化字符串

格式化字符串的主要功能是保存日志输出的格式字符串。其格式化字符主要有下面几种

日志系统——日志格式化模块设计_第1张图片

格式化字符串定义了日志的输出格式,而格式化字符更有助于用户自由的控制日志的输出格式 。这里要注意的是由于我们信息中的日期为时间戳,因此在设置其格式化字符时还应设置对应的子格式化字符如[%d{%H:%M:%S}]指的是按照年月日输出时间

 1.2 格式化子项数组

格式化子项数组:用于按顺序保存格式化字符串对应的子格式化对象(FormatItem类)

那么什么是子格式化类(FormatItem类)?子格式化类主要负责日志消息子项的获取以及格式化,其下包含诸多子类,通过继承关系实现多态,即使是不同的子类也能依靠多态由相同的父类指针指向,从而保存到同一个vector中,Formatltem主要有以下子类:

日志系统——日志格式化模块设计_第2张图片

 格式化字符,以及格式化子项的关系如下,这里我们以日期为例子

 日志系统——日志格式化模块设计_第3张图片

 

1.3 举例说明

例子:"[%d{%H:%M:%S}] %m%n"

pattern = "[%d{%H:%M:%S}] %m%n"
items = {
 {OtherFormatItem(), "["},
 {TimeFormatItem(), "%H:%M:%S"},
 {OtherFormatItem(), "]"},
 {MsgFormatItem (), ""},
 {NLineFormatItem (), ""}
}
message msg = {
 size_t _line = 22;
 size_t _ctime = 12345678;
 std::thread::id _tid = 0x12345678;
 std::string _logger = "logger";
 std::string _file = "main.cpp";
 std::string _payload = "创建套接字失败";
 LogLevel::level _level = ERROR;
};

格式化的过程其实就是按次序从Msg中取出需要的数据进⾏字符串的连接的过程。

最终组织出来的格式化消息: "[22:32:54] 创建套接字失败\n"

 二,代码实现

2.1 代码

核心代码bool AnalyPattern()的分析如下

 日志系统——日志格式化模块设计_第4张图片

 

#ifndef _M_FORMAT_H_
#define _M_FORMAT_H_

#include "level.hpp"
#include "message.hpp"
#include "util.hpp"
#include 
#include 
#include 


namespace mjwlog
{
    // 格式化子项基类
    class Formatlem
    {
    public:
        using ptr=std::shared_ptr;
        virtual void format(std::ostream &os, const message& msg) = 0;
    };
    // 格式化子项子类
    // 日期类子类
    class TimeFormatlem : public Formatlem
    {
    public:
        TimeFormatlem(std::string format="%H:%M:%S")
            :_fromat(format)
        {}

        void format(std::ostream &os, const message& msg) override
        {
            struct tm time;
            localtime_r((time_t*)&msg._time,&time);
            char str[32];
            strftime(str,sizeof(str)-1,_fromat.c_str(),&time);
            
            os<format(os,msg);
                }
            }
        }
        std::string format(const message& msg)//将格式化后的内容以string方式返回
        {
            std::stringstream str;
            if(AnalyPattern())
            {
                for(auto& it:_items)
                {
                    it->format(str,msg);
                }
            }
            return str.str();
        }
        //对格式化字符串进行分析
        bool AnalyPattern()
        {
            //遍历_parttern进行逐一分析
            int cur=0;
            std::string key="",val="";
            //"abc[%%d{%H:%M:%S}]"
            while(cur<_pattern.size())
            {
                
                //先排查非格式化字符,如abc
                if(_pattern[cur]!='%')
                {
                    val+=_pattern[cur++];
                    //特殊情况:"aaaa[%%d{%H:%M:%S}]"
                    if(cur==_pattern.size())
                    {
                        _items.push_back(createItem(key,val));
                    }
                    continue;
                }
                //到这一步,说明碰到%,这是需要排除"%[" "%%"等情况
                //"%["
                //if(_pattern[cur]=='%'&&_pattern[cur+1]=='%')
                if(_pattern[cur]=='%'&&(!isalpha(_pattern[cur+1])))
                {
                    val+=_pattern[cur++];
                    //特殊情况:"aaaa[%%d{%H:%M:%S}%"
                    /* if(cur==_pattern.size())
                    {
                        _items.push_back(createItem(key,val));
                    } */
                    continue;
                }
                //此时,key为空,val中全是非格式化字符字符
                //不过也有可能val中没有任何字符
                if(!val.empty()) _items.push_back(createItem(key,val));
                key.clear();
                val.clear();
                //cur+1==_pattern.size()
                if(cur+1==_pattern.size())
                {
                    std::cout<<"格式化字符关键字%后数据错误"< createItem(const std::string& key,const std::string& val)
        {
            if(key=="d") return Formatlem::ptr(new TimeFormatlem(val));
            if(key=="T") return Formatlem::ptr(new TabFormatlem());
            if(key=="p") return Formatlem::ptr(new LevelFormatlem());
            if(key=="t") return Formatlem::ptr(new ThreadFormatlem());
            if(key=="c") return Formatlem::ptr(new NameFormatlem());
            if(key=="f") return Formatlem::ptr(new CFileFormatlem());
            if(key=="l") return Formatlem::ptr(new CLineFormatlem());
            if(key=="n") return Formatlem::ptr(new NLineFormatlem());
            //当key为空时,则说明val里存储的是非格式化化字符,如abcd
            if(key.empty()) return Formatlem::ptr(new OtherFormatlem(val));
            //还有一种情况,就是key中存储的不是设定的格式字符,如%g
            std::cout<<"没有该格式化字符:%"< _items;
    };
}

#endif

3.1 测试

日志系统——日志格式化模块设计_第5张图片

 日志系统——日志格式化模块设计_第6张图片

 

你可能感兴趣的:(C++/Linux项目,linux,c++)