C++ Log4cpp跨平台日志库使用记录(Window与Linux)

【log4】c++日志工具之——log4cpp 1、log4cpp概述 Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试; 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等; 可以动态控制日志记录级别,在效率和功能中进行调整; 所有配置可以通过配置文件进行动态调整; 多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(... 阅读详情
AI摘要

本文详细介绍了C++日志库log4cpp的使用方法,包括在Windows和Linux环境下如何下载、编译、解决编译问题,以及如何设置日志输出格式和优先级。提供了配置文件和纯代码两种方式在项目中使用log4cpp的例子。,

项目中,最重要的模块之一就是日志了,今天这篇博客记录项目中log4cpp的用法!

Log4cpp是c++类库,用于灵活地记录文件、syslog、IDSA和其他目的地。它是在Log4j Java库之后建模的,尽可能地接近它们的API。


目录

一、介绍

1. log4cpp的日志方式

2. 设置日志输出的格式

3. 设置日志的输出优先级

二、Window

1. 下载log4cpp

2. 编译

3. 报错解决1

4. 报错解决2

5. 编译成功

6. 测试

三、Linux

1. 下载Log4cpp

2. 编译安装

3. 测试

 四、log4cpp项目用法

1. 配置文件使用log4cpp

2. 纯代码使用log4cpp

五、总结


一、介绍

1. log4cpp的日志方式

log4cpp::FileAppender                            // 输出到文件(常用)
log4cpp::RollingFileAppender                 // 输出到回卷文件,即当文件到达某个大小后回卷(常用)
log4cpp::OstreamAppender                   // 输出到一个ostream类(常用)
log4cpp::RemoteSyslogAppender          // 输出到远程syslog服务器
log4cpp::StringQueueAppender             // 内存队列
log4cpp::SyslogAppender                      // 本地syslog
log4cpp::Win32DebugAppender            // 发送到缺省系统调试器
log4cpp::NTEventLogAppender             // 发送到win 事件日志

2. 设置日志输出的格式

log4cpp::FileAppender* appender = new log4cpp::FileAppender("appender", "text.log");     

例如:

PatternLayout:自定义日志格式

log4cpp::PatternLayout *patternLayout = new log4cpp::PatternLayout();
patternLayout->setConversionPattern("%d [%p] - %m%n");
appender->setLayout(patternLayout);

PatternLayout支持以下一组格式字符:

  • %% - 一个百分号;
  • %c - the category;
  • %d - date日期格式:日期格式字符后面可以跟着花括号括起来的日期格式说明符。例如,%d              {% H: % M: % S、l %}或% d {% d % M H % Y %: % M: % S、l %}。如果没有给出日期          格式说明符,则使用以下格式:"Wed Jan 02 02:03:55 1980"。日期格式说明符承认与              ANSI C函数strftime相同的语法,只是增加了1个。加号是以毫秒为单位的说明符%l,用          0填充为3位数字;
  • %m - 你要输出的日志信息;
  • %n - 换行符;
  • %p - 优先级;
  • %r - 该布局创建后的毫秒数;
  • %R - 从1970年1月1日0时开始到目前为止的秒数;
  • %u - 进程开始到目前为止的时钟周期数;
  • %x - the NDC;
  • %t - 线程的名字;
  • 默认情况下,PatternLayout的ConversionPattern设置为“%m%n”。

3. 设置日志的输出优先级

log4cpp::Category &root = log4cpp::Category::getRoot();
root.setPriority(log4cpp::Priority::NOTICE);
root.addAppender(appender);

日志的级别总共有:

NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG

日志级别的意思是低于该级别的日志不会被记录。


二、Window

1. 下载log4cpp

log4cpp官网:

下载后解压进入msvc10

 

因为官方提供的是vs2010编译的项目,所以根据自己电脑装的vs去打开即可,例如我这里使用vs2017去打开,打开后会提示升级,升级即可。

2. 编译

  

3. 报错解决1

 不出意外的话,会报错。

解决方法:①在log4cpp项目工程中找到NTEventLogCategories.mc文件,选择该文件上然后右键选择属性,在弹出窗口中找到“配置属性 - 自定义生成工具 - 常规 - 命令行”中修改编译命令,设置为如下命令:

if not exist $(OutDir) md $(OutDir)
mc.exe -h $(OutDir) -r $(OutDir) $(ProjectDir)..\%(Filename).mc
RC.exe -r -fo $(OutDir)%(Filename).res $(OutDir)%(Filename).rc
link.exe /MACHINE:IX86 -dll -noentry -out:$(OutDir)NTEventLogAppender.dll $(OutDir)%(Filename).res

然后再次右键log4cpp,选择重新编译!

 不出意外的话,再次报错。

4. 报错解决2

解决方法:由于log4cpp中对snprintf进行了重新实现,visual studio的c库对snprintf也有实现,windows中在链接时会报snprintf函数冲突,所以需要设置log4cpp的预编译项,选择使用visual stuido中c库的实现,在log4cpp工程上点右键选属性,在”配置属性 - C/C++ - 预处理器 - 预处理器定义"中增加一条预处理定义 。

HAVE_SNPRINTF

再次编译!

5. 编译成功

不出意外的话,编译通过!

 进入路径log4cpp-1.1.3\log4cpp\msvc10\log4cpp\Debug,编译好的库就在这里。

头文件路径:log4cpp-1.1.3\log4cpp 

 注意,这是编译x86(Win32)的库,如果需要编译x64的库,在项目中添加x64的库后进行编译即可;编译好的库路径:log4cpp-1.1.3\log4cpp\msvc10\x64\Debug

 Release库编译方式与上面方式一样!

6. 测试

官方例子,稍作修改

新建项目,将上面编译好的 log4cpp.dll 和 log4cpp.lib 和 /include 文件夹拷贝到项目路径中去

#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/PatternLayout.hh"


int main(void) {

	/* 1.日志输出到控制台 */
	{
		log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
		appender1->setLayout(new log4cpp::BasicLayout());	// 默认配置

		log4cpp::Category& root = log4cpp::Category::getRoot();
		root.setPriority(log4cpp::Priority::WARN);
		root.addAppender(appender1);

		// 1.use of functions for logging messages	
		root.debug("root debug");
		root.warn("root warn");
		root.error("root error");
		root.info("root info");

		// 2.printf-style for logging variables
		root.warn("%d + %d == %s ?", 1, 1, "two");

		// 3.use of streams for logging messages
		root << log4cpp::Priority::ERROR << "Streamed root error";
		root << log4cpp::Priority::INFO << "Streamed root info";

		// 4.or this way:
		root.errorStream() << "Another streamed error";
		root.debugStream() << "Another streamed debug";
	}
	
	/* 2.日志输出到控制台和本地文件 */
	{
		log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");
		appender2->setLayout(new log4cpp::BasicLayout());

		log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
		sub1.addAppender(appender2);

		sub1.error("sub1 error");
		sub1.warn("sub1 warn");

		sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error";
		sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";
	}

	/* 3.日志输出到本地文件 */
	{
		std::string logFileName = "test.log";

		// 优先级
		log4cpp::Priority::PriorityLevel logPri = log4cpp::Priority::DEBUG;		
		
		// 自定义布局
		log4cpp::PatternLayout* logLayout = new log4cpp::PatternLayout();
		logLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] : %m%n");

		// 日志输出到本地文件
		log4cpp::FileAppender* logFile = new log4cpp::FileAppender("default", logFileName);
		logFile->setLayout(logLayout);	// 设置自定义布局

		// 输出日志的操作类
		log4cpp::Category& logCat = log4cpp::Category::getInstance("logCat");
		logCat.addAppender(logFile);
		
		//设置优先级
		logCat.setPriority(logPri);

		logCat.error("测试 error");	
		logCat.debug("测试 debug");

		logCat.warn("%d + %d == %s ?", 1, 1, "two");

		logCat << log4cpp::Priority::ERROR << "Streamed root error";
		logCat << log4cpp::Priority::INFO << "Streamed root info";

		logCat.errorStream() << "Another streamed error";
		logCat.debugStream() << "Another streamed debug";
	}

	// 关闭日志
	log4cpp::Category::shutdown();

	return 0;
}

