C++日志类封装(超级干货)

 写程序通常用要输出日志,以便程序修复BUG和查看程序运行情况。下面是C++语言封装的一个日志类,使用的C语言下的通用文件操作函数,因此可以用于window,linux等平台下开发。C语言下的通用文件操作函数具有线程安全性,因此可以用于多线程程序环境。日志类能在指定文件夹下生成以日期命名的日志文件,并且能根据参数保留最近多少天的日志文件,即之前的文件自动清除掉。
      下面是日志类的头文件:

#ifndef _LOGGER_H_
#define _LOGGER_H_

#include <iostream>
#include <fstream>
#include <time.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
using namespace std;

namespace SgLib
{
    class Logger
    {
    public:
        enum EM_LOG_LEVEL
        {
            TRACE,
            DEBUG,
            INFORMATION,
            WARNING,
            ERROR,
            FATAL
        }; // 日志等级
        enum EM_LOG_TARGET
        {
            TAR_FILE,
            TAR_TERMINAL,
            TAR_FILE_AND_TAR_TERMINAL
        }; // 日志输出目标
    public:
        Logger();
        Logger(EM_LOG_TARGET target, EM_LOG_LEVEL level, const char *pszLogFolder, const char *pszLogFileName, int iKeepLogDays);
        ~Logger();


        void trace(const string &text);
        void debug(const string &text);
        void information(const string &text);
        void warn(const string &text);
        void error(const string &text);
        void fatal(const string &text);

    private:
        int getDiffDays(int iYear1, int iMonth1, int iDay1, int iYear2, int iMonth2, int iDay2);
        void handleOldLogs(tm *);

        FILE *m_pFile;
        ofstream m_outfile;      // 将日志输出到文件的流对象
        EM_LOG_TARGET m_target;  // 日志输出目标
        char m_szLogFolder[256]; // 日志文件路径
        char m_szLogFileName[200];
        EM_LOG_LEVEL m_level;                                    // 日志等级
        void output(const string &text, EM_LOG_LEVEL act_level); // 输出行为
        char m_szOldDay[30];
        int m_iKeepLogDays; // 日志保留天数 -1:无穷天
    };

}

#endif //_LOGGER_H_

       日志进行了分级,具体分为TRACE、DEBUG、INFORMATION、WARNING、ERROR、FATAL六个等级。创建日志对象的时候,level参数指定了日志的最小输出级别,即小于该级别参数的日志信息不会输出。
target参数则指定日志输出到控制台还是文件,还是控制台和日志均同时输出。
       下面是日志实现类的具体实现细节。
       日志类的构造函数如下:

