C++实现日志库

C++实现一个日志库,满足以下要求:
1. 日志信息分级:FATAL(致命错误)、ERROR(一般错误)、WARN(警告)、INFO(一般信息)、DEBUG(调试信息)
2. 记录日志信息支持记录到文件、控制台、数据库(要求能支持多种数据库,比如 MSSQL MySQL SQLite等)
3. 要求能够方便配置该功能:比如 开关日志,仅记录某级别以上的日志,日志记录到哪里的功能。
4. 适当考虑多线程并发,和毫秒级快速日志记录(需要日志记录的时间间隔小于读写文件的时间间隔)

这里,配置文件使用的XML文件,解析XML文件调用的tinyxml2库。
配置文件
这里XML文件中选择显示在Text和控制台,因此最终实现结果为:
控制台

目录
在debug目录下,会有一个Log.txt文件,打开就是我们的日志信息。
日志信息

代码结构如下:
结构

上代码:
日志库头文件

#ifndef LOGOUT_H
#define LOGOUT_H

#include <string>
#include <time.h>
#include <iostream>
#include <windows.h>
#include "logxml.h"

using namespace std;

typedef enum LogLevel{
    DEBUG,              ///<调试信息 级别5
    INFO,               ///<一般信息 级别4
    WARN,               ///<警告信息 级别3
    ERRO,               ///<一般错误 级别2
    FATAL,              ///<致命错误 级别1
}LogLevel;

/*宏定义函数,用于获取日志函数所在行号,也是最终提供的接口*/
#define Log_Out(str,level){\
    char sline[256] = {0};\
    string line;\
    sprintf(sline,"[File:%s Line:%04d]",__FILE__,__LINE__);\
    line = sline;\
    LogOut log;\
    log.logOut(line,str,level);}

class LogOut
{
public:
    LogOut();
    void    logOut(string line,string msg,LogLevel level);      //输出

protected:
    string  getCurrentTime();//获取当前系统时间

    void    printLog(string line,string msg,LogLevel level);    //写日志打印到控制台
    void    writeLog(string line,string msg,LogLevel level);    //写日志到txt文件
    void    saveLog(string line,string msg,LogLevel level);     //写日志到数据库

private:
    string  m_path;                                             //储存文件路径
    LogXml  *m_logXml;
};

#endif // LOGOUT_H

日志库cpp

#include <fstream>
#include "logout.h"

LogOut::LogOut()
{
    m_path.clear();

    m_logXml = new LogXml;
}

void LogOut::logOut(string line, string msg, LogLevel level)
{
    if("true" == m_logXml->getTextSwitch())
    {
        writeLog(line,msg,level);
    }
    if("true" == m_logXml->getConSwitch())
    {
        printLog(line,msg,level);
    }
    if("true" == m_logXml->getDBSwitch())
    {
        saveLog(line,msg,level);
    }
}

string LogOut::getCurrentTime()
{
    struct tm *local; //定义tm结构指针存储时间信息
    time_t now;  //声明time_t类型变量
    timeb tb;
    ftime(&tb); //微秒
    now=time(NULL);//获取当前系统的日历时间
    local=localtime(&now);//localtime()函数是将日历时间转化为本地时间
    char temp[50] = {0};
    sprintf(temp,"[%d-%d-%d %d:%d:%d:%3d]",local->tm_year + 1900,local->tm_mon + 1,local->tm_mday,
            local->tm_hour,local->tm_min,local->tm_sec,tb.millitm);
    string timeNow = temp;
    return timeNow;
}

void LogOut::printLog(string line, string msg, LogLevel level)
{
    switch(level)
    {
    case DEBUG:
        cout<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->DEBUG"<<endl;
        break;
    case INFO:
        cout<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->INFO"<<endl;
        break;
    case WARN:
        cout<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->WARN"<<endl;
        break;
    case ERRO:
        cout<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->ERRO"<<endl;
        break;
    case FATAL:
        cout<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->FATAL"<<endl;
        break;
    default:
        break;
    }
}

void LogOut::writeLog(string line, string msg, LogLevel level)
{
    string fileName = m_logXml->getPath();
    ofstream outfile(fileName.c_str(),ios::app);//将fileName转化为c型字符串作为文件名
    if(!outfile)
    {
        cout<<"Log.txt can't open."<<endl;
        return;
    }
    else
    {
        switch(level)
        {
        case DEBUG:
            if(m_logXml->getLevel()>="5")
            {
                outfile<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->DEBUG"<<endl;
            }
            break;
        case INFO:
            if(m_logXml->getLevel()>="4")
            {
                outfile<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->INFO"<<endl;
            }
            break;
        case WARN:
            if(m_logXml->getLevel()>="3")
            {
                outfile<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->WARN"<<endl;
            }
            break;
        case ERRO:
            if(m_logXml->getLevel()>="2")
            {
                outfile<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->ERRO"<<endl;
            }
            break;
        case FATAL:
            if(m_logXml->getLevel()>="1")
            {
                outfile<<getCurrentTime()<<line<<m_path.c_str()<<": "<<msg.c_str()<<" -->FATAL"<<endl;
            }
            break;
        default:
            break;
        }
        outfile.close();
        cout<<"save to text......"<<endl;
    }
}

void LogOut::saveLog(string line, string msg, LogLevel level)
{
    cout<<"save to db......"<<endl;
}

解析XML头文件:

#ifndef LOGXML_H
#define LOGXML_H

#include <iostream>
#include "tinyxml2.h"

using namespace std;
using namespace tinyxml2;

class LogXml
{
public:
    LogXml();
    string getTextSwitch();     //获取文本文件开关
    string getConSwitch();      //获取控制台开关
    string getDBSwitch();       //获取数据库开关
    string getLevel();          //获取日志等级
    string getPath();           //获取日志输出路径

private:
    string m_textSwitch;        //文本输出开关
    string m_consoleSwitch;     //控制台输出开关
    string m_dbSwitch;          //数据库输出开关
    string m_level;             //日志消息等级
    string m_path;              //日志输出路径

};

#endif // LOGXML_H

解析XML cpp

#include "logxml.h"

LogXml::LogXml()
{
    tinyxml2::XMLDocument docXml;
    docXml.LoadFile("../LogLib/config.xml");
    XMLElement *elmtRoot = docXml.RootElement();
    XMLElement *elmtConfig=elmtRoot->FirstChildElement("config");
    XMLElement *configChild = elmtConfig->FirstChildElement("text");
    m_textSwitch = configChild->GetText();
    configChild = elmtConfig->FirstChildElement("console");
    m_consoleSwitch = configChild->GetText();
    configChild = elmtConfig->FirstChildElement("database");
    m_dbSwitch = configChild->GetText();
    configChild = elmtConfig->FirstChildElement("level");
    m_level = configChild->GetText();
    configChild = elmtConfig->FirstChildElement("path");
    m_path = configChild->GetText();
}

string LogXml::getTextSwitch()
{
    return m_textSwitch;
}

string LogXml::getConSwitch()
{
    return m_consoleSwitch;
}

string LogXml::getDBSwitch()
{
    return m_dbSwitch;
}

string LogXml::getLevel()
{
    return m_level;
}

string LogXml::getPath()
{
    return m_path;
}

最后附上源码传送门:https://download.csdn.net/download/fan_xingwang/10407947

猜你喜欢

转载自blog.csdn.net/fan_xingwang/article/details/80280867
今日推荐