三、Linux

1. 下载Log4cpp

可以通过上面的官网去下载,然后再拷入Linux系统中!

或者根据自己系统的特性,使用下面链接去下载,

https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz

例如Ubuntu:wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz

下载后,使用命令 tar -zxvf log4cpp*.tar.gz 去解压。

2. 编译安装

然后 cd log4cpp* 进入文件夹

然后执行 ./configure

然后执行 make

然后执行 make install 

即可安装成功!

命令汇总:

wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz

tar xzvf log4cpp-1.1.3.tar.gz

cd log4cpp-1.1.3

./configure 

make

make install

安装完毕后,log4cpp库路径在 /usr/local/lib

可以使用命令 mv -if /usr/local/lib/liblog4cpp.* 自己的项目路径 拷贝到自己的项目路径中去;例如,我会在项目路径中创建一个lib文件夹,将刚刚安装的log4cpp库拷贝到此文件夹中

log4cpp头文件路径在 /usr/local/include/log4cpp

可以使用命令 mv -if /usr/local/include/log4cpp 自己的项目路径 拷贝到自己的项目路径中去;例如,我会在项目路径中创建一个include文件夹,将刚刚安装的log4cpp头文件拷贝到此文件夹中

3. 测试

#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
#include "log4cpp/PatternLayout.hh"