Logger::Logger(EM_LOG_TARGET target, EM_LOG_LEVEL level, const char *pszLogFolder, const char *pszLogFileName, int iKeepLogDays)
{
    m_pFile = NULL;
    m_target = target;
    m_level = level;
    m_iKeepLogDays = iKeepLogDays;
    if (strlen(pszLogFolder) > sizeof(m_szLogFolder) - 1)
    {
        cout << "日志的保存目录过长,程序将不能正确保存日志" << endl;
        return;
    }
    if (strlen(pszLogFileName) > sizeof(m_szLogFileName) - 1)
    {
        cout << "日志的保存文件名过长,程序将不能正确保存日志" << endl;
        return;
    }
    if (access(pszLogFolder, 0) != 0)
    {
        mkdir(pszLogFolder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
    }
    strcpy(m_szLogFolder, pszLogFolder);
    strcpy(m_szLogFileName, pszLogFileName);
}

        具体级别的日志输出以information为例子,其他级别的日志输出函数类似。

void Logger::information(const string &text)
{
    output(text, INFORMATION);
}
void Logger::output(const string &text, EM_LOG_LEVEL act_level)
{
    string prefix;
    if (act_level == TRACE)
        prefix = "[TRA]";
    else if (act_level == DEBUG)
        prefix = "[DEB]";
    else if (act_level == INFORMATION)
        prefix = "[INF]";
    else if (act_level == WARNING)
        prefix = "[WAR]";
    else if (act_level == ERROR)
        prefix = "[ERR]";
    else if (act_level == FATAL)
        prefix = "[FAT]";


    // 如果时间发生变化,需要关闭老文件,创建新文件
    char curDay[64];
    char curTime[64];
    time_t ptime;
    time(&ptime); // time_t time (time_t* timer);
    tm * pTm = localtime(&ptime);
    strftime(curDay, sizeof(curDay), "%Y-%m-%d", pTm);
    strftime(curTime, sizeof(curTime), "%Y-%m-%d %H:%M:%S", pTm);
 
    handleOldLogs(pTm);


    if (strcmp(m_szOldDay, curDay) != 0)
    {
        if (m_pFile != NULL)
        {
            fclose(m_pFile);
        }


        char szLogFile[500] = {0};
        sprintf(szLogFile, "%s/%s_%s.txt", m_szLogFolder, m_szLogFileName, curDay);
        m_pFile = fopen(szLogFile, "w");
        if (m_pFile == NULL)
        {
            cout << "创建文件失败!" << endl;
            return;
        }
    }


    char szCon[8000] = {0};
    sprintf(szCon, "%s[%s]:%s\n", prefix.c_str(), curTime, text.c_str());
    if (m_level <= act_level && m_target != TAR_FILE)
    {
        // 当前等级设定的等级才会显示在终端,且不能是只文件模式
        cout << szCon;
    }
    if (m_target != TAR_TERMINAL)
        fwrite(szCon, strlen(szCon), 1, m_pFile);


    fflush(m_pFile); //刷新缓冲区


    strcpy(m_szOldDay, curDay);
}
       handleOldLogs函数处理了过期的日志文件,即超过保留日志天数的会被程序删除掉。输出日志时候,程序会判断日期是否发生了变化。如果发生变化,将会关闭当天的文件,并创建一个新的日期的日志文件。
      下面是工程在vscode里的快照。 

程序运行后生成日志的快照:

 想要完整源码的朋友,可以去这里下载。

http://www.kbase12.com/linuxcpp/doc/detail?id=4edf01b35f4145c5bcaef0ac94fdb3f2

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: C++中的是面向对象编程的基本单元,其中封装是其最重要的特征之一。封装可确保数据和函数都能被保护起来,不会被外部访问和修改,而只能通过定义的公共接口来操作这些数据。 Dll是动态链接库(Dynamic Link Library)的缩写,它是一种库文件,可以在编译时链接到可执行文件,也可以在运行时加载。封装在动态链接库中使用可以更好地保障其安全性和灵活性。 在C++中,封装可以被编译成动态链接库,也称为库(Class Library)。这种方式可以使开发者将代码分成多个库文件,并且仅将需要的库文件链接到可执行文件中。这种方式可以在多个程序之间共享定义和函数实现,减少代码重复并提高代码的可维护性。 同时,如果只需修改库中的某个的实现,而其他的实现没有改变,那么只需重新编译该库就可以了,而不用重新编译所有代码。 在使用动态链接库时,需要使用C++的导出和导入关键字将和函数导出到DLL中,并在可执行程序中使用它们。这些关键字包括__declspec(dllexport)和__declspec(dllimport)等。 总之,在C++中使用封装和dll可以使代码变得更加安全,可维护性更高,并有效地减少代码重复。 ### 回答2: C语言中,封装需要使用结构体和函数来实现,其中结构体表示对象的属性,而函数则表示对象的方法。为了更好地维护代码,实现代码的复用,我们可以将封装通过dll动态链接库的方式实现。 首先,我们需要定义一个包含结构体和函数声明的header文件,用来描述的结构和功能,然后将这个header文件编译成动态链接库,供其他程序调用。这样做的好处在于,只要我们在其他程序中引用了这个dll,就可以直接使用这个,无需重新编写代码,提高了代码的复用性。 同时,在dll封装中,我们也需要注意一些问题,比如动态链接库的版本问题,如果不同的程序引用了不同版本的dll,可能会出现运行错误,所以需要在编写dll时考虑这些问题。在使用dll时,也需要注意动态链接库的加载和释放问题,防止出现内存泄漏等问题。 总之,通过dll的封装,可以更加方便地实现C语言中的封装,提高代码的复用性和可维护性,但需要在实现过程中注意一些问题,提高代码的质量。 ### 回答3: C++封装 DLL是一种将库打包为可重用代码的方式。DLL全称为Dynamic Link Library,动态链接库。它是一种Windows系统下的动态链接库文件,提供了一种动态加载可以在运行时执行的代码和数据的方式。使用DLL的好处在于,它可以节省资源并提高程序的灵活性。 C++封装 DLL可以将封装为可直接调用的动态链接库。这样,其他程序就可以直接使用这个库,而无需自行编写相应的代码。使用DLL可以使程序员们更加专注于自己的工作而不必担心代码的实现细节。 封装DLL还有另外一些优点,例如:DLL文件可以被多个应用程序所共享,因此可以减少内存的消耗,提高程序的运行效率。同时,库也可以在项目开发过程中进行独立开发和单元测试,这样可以更好地提高程序的质量和可维护性。 总之,C++封装 DLL是一种非常有用的开发技术,它能够有效地提高程序的复用性、可移植性和可维护性。因此,对于需要维护大型项目的开发团队来说,封装DLL是一种非常具有实际意义的开发策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wave12_mp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值