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

项目中,最重要的模块之一就是日志了,今天这篇博客记录项目中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日志如何使用,直接拷贝上面项目代码去到自己的项目中就可以直接使用了!

猜你喜欢

转载自blog.csdn.net/cpp_learner/article/details/128738417