int main(int argc, char **argv) {

	/* 1.日志输出到控制台 */
	{
		log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
		appender1->setLayout(new log4cpp::BasicLayout());	// 默认配置

		log4cpp::Category& root = log4cpp::Category::getRoot();
		root.setPriority(log4cpp::Priority::WARN);
		root.addAppender(appender1);

		// 1.use of functions for logging messages	
		root.debug("root debug");
		root.warn("root warn");
		root.error("root error");
		root.info("root info");

		// 2.printf-style for logging variables
		root.warn("%d + %d == %s ?", 1, 1, "two");

		// 3.use of streams for logging messages
		root << log4cpp::Priority::ERROR << "Streamed root error";
		root << log4cpp::Priority::INFO << "Streamed root info";

		// 4.or this way:
		root.errorStream() << "Another streamed error";
		root.debugStream() << "Another streamed debug";
	}
	
	/* 2.日志输出到控制台和本地文件 */
	{
		log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");
		appender2->setLayout(new log4cpp::BasicLayout());

		log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
		sub1.addAppender(appender2);

		sub1.error("sub1 error");
		sub1.warn("sub1 warn");

		sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error";
		sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";
	}

	/* 3.日志输出到本地文件 */
	{
		std::string logFileName = "test.log";

		// 优先级
		log4cpp::Priority::PriorityLevel logPri = log4cpp::Priority::DEBUG;		
		
		// 自定义布局
		log4cpp::PatternLayout* logLayout = new log4cpp::PatternLayout();
		logLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] : %m%n");

		// 日志输出到本地文件
		log4cpp::FileAppender* logFile = new log4cpp::FileAppender("default", logFileName);
		logFile->setLayout(logLayout);	// 设置自定义布局

		// 输出日志的操作类
		log4cpp::Category& logCat = log4cpp::Category::getInstance("logCat");
		logCat.addAppender(logFile);
		
		//设置优先级
		logCat.setPriority(logPri);

		logCat.error("测试 error");	
		logCat.debug("测试 debug");

		logCat.warn("%d + %d == %s ?", 1, 1, "two");

		logCat << log4cpp::Priority::ERROR << "Streamed root error";
		logCat << log4cpp::Priority::INFO << "Streamed root info";

		logCat.errorStream() << "Another streamed error";
		logCat.debugStream() << "Another streamed debug";
	}

	// 关闭日志
	log4cpp::Category::shutdown();

	return 0;
}

编译:

g++ test_log4cpp.cpp -I ./inlcude/ -L ./lib/  -llog4cpp1 -lpthread -o test_log4cpp

log4cpp1:是log4cpp.a静态库,我将名字改成这样(在上图中可以看到),才可以正常链接到静态库;不知道为什么,链接动态库.so,编译会报错,所以只能链接静态库去完成编译运行。

-I:指定头文件路径,可以使用相对路径
-L:指定库的路径,可以使用相对路径

 四、log4cpp项目用法

以下介绍的项目用法,Linux和Window环境均可使用! 

一般来说,日志都是由独立的文件夹去保存的,下面为了方便就直接将日志保存在main函数同级目录了。 

1. 配置文件使用log4cpp

新建项目,在项目路径下新建文件名为:log.conf

粘贴以下配置到log.conf文件中

#定义Root category的属性
log4cpp.rootCategory=DEBUG, RootLog     # 优先级, 当前日志代表变量名

#定义RootLog属性
#log4cpp.appender.RootLog = FileAppender           # 输出到文件
log4cpp.appender.RootLog = RollingFileAppender    # 回卷
log4cpp.appender.RootLog.layout = PatternLayout   # 自定义输出日志格式

# 日志输出格式
log4cpp.appender.RootLog.layout.ConversionPattern = %d{%Y-%m-%d %H:%M:%S.%l} [%t][%p] %m%n 

# 日志名
log4cpp.appender.RootLog.fileName = ./test.log

# 单个日志文件大小
log4cpp.appender.RootLog.maxFileSize = 268435456 #256MB

# 回卷日志个数名
log4cpp.appender.RootLog.fileNamePattern = test_%i.log

# 日志个数
log4cpp.appender.RootLog.maxBackupIndex = 256

# append=true 信息追加到上面指定的日志文件中,false表示将信息覆盖指定文件内容
log4cpp.appender.RootLog.append = true

在项目中新建文件MyLogger.h

#ifndef _MY_LOGGER_H_
#define _MY_LOGGER_H_

#include <string>
#include <log4cpp/Category.hh>

class MyLogger {
public:
	bool init(const std::string &log_conf_file);			// 指定加载log配置文件
	static MyLogger *instance() { return &_instance; };		// 单例模式,返回自己

	log4cpp::Category *GetHandle() { return _category; };	

private:
	static MyLogger _instance;
	log4cpp::Category *_category;	// 通过此对象可以实现日志写入
};

/* 宏定义,方便调用 */
#define LOG_DEBUG MyLogger::instance()->GetHandle()->debug		// 调试
#define LOG_INFO MyLogger::instance()->GetHandle()->info		// 信息,消息
#define Log_NOTICE MyLogger::instance()->GetHandle()->notice	// 通知
#define LOG_WARN MyLogger::instance()->GetHandle()->warn		// 警告
#define LOG_ERROR MyLogger::instance()->GetHandle()->error		// 错误
#define LOG_FATAL MyLogger::instance()->GetHandle()->fatal		// 致命错误

/*
 * __LINE__ : 文件中的当前行号;
 * __FILE__ : 文件的完整路径和文件名;如果用在包含文件中,则返回包含文件名;
 * __FUNCTION__ : 函数名字。
 */
#define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << "[" << __FUNCTION__ << "][" << __LINE__ << "]: "
//#define LOG(__level) log4cpp::Category::getRoot() << log4cpp::Priority::__level << "[" << __FILE__ << "][" << __FUNCTION__ << "][" << __LINE__ << "]: "

#endif

在项目中新建文件MyLogger.cpp

#include "MyLogger.h"

#include <iostream>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/PropertyConfigurator.hh>


// 静态变量,需要在类外部初始化一下
MyLogger MyLogger::_instance;

