封装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