Skip to content

封装log4cpp

封装要求

用所学过的类和对象的知识,封装log4cpp,实现一个单例的效果。能够输出到终端,还能保存到文件。让其使用起来更方便,要求:可以像printf一样,同时输出的日志信息中最好能有文件的名字,函数的名字及其所在的行号(这个在C/C++里面有对应的宏,可以查一下)

代码模板

cpp
class Mylogger {
public:
    void warn(const char *msg);
    void error(const char *msg);
    void debug(const char *msg);
    void info(const char *msg);

private:
    Mylogger();
    ~Mylogger();

private:
    //...
};

void test0() {
    //第一步,完成单例模式的写法
    Mylogger *log = Mylogger::getInstance();
    
    log->info("The log is info message");
    log->error("The log is error message");
    log->fatal("The log is fatal message");
    log->crit("The log is crit message");
    
    //规范使用单例模式的写法
    Mylogger::getInstance()->info("The log is info message");
}

void test1() {
    printf("hello,world\n");
    // 第二步,像使用printf一样
    // 只要求能输出纯字符串信息即可,不需要做到格式化输出
    LogInfo("The log is info message");
    LogError("The log is error message");
    LogWarn("The log is warn message");
    LogDebug("The log is debug message");
}

最终希望的效果

LogDebug("The log is debug message");

日期 记录器名字 [优先级] 文件名 函数名 行号 日志信息

封装

第一个test函数中的要求比较好满足,但是第二个test中的输出要求要有对应的函数名和行号信息,使用函数或者类对象来做无法达成目标,至少暂时我无法完成,所以考虑使用宏函数来做第二个test的要求。

cpp
#pragma once

#include "log4cpp/PatternLayout.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Category.hh"

class MyLogger
{
public:
    static MyLogger *getInstance();
    void emerg(const char *msg);
    void fatal(const char *msg);
    void alert(const char *msg);
    void crit(const char *msg);
    void error(const char *msg);
    void warn(const char *msg);
    void debug(const char *msg);
    void info(const char *msg);

private:
    MyLogger();
    ~MyLogger();

private:
    log4cpp::PatternLayout *_ptn;
    log4cpp::OstreamAppender *_pos;
    log4cpp::Category &logger;
};

#define LogInfo(msg)                                                             \
    {                                                                            \
        std::string str(__FILE__);                                               \
        str = str + " " + __func__ + " " + std::to_string(__LINE__) + " " + msg; \
        MyLogger::getInstance()->info(str.c_str());                              \
    }

#define LogError(msg)                                                            \
    {                                                                            \
        std::string str(__FILE__);                                               \
        str = str + " " + __func__ + " " + std::to_string(__LINE__) + " " + msg; \
        MyLogger::getInstance()->error(str.c_str());                             \
    }

#define LogWarn(msg)                                                             \
    {                                                                            \
        std::string str(__FILE__);                                               \
        str = str + " " + __func__ + " " + std::to_string(__LINE__) + " " + msg; \
        MyLogger::getInstance()->warn(str.c_str());                              \
    }

#define LogDebug(msg)                                                            \
    {                                                                            \
        std::string str(__FILE__);                                               \
        str = str + " " + __func__ + " " + std::to_string(__LINE__) + " " + msg; \
        MyLogger::getInstance()->debug(str.c_str());                             \
    }
cpp
#include "MyLogger.h"

MyLogger *MyLogger::getInstance()
{
    static MyLogger log;
    return &log;
}

void MyLogger::emerg(const char *msg)
{
    logger.emerg(msg);
}

void MyLogger::fatal(const char *msg)
{
    logger.fatal(msg);
}

void MyLogger::alert(const char *msg)
{
    logger.alert(msg);
}

void MyLogger::crit(const char *msg)
{
    logger.crit(msg);
}

void MyLogger::error(const char *msg)
{
    logger.error(msg);
}

void MyLogger::warn(const char *msg)
{
    logger.warn(msg);
}

void MyLogger::debug(const char *msg)
{
    logger.debug(msg);
}

void MyLogger::info(const char *msg)
{
    logger.info(msg);
}

MyLogger::MyLogger() : logger(log4cpp::Category::getInstance("logger"))
{
    // 1.设置日志布局
    _ptn = new log4cpp::PatternLayout();
    _ptn->setConversionPattern("%d %c [%p] %m%n");

    // 2.创建对象输出器
    _pos = new log4cpp::OstreamAppender("console", &std::cout);
    _pos->setLayout(_ptn);

    // 3.创建日志记录器

    // 4.设置Category优先级
    logger.setPriority(log4cpp::Priority::DEBUG);

    // 5.给Category设置输出器
    logger.setAppender(_pos);

    // 6.记录日志
}

MyLogger::~MyLogger()
{
    // delete _ptn;
    // delete _pos;
    /*
    valgrind --tool=memcheck --leak-check=full ./main
==23714== Memcheck, a memory error detector
==23714== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==23714== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==23714== Command: ./main
==23714==
2025-03-28 11:43:00,872 logger [INFO] The log is info message
2025-03-28 11:43:01,006 logger [ERROR] The log is error message
2025-03-28 11:43:01,014 logger [FATAL] The log is fatal message
2025-03-28 11:43:01,015 logger [CRIT] The log is crit message
2025-03-28 11:43:01,017 logger [INFO] The log is info message
==23714==
==23714== HEAP SUMMARY:
==23714==     in use at exit: 0 bytes in 0 blocks
==23714==   total heap usage: 70 allocs, 70 frees, 91,767 bytes allocated
==23714==
==23714== All heap blocks were freed -- no leaks are possible
==23714==
==23714== For lists of detected and suppressed errors, rerun with: -s
==23714== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
    */
    // 经测试,不释放_ptn和_pos不会造成内存泄漏
}

效果展示

cpp
#include "MyLogger.h"

void test0()
{
    // 第一步,完成单例模式的写法
    MyLogger *log = MyLogger::getInstance();

    log->info("The log is info message");
    log->error("The log is error message");
    log->fatal("The log is fatal message");
    log->crit("The log is crit message");

    // 规范使用单例模式的写法
    MyLogger::getInstance()->info("The log is info message");
}

void test1()
{
    printf("hello,world\n");
    // 第二步,像使用printf一样
    // 只要求能输出纯字符串信息即可,不需要做到格式化输出
    LogInfo("The log is info message");
    LogError("The log is error message");
    LogWarn("The log is warn message");
    LogDebug("The log is debug message");
}

int main()
{
    test0();

    std::cout << "------------" << std::endl;

    test1();

    return 0;
}

运行结果

bash
2025-03-28 12:37:09,495 logger [INFO] The log is info message
2025-03-28 12:37:09,495 logger [ERROR] The log is error message
2025-03-28 12:37:09,495 logger [FATAL] The log is fatal message
2025-03-28 12:37:09,496 logger [CRIT] The log is crit message
2025-03-28 12:37:09,496 logger [INFO] The log is info message
------------
hello,world
2025-03-28 12:37:09,496 logger [INFO] main.cpp test1 22 The log is info message
2025-03-28 12:37:09,496 logger [ERROR] main.cpp test1 23 The log is error message
2025-03-28 12:37:09,496 logger [WARN] main.cpp test1 24 The log is warn message
2025-03-28 12:37:09,496 logger [DEBUG] main.cpp test1 25 The log is debug message