bool MyLogger::init(const std::string &log_conf_file) {
	try {
		log4cpp::PropertyConfigurator::configure(log_conf_file);	// 初始化log配置文件
	} catch (log4cpp::ConfigureFailure &f) {
		std::cerr << "load log config file " << log_conf_file.c_str() << " failed with result: " << f.what() << std::endl;
		return false;
	}

	// 初始化成功后,使用getRoot()获取操作日志的对象
	_category = &log4cpp::Category::getRoot();
	
	return true;
}

main函数测试

#include "MyLogger.h"

int main(void) {
	if (!MyLogger::instance()->init("log.conf")) {
		fprintf(stderr, "init log module failed.\n");
		return -1;
	}

	LOG_DEBUG("测试 debug.");
	LOG_INFO("测试 inof.");
	Log_NOTICE("测试 notice.");
	LOG_WARN("测试 warn.");
	LOG_ERROR("测试 error.");
	LOG_FATAL("测试 fatal.");

	LOG_DEBUG("%d + %c == %s", 1, 'a', "1a");

	LOG(DEBUG) << "123";
	LOG(ERROR) << "ERROR";

    // 关闭日志
	log4cpp::Category::shutdown();

	return 0;
}

运行结果:

 在运行一次项目:

Linux编译命令:(链接的是静态库)

g++ main.cpp MyLogger.h MyLogger.cpp -std=c++11 -I ./inlcude/ -L ./lib/  -llog4cpp1 -lpthread -o test_log4cpp

2. 纯代码使用log4cpp

网上找的代码,感觉挺不错的,拷贝过来做了修改,改成自己以后做项目可能会这样使用! 

MyLog.h

#ifndef _MY_LOG_H_
#define _MY_LOG_H_

#include <log4cpp/Category.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/PropertyConfigurator.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/RollingFileAppender.hh>

#include <string>


// 优先级
#define COUNT_PRITY			log4cpp::Priority::INFO;		// 控制台
#define LOG_PRITY			log4cpp::Priority::DEBUG;		// 本地文件


/*采用单例模式设计,包含两个category对象,一个负责输出到屏幕的信息,一个负责记录到日志的信息,
通过设置优先级差别,可以实现所有信息都记录在日志中,遇到error及以上的信息时打印到屏幕上*/
class MyLog {
private:
	MyLog(bool b) {
		outToScreen = b;
	}
	~MyLog() {}
	static MyLog * log;
	bool outToScreen;//是否输出日志信息到屏幕
	static std::string _screenInfo;//屏幕日志信息
	static std::string _logName;//文件日志名称

	static log4cpp::Category& logCat;
	static log4cpp::Category& coutCat;

	static log4cpp::FileAppender* logFile;//文件日志输入
	static log4cpp::OstreamAppender* logScreen;//屏幕日志输入
	static log4cpp::RollingFileAppender *rollLogFile;	/* 回卷用这个 */

	static log4cpp::Priority::PriorityLevel logPri;//文件日志优先级
	static log4cpp::Priority::PriorityLevel coutPri;//屏幕日志优先级

	static log4cpp::PatternLayout* logLayout;//日志布局 
	static log4cpp::PatternLayout* screenLayout;//屏幕布局 
	static log4cpp::PatternLayout* logLayout2;	/* 回卷用这个 */

private:
	// 返回当前年月日时分秒
	static std::string getCurrentTime(std::string& year, std::string& month, std::string& day, std::string& hour, std::string& min, std::string& sec);

public:
	// 初始化日志配置信息
	static bool init(std::string logName = "time", bool toScreen = false);
	//获取日志函数,默认参数选择是否输出到屏幕
	static MyLog* getLog(bool toScreen = false);
	//销毁日志对象
	static void destoryLog();
	//设置日志记录优先级
	static void setPri(log4cpp::Priority::PriorityLevel coutLevel, log4cpp::Priority::PriorityLevel logLevel);
	//记录日志,调用参数 __LINE__ ,__FUNCTION__
	void warn(const char * msg, int line = __LINE__, const char *function = "warn");
	void error(const char * msg, int line = __LINE__, const char *function = "error");
	void debug(const char * msg, int line = __LINE__, const char *function = "debug");
	void info(const char * msg, int line = __LINE__, const char *function = "info");
};

//为避免每次调用都要填写参数__LINE__和__FUNCTION__,可以使用带参数的宏定义
#define  MyLogWARN(msg) MyLog::getLog()->warn(msg,__LINE__,__FUNCTION__);
#define  MyLogINFO(msg) MyLog::getLog()->info(msg,__LINE__,__FUNCTION__);
#define  MyLogERROR(msg) MyLog::getLog()->error(msg,__LINE__,__FUNCTION__);
#define  MyLogDEBUG(msg) MyLog::getLog()->debug(msg,__LINE__,__FUNCTION__);

#endif

MyLog.cpp

#include "MyLog.h"

#include <time.h>

MyLog* MyLog::log = NULL;
std::string MyLog::_screenInfo = "screenInfo";
std::string MyLog::_logName = "log";

log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& MyLog::logCat = root.getInstance(MyLog::_logName);
log4cpp::Category& MyLog::coutCat = root.getInstance(MyLog::_screenInfo);

// 优先级
log4cpp::Priority::PriorityLevel MyLog::coutPri = COUNT_PRITY;		// 控制台
log4cpp::Priority::PriorityLevel MyLog::logPri = LOG_PRITY;		// 本地文件

log4cpp::PatternLayout* MyLog::logLayout = NULL;
log4cpp::PatternLayout* MyLog::screenLayout = NULL;
log4cpp::PatternLayout* MyLog::logLayout2 = NULL;	/* 回卷用这个 */

log4cpp::FileAppender* MyLog::logFile = NULL;//文件日志输入
log4cpp::OstreamAppender* MyLog::logScreen = NULL;//屏幕日志输入
log4cpp::RollingFileAppender *MyLog::rollLogFile;	/* 回卷用这个 */

bool MyLog::init(std::string logName, bool toScreen) {

	// 判断如果传入文件名参数为空,或为默认参数,则使用当前年月日.log作为日志文件名
	if (logName.empty() || logName == "time") {
		std::string year, month, day, hour, min, sec;
		getCurrentTime(year, month, day, hour, min, sec);
		logName = year + month + day + ".log";
	}

	if (MyLog::log == NULL) {
		MyLog::log = new MyLog(toScreen);

		MyLog::_logName = logName;

		log4cpp::Category& logCat = root.getInstance(MyLog::_logName);
		log4cpp::Category& coutCat = root.getInstance(MyLog::_screenInfo);

		logScreen = new log4cpp::OstreamAppender("logScreen", &std::cout);
		logFile = new log4cpp::FileAppender("logFile", MyLog::_logName);								/* 然后注释这个 */
		//rollLogFile = new log4cpp::RollingFileAppender("rollLogFile", MyLog::_logName, 1024*1024, 5);	/* 回卷用这个 */	// 单个日志文件大小1M,5个回卷


		//设置布局
		MyLog::logLayout = new log4cpp::PatternLayout();	/* 然后注释这个 */
		MyLog::screenLayout = new log4cpp::PatternLayout();
		MyLog::logLayout2 = new log4cpp::PatternLayout();	/* 回卷用这个 */
		logLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] %m%n");
		screenLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] %m%n");
		logLayout2->setConversionPattern("%d{%Y-%m-%d %H:%M:%S} [%p] %m%n");
		MyLog::logScreen->setLayout(screenLayout);
		MyLog::logFile->setLayout(logLayout);			/* 然后注释这个 */
		//MyLog::rollLogFile->setLayout(logLayout2);	/* 回卷用这个 */


		//追加到目录	
		MyLog::logCat.addAppender(MyLog::logFile);			/* 然后注释这个 */
		//MyLog::logCat.addAppender(MyLog::rollLogFile);	/* 回卷用这个 */
		MyLog::coutCat.addAppender(MyLog::logScreen);
		
		//设置优先级
		MyLog::logCat.setPriority(MyLog::logPri);
		MyLog::coutCat.setPriority(MyLog::coutPri);
	}
	MyLog::log->outToScreen = toScreen;


	return true;
}

//获取日志函数,默认参数选择是否输出到屏幕
MyLog* MyLog::getLog(bool toScreen) {
	MyLog::log->outToScreen = toScreen;

	if (NULL == MyLog::log) {
		printf("MyLog::log is NULL, please use MyLog::init!\n");
		return NULL;
	}

	return MyLog::log;
}
//销毁日志对象
void MyLog::destoryLog() {
	log4cpp::Category::shutdown();
	delete MyLog::log;
}
//设置日志记录优先级
void MyLog::setPri(log4cpp::Priority::PriorityLevel coutLevel, log4cpp::Priority::PriorityLevel logLevel) {
	MyLog::logPri = logLevel;
	MyLog::coutPri = coutLevel;
	MyLog::logCat.setPriority(MyLog::logPri);
	MyLog::coutCat.setPriority(MyLog::coutPri);
}
//记录日志,调用参数__FILE__, __LINE__ ,__FUNCTION__
void MyLog::warn(const char * msg, int line, const char *function) {
	char info[4096] = { 0 };
	sprintf(info, "[%s][%d]: %s", function, line, msg);
	if (this->outToScreen) {
		logCat.warn(info);
		coutCat.warn(info);
	} else {
		logCat.warn(info);
	}
}
void MyLog::error(const char * msg, int line, const char *function) {
	char info[4096] = { 0 };
	sprintf(info, "[%s][%d]: %s", function, line, msg);
	if (this->outToScreen) {
		logCat.error(info);
		coutCat.error(info);
	} else {
		logCat.error(info);
	}
}
void MyLog::debug(const char * msg, int line, const char *function) {
	char info[4096] = { 0 };
	sprintf(info, "[%s][%d]: %s", function, line, msg);
	if (this->outToScreen) {
		logCat.debug(info);
		coutCat.debug(info);
	} else {
		logCat.debug(info);
	}
}
void MyLog::info(const char * msg, int line, const char *function) {
	char info[4096] = { 0 };
	sprintf(info, "[%s][%d]: %s", function, line, msg);

	if (this->outToScreen) {
		logCat.info(info);
		coutCat.info(info);
	} else {
		logCat.info(info);
	}
}

std::string MyLog::getCurrentTime(std::string& year, std::string& month, std::string& day, std::string& hour, std::string& min, std::string& sec) {
	// 获取系统时间 - 年月日时分秒
	time_t _time;
	struct tm* target_time;
	time(&_time);
	target_time = localtime(&_time);


	year = std::to_string(target_time->tm_year + 1900);
	month = target_time->tm_mon + 1 > 9 ? std::to_string(target_time->tm_mon + 1) : "0" + std::to_string(target_time->tm_mon + 1);
	day = target_time->tm_mday > 9 ? std::to_string(target_time->tm_mday) : "0" + std::to_string(target_time->tm_mday);
	hour = target_time->tm_hour > 9 ? std::to_string(target_time->tm_hour) : "0" + std::to_string(target_time->tm_hour);
	min = target_time->tm_min > 9 ? std::to_string(target_time->tm_min) : "0" + std::to_string(target_time->tm_min);
	sec = target_time->tm_sec > 9 ? std::to_string(target_time->tm_sec) : "0" + std::to_string(target_time->tm_sec);

	return year + month + day + hour + min + sec;
}

main函数测试

#include "MyLog.h"


int main(void) {

	if (!MyLog::init("")) {
		fprintf(stderr, "init log module failed.\n");
		return -1;
	}

	MyLogWARN("警告");
	MyLogINFO("信息");
	MyLogERROR("错误");
	MyLogDEBUG("调试");
	
    // 关闭日志
	log4cpp::Category::shutdown();

	return 0;
}

运行结果:

Linux编译命令:(链接的是静态库)

g++ main.cpp MyLog.h MyLog.cpp -std=c++11 -I ./inlcude/ -L ./lib/  -llog4cpp1 -lpthread -o test_log4cpp


五、总结

日志在项目中是必须使用的,如果看完此篇博客还是不太懂log4cpp日志如何使用,直接拷贝上面项目代码去到自己的项目中就可以直接使用了!

C++项目实战:Log4cpp日志库在Windows和Linux下的编译踩坑全记录(附解决方案) 本文详细记录了Log4cpp日志库在Windows和Linux下的编译过程及常见问题解决方案,特别针对VS2019和Linux环境中的典型错误提供了实用修复方法。作为C++跨平台开发的日志标杆工具,Log4cpp支持多级日志控制、线程安全和动态配置,是提升项目可维护性的关键组件。 阅读详情

相关推荐

Log4cpp详解:C++中的强大日志记录库

log4cpp是一个功能强大的C++日志记录库,它提供了丰富的功能和灵活的配置选项。本文介绍了log4cpp的基本概念和示例代码,希望能帮助读者理解和使用log4cpp进行日志记录。在C++开发中,log4cpp是一款非常流行和强大的日志记录库。log4cpp是一个用于C++的开源日志记录库,它提供了丰富的功能和灵活的配置选项。它采用了面向对象的设计模式,具有模块化的架构,可以轻松地与现有的C++应用程序集成。Logger(日志记录器):Logger是log4cpp中的核心概念,用于记录日志消息。

CyberWarpX的博客 592

log4cpp浅析

log4cpp是个基于LGPL的开源项目,移植自Java的日志处理跟踪项目log4j,并保持了API上的一致。其类似的支持库还包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等。 Log4cpp中最重要概念有Category(种类)、Appender(附加器)、Layout(布局)、Priorty(优先级)、NDC(嵌套的诊断上下文)。 Category、Appender与Layout三者的关系如下图所示: ...

lyt_dawang的博客 5113

log4cpp、log4cplus 与 log4cxx 三大 C++ 日志框架

受 Java 领域著名日志框架的启发,社区衍生出了多个 C++ 版本的日志库。其中,和是最广为人知的三大实现。

h a 6 6 6 c k 为 你解决复杂难题! 467

Log4cpp

Log4cpp

敖丙007的博客 2065

【神经网络与深度学习】【C/C++】C++日志操作开源函数库之Google-glog

今天想给我的C++项目找一个开源的日志类,用于记录系统日志,结果浪费了半个下午的时间。从网上搜索相关资料,找到以下几个备选方案: 1、log4cplus  下载地址:http://sourceforge.net/projects/log4cplus/files/log4cplus-stable/1.1.0 2、log4cxx  下载地址:http://logging.apache.or

ZhangPY的专栏 2737

log4cpp源码完整解析

完整分析了log4cpp的整体架构,详细介绍了log4cpp的这个重要组件的实现分析了log4cpp内部所使用的设计模式。介绍了log4cpp中的Category的完整实现细节,介绍了所有的Layout及其子类的具体实现。也详细介绍了比较常用的Appender的具体实现,比如RollingFileAppender,DailyRollingFileAppender...,有兴趣的朋友可以下载看一下。 此资源完全属于原创,转发请转明出处。

Linux和Windows(VS 2019)下安装使用Log4cpp日志库

Log4cpp是个基于LGPL的开源项目,移植自Java的日志处理跟踪项目log4j,并保持了API上的一致。其类似的支持库还包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等。•提供了可扩展的多种日志记录方式;•提供了NDC(嵌套诊断上下文),可用于多线程、多场景的跟踪调试;•提供了完整的日志动态优先级控制,可随时调整需要记录的日志优先级;•可通过配置文件完成所有配置并动态加载;

m0_65635427的博客 2332

STM32掉电保存配置参数技巧

本文介绍了使用STM32内置备份寄存器(BKP)实现掉电保存配置参数的方法。相比外接EEPROM或Flash,备份寄存器无需外设但存储容量有限,需通过VBAT引脚连接纽扣电池供电。文章详细说明了初始化步骤,包括使能PWR时钟、允许访问备份寄存器等操作,并提供了RTC初始化的代码示例。同时介绍了HAL库中读写备份寄存器的函数使用方法,包括HAL_RTCEx_BKUPWrite和HAL_RTCEx_BKUPRead函数的具体参数和调用示例。该方法适用于需要小容量数据掉电保存的应用场景。

hanhanhan233的博客 946

C/C++日志库-log4cplus(log4j的C++版本)

  Log4j以其简单的使用方式(引入一个jar包,一行代码即可调用),灵活(可通过配置文件随意配置),功能强大(多个级别,可配置多个输出目的地,Console,File,系统日志,远端的LogServer等等,可订制日志格式,自动产生,删除日志文件)等特性,是Java日志系统的首选。 1.C++版本Log4j - Log4cplus   Log4cplus日志系统是仿照Log4J,使用C++...

Dreamhigh_M的博客 4072

新买的USB无线网卡插上没反应?保姆级排查指南:从设备管理器到网络列表

本文提供USB无线网卡无法识别的全流程排查手册,涵盖硬件检测、驱动管理和网络配置三大维度。重点解析设备管理器中的设备状态诊断和驱动解决方案,特别适用于Realtek芯片的无线网卡(如RTL8188GU、RTL8812BU等),帮助用户快速解决网卡插上无反应的问题。

weixin_29876033的博客 497

WhatsApp注册流程逆向分析:从协议解析到风控对抗实战

移动应用安全分析的核心在于理解客户端与服务端的交互协议与验证机制。通过逆向工程,可以深入剖析应用的数据加密、传输与身份验证原理,这对于构建安全模型、进行自动化测试和风控策略研究具有重要技术价值。在即时通讯、金融支付等高安全要求场景中,掌握应用注册流程的底层实现是评估其安全性的关键。本文聚焦于使用动态分析工具如Frida进行Hook和流量抓包,结合设备指纹识别与模拟器检测技术,详细解析了大型应用的注册风控体系,为安全研究人员和开发者提供了从环境搭建到实战对抗的完整方法。

weixin_33935636的博客 315

探秘:Spdlog - 高速、灵活的 C++日志库

Spdlog是一个开源的、快速的、仅有头文件的C++11日志库。它提供了向流、标准输出、文件、系统日志、调试器等目标输出日志的能力,支持的平台包括Windows、Linux、Mac、Android。

新法的博客 3457

RK3588 C-PHY摄像头驱动升级踩坑记:从‘Only CSI2 supported’报错到成功取流

本文详细记录了在RK3588平台上调试C-PHY摄像头驱动的全过程,从‘Only CSI2 supported’报错分析到成功取流。内容涵盖C-PHY与CSI-2协议差异、SDK版本对比、V4L2框架下的bus-type解析机制,以及硬件排查与寄存器调优实战经验,为嵌入式Camera驱动工程师提供宝贵参考。

weixin_42522374的博客 122

Qt C++项目main.cpp深度解析:从基础骨架到工业级实践

在C++应用程序开发中,main函数作为程序的唯一入口点,承担着初始化全局资源、解析命令行参数、设置运行环境等核心职责,是应用程序生命周期的起点。其设计质量直接影响程序的健壮性、可维护性与跨平台兼容性。在Qt框架下,main.cpp的编写尤为关键,它需要集成Qt特有的应用程序对象管理、事件循环机制、高DPI适配、国际化支持等核心技术。通过合理的架构设计,开发者可以构建出具备异常捕获、日志系统、单实例控制等能力的工业级应用,有效提升软件在桌面端开发场景下的稳定性与用户体验。本文以main.cpp为核心,深入探

weixin_30838873的博客 371

Harness Engineering:让Coding Agent真正落地生产

本文将带你系统性地了解如何让Coding Agent真正落地生产,核心是依托(全球领先的持续交付、云成本管理、 feature flagging、安全治理一体化平台),结合企业级AIDD(AI-Driven Development)的工程化实践,构建一套可信赖、可观测、可扩展、可治理的Coding Agent落地体系。核心概念与理论基础:什么是Coding Agent?它和普通的AI代码补全工具(比如GitHub Copilot)有什么区别?什么是Harness Engineering?

移动开发前沿的博客 454

HCIP - Al Solution 华为认证—— 3、大模型基础

00:20核心目标: 与GPT类似,旨在学习一个通用的预训练模型,以便在大量不同任务上通过微调快速适配。与GPT的对比: BERT的效果在实验数据上优于GPT-1。模型特点: 采用双向的Transformer编码器结构,能够实现不同位置信息之间的互通,这与GPT的单向结构不同。06:3735:45核心思想: 尝试将标准的Transformer结构直接应用于图像,并对图像分类流程进行最少的修改。具体操作流程:图像分块: 将整幅图像拆分成多个小的图像块(Patch)。

qq837993702的博客 158

收藏夹记录

6、问题产生场景:通过git下载QGroudControl后,无法编译源码。5、问题产生场景:关于QGroudControl的介绍。1、问题产生场景:关于RflySim平台的介绍及其功能。3、问题产生场景:使用QML技术,如何实现跨平台开发。4、问题产生场景:使用QML技术,如何实现跨平台开发。5、问题产生场景:Qt程序移植到Linux平台运行。1、问题产生场景:安装Qt后,设置断点后不生效。1、问题产生场景:五阶魔方入门教程。2、问题产生场景:怎们添加日志库。链接说明:主要说明翻楞公式。

天码丶行满 1177

轴承故障诊断领域的论文到底有多水

这个是最让人困惑的,就好像你说自己证明了某个方法更好,但是你却没有交代自己怎么做的,或者说你交代的过程有外行话或者逻辑上的缺陷,但是你就这么给出个结果完事了。由于自己没有足够大的学术交流圈子,为了尽量避免误判,我在原来13篇论文的基础上又读了18篇,这些论文至少都出自中文核心,有一些还有EI的title,事实上近几年能找到的文章也不算多,这些基本能说明问题了。当然,还有更多细节,比如说损失函数你得交代吧,模型超参数得介绍全吧,至少数据集是哪个工况下的得说吧,当你想复现这些论文,关注点在这些地方的时候。

weixin_50642818的博客 3050

Linux下log4cxx的安装使用

From: http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=78707&id=368589 Log4cxx是开放源代码项目Apache Logging Service的子项目之一,用于为C++程序提供日志功能,以便开发者对目标程序进行调试和审计。 要使用log4cxx,首先要从官网下载,官网是http://logging.

tina_tian1的博客 3698

【MERRA-2数据集】M2I1NXASM (5.12.4) 和 M2I1NXINT (5.12.4)概述

M2I1NXASM (5.12.4) 和 M2I1NXINT (5.12.4)概述

WW、forever的博客 680

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Log:Spdlog初探(1)

文章目录Log:Spdlog初探简介spdlog简介安装/使用Header only version编译静态库Linux版本Windows版本代码说明设置日志输出样式 Log:Spdlog初探 简介 公司需要开新项目,提议更换日志库,交给我让我调研一下spdlog库的使用。 spdlog简介 Github地址:Github地址 官网介绍:Very fast, header-only/compile...

u011218356的博客 9234

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

从零构建跨平台SPICE客户端:C++核心实现与Qt GUI集成指南

在虚拟化与远程桌面技术领域,SPICE协议以其高性能的图形与多媒体传输能力,成为构建高效云桌面和远程办公解决方案的关键技术。其工作原理基于多通道架构,通过主通道、显示通道、输入通道等分工协作,实现了低延迟的桌面交互体验。从技术价值看,深入理解SPICE协议栈有助于开发者定制化集成、性能优化及协议调试。在应用场景上,它广泛服务于KVM/QEMU虚拟化环境、桌面云和嵌入式图形终端。本文聚焦于使用C++和CMake构建跨平台SPICE客户端,详细解析了如何利用libspice-client-glib库进行核心连接

weixin_30608503的博客 354

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

spdlog实战:C++日志库的工程化接入与性能优化

在C++项目开发中,日志记录不仅是程序运行状态的可视化窗口,更是排查故障、分析性能的关键手段。从基础的printf输出到成熟的日志系统,核心区别在于是否具备多线程安全、日志级别过滤、格式化输出以及异步写入等工程能力。spdlog作为一款高性能C++日志库,通过清晰的logger、sink、formatter职责划分,将输出目标与业务逻辑解耦,并提供了同步与异步两种模式,配合滚动文件、按日切割等机制,可灵活适配服务器、桌面应用等不同场景。合理利用日志级别与异步队列,既能在开发期快速定位问题,又能在生产环境保证

weixin_30315435的博客 446

C/C++格式化日志库实现代码

头文件如下: /*****************************************************/ /* 跨平台日志函数,Linux下与windows下亲测有效 */ /*****************************************************/ #ifndef _LOG_FORMAT_H_ #define _LOG_FORMAT_H_ // 日志等级 enum LogLevel { _LOG_T...

huang714的专栏 325

【C C++开源库】单片机 嵌入式中的C语言日志库_单片机开源库

我们平时开发中,log打印必不可少,仅仅使用printf,则log信息不好定位。使用时,再根据不同的平台自己定义一个获取系统时间的函数,以注册的方式进行绑定。日志系统在系统开发和调整过程中的重要性,大家应该都清楚,特别是项目出问题之后,却没有日志可以帮忙定位问题,就非常令人痛苦。以上是比较基本的功能,但是在嵌入式设备中,有的时候我们希望可以保存设备的运行日志,我们需要以下的一些功能;这里简单分享一个我自己用的一个极简的log模块:log颜色可设置、带时间戳、文件、行号、函数。以上这些需求不一定会全部实现。

2401_84263114的博客 1002

C/C++格式化日志库的实现

头文件如下: /*****************************************************/ /* 跨平台日志函数,Linux下与windows下亲测有效 */ /*****************************************************/ #ifndef _LOG_FORMAT_H_ #define _...

Yan_bb_5的博客 1083
上一篇: C/C++ 操作ini文件(SinpleIni 跨平台库)
下一篇: Linux Makefile入门总结
cpp_learners
博客等级 码龄7年 1526粉丝 274原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

cpp_learners

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

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

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

打赏作者

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

抵扣说明:

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

余额充值