博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
log4cxx 的编译安装过程和使用
阅读量:4047 次
发布时间:2019-05-25

本文共 15367 字,大约阅读时间需要 51 分钟。

简介
log4cxx是Java社区著名的的c++移植版,用于为C++程序提供日志功能,以便开发者对目标程序进行调试和审计,log4cxx是apache软件基金会的开源项目,基于APR实现跨平台支持。一个良好的日志系统不管是开发、调试和维护,对一个项目来说是多么的重要,我想做过开发的同学深知这点。我用过的日志框架比较少,所以在这里不做与其它日志框架的比较,类似的日志框架还有GLog、boost log,如果有兴趣可以去研究一下。
 
其实刚工作时,9c的pass9项目中就需要日志系统,只是那时候还不知道log4cxx这个好东西,只能自己动手实现了一个简单,主要是用到了c函数的可变参数,值得注意的是线程安全的问题,所以在写文件时要加互斥锁,为了提高性能,还需注意文件块大小问题,当然了,功能特别简单,只有控制台和文件输出,有等级、时间、线程号、文件名、行号、函数名这些输出。
 
下载与安装  
环境:linux和windows
依赖:apr、apr-util
apr、apr-util下载地址:
log4cxx下载地址:
下面介绍下载源码以及编译过程
1. 
下载
 log4cxx 以及 apr 和 apr-util 源码:
从上面的下载地址中下载如下三个文件;
 
2. 将 3 个压缩包解压到同一个目录.
 
3. 将 apr-1.2.11 重命名为 apr, 将 apr-util-1.2.10 重命名为 apr-util.
最终如下:
 
4. 使用 cmd, 切换至 apache-log4cxx-0.10.0 目录, 运行 configure.bat
 
5. 在与第 4  步同一目录下的 cmd 中, 执行 configure-aprutil.bat
1)和2)两个步骤中选择一个执行就行了
1) 此时, 如果环境变量中没有 sed 程序, 则会出现:
此时应该:
手动修改 apr-util\include\apu.hw 里的内容
#define APU_HAVE_APR_ICONV 1
改为
#define APU_HAVE_APR_ICONV 0
2) 如果系统可以找到 sed 程序, 那么会出现:
 
6. 打开 apache-log4cxx-0.10.0\projects 下的 log4cxx.dsw
打开工程会提示转换:
 
7. 将 log4cxx 设置为启动项.
 
8. 开始编译. 快捷键 F7.
 
9.
1) 出现
'4>D:\log4cxx-src\apache-log4cxx-0.10.0\src\main\include\log4cxx/spi/loggingevent.h(155): error C2252: 只能在命名空间范围内显式实例化模板' 错误.
a) 双击 "输出" 窗口中的错误行, 此时会在 "代码窗口" 中出现错误的位置.
b) 选择 LOG4CXX_LIST_DEF, 按键盘 F12, 此时会跳转到该宏的定义
c) 将
#define LOG4CXX_LIST_DEF(N, T) \ template class LOG4CXX_EXPORT std::allocator
; \ template class LOG4CXX_EXPORT std::vector
; \ typedef std::vector
N
替换为: #define LOG4CXX_LIST_DEF(N, T) \ typedef std::vector
N
 
2) 出现
'2>network_io\unix\multicast.c(137): error C2079: “mip”使用未定义的 struct“group_source_req"' 等错误.
双击第一行出错输出, 将 136 和 148 行的 #if MCAST_JOIN_SOURCE_GROUP 注释, 替换为 #if defined (group_source_req)
 
 
3) 出现
'4>..\src\main\cpp\stringhelper.cpp(64): error C2039: “insert_iterator”: 不是“std”的成员' 等错误.
在该 .cpp 中(stringhelper.cpp) 加入头文件
:
 
4) 出现
'无法解析的外部符号 xxx' 等错误.
将 apr, aprutil, xml 添加至 log4cxx 的引用中.
 
10. 选择重新生成解决方案. 否则可能会造成 '无法打开 apr_iconv.h' 错误. 个人怀疑是第 5 步中, configure-aprutil.bat 脚本中的 sed 命令没有正确更新文件的时间所致.
编译成功后:
 
下面介绍其使用方法:
1.优先级
Logger的语法:               
log4j.rootLogger = [ level ] , appenderName, appenderName, …          其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,可以控制到应用程序中相应级别的日志信息的开关。比如这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。 appenderName名字任意,用来标示日志信息输出到哪里,可以同时指定多个。 
2.输出目的地
Appender的语法:               
log4j.appender.appenderName = fully.qualified.name.of.appender.class         log4j.appender.appenderName.option1 = value1            …                log4j.appender.appenderName.option = valueN            其中,Log4j提供的appender有以下几种:            org.apache.log4j.ConsoleAppender 控制台            org.apache.log4j.FileAppender 文件             org.apache.log4j.DailyRollingFileAppender 每天产生一个日志文件          org.apache.log4j.RollingFileAppender 文件大小到达指定尺寸的时候产生一个新的文件        org.apache.log4j.WriterAppender 将日志信息以流格式发送到任意指定的地方
3.输出格式
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class        log4j.appender.appenderName.layout.option1 = value1           …                log4j.appender.appenderName.layout.option = valueN          Log4j提供的Layout有以下几种:            org.apache.log4j.HTMLLayout 以HTML表格形式布局           org.apache.log4j.PatternLayout 可以灵活地指定布局模式           org.apache.log4j.SimpleLayout 包含日志信息的级别和信息字符串          org.apache.log4j.TTCCLayout 包含日志产生的时间、线程、类别等等信息          Log4j采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:%m 输出代码中指定的消息              %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL           %r 输出自应用启动到输出该log信息耗费的毫秒数            %c 输出所属的类目,通常就是所在类的全名            %t 输出产生该日志事件的线程名             %n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”          %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出2008年11月14日 15:16:17,890 %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。
以下只讲怎样使用。
一、建测试工程:testlog4cxx,直接选控制台应用程序,    在配置属性页中,选C/C++,常规,在附加包含目录中加入“./”;选链接器,常规,在附加库目录中加入"./",点选中常规下面的输入,在附加依赖项中加入“log4cxx/log4cxx.lib”
二、在测试工程目录下加入log4cxx文件包
三、加入include头文件:
#include
#include
四、定义配置文件log4cxx.properties的位置 log4cxx::PropertyConfigurator::configure("log4cxx.properties"); 此处的作用为定义配置文件的位置,如果想让程序在D盘根目录下加载配置文件,可以如下定义: log4cxx::PropertyConfigurator::configure("D:\\log4cxx.properties"); 五、定义不同的打印级别 此在配置文件中log4cxx.properties将会有所定义。假设有这样的场景,你必须使用别人提供一个DLL用来获取接口,此DLL中使用了log4cxx日志,然后你又想在自己的工程中同样引入log4cxx日志,为了区分你的日志和别人的日志,你该如何做呢,假设别人使用的为log4j.rootLogger顶级接口。(默认情况下,所有的日志都会在顶级接口对应的日志文件中进行记录) 这样一个设置可使得顶级接口与子接口分离: # 屏蔽gather的Appender继承  log4j.additivity.gather = false 以下配置假设引用的DLL库使用了log4cxx的根接口,并且输出两种级别的文件,一种为error,一种为debug # 设置root logger为DEBUG级别,使用了两个Appender log4j.rootLogger=DEBUG, COM, ERR # 设置sample logger为DEBUG级别 log4j.logger.sample = DEBUG, sample  # 屏蔽sample的Appender继承 log4j.additivity.sample = false log4j.logger.sample.error = WARN, sample.error #log4j.additivity.sample.error = false log4j.appender.COM=org.apache.log4j.RollingFileAppender log4j.appender.COM.File=../log/dll_output.log log4j.appender.COM.Append=false log4j.appender.COM.MaxFileSize=3MB log4j.appender.COM.MaxBackupIndex=10 log4j.appender.COM.ImmediateFlush=true log4j.appender.COM.layout=org.apache.log4j.PatternLayout log4j.appender.COM.layout.ConversionPattern=%d %-5p %m%n log4j.appender.ERR=org.apache.log4j.RollingFileAppender log4j.appender.ERR.File=../log/dll_error.log log4j.appender.ERR.Append=false log4j.appender.ERR.Threshold=ERROR log4j.appender.ERR.MaxFileSize=3MB log4j.appender.ERR.MaxBackupIndex=10 log4j.appender.ERR.layout=org.apache.log4j.PatternLayout log4j.appender.ERR.layout.ConversionPattern=%d %-5p %m%n log4j.appender.sample=org.apache.log4j.RollingFileAppender log4j.appender.sample.File=../log/sample_output.log log4j.appender.sample.Append=false log4j.appender.sample.MaxFileSize=10MB log4j.appender.sample.MaxBackupIndex=10 log4j.appender.sample.ImmediateFlush=true log4j.appender.sample.layout=org.apache.log4j.PatternLayout log4j.appender.sample.layout.ConversionPattern=%d %-5p %m%n log4j.appender.sample.error=org.apache.log4j.RollingFileAppender log4j.appender.sample.error.File=../log/sample_error.log log4j.appender.sample.error.Append=false log4j.appender.sample.error.MaxFileSize=3MB log4j.appender.sample.error.MaxBackupIndex=10 log4j.appender.sample.error.ImmediateFlush=true log4j.appender.sample.error.layout=org.apache.log4j.PatternLayout log4j.appender.sample.error.layout.ConversionPattern=%d %-5p %m%n   六、后台打印的日志与控制台显示的级别不同(一般控制台打印比较慢,显示的尽可能少,后台则尽可能详尽) 使用log4j.appender.ca.Threshold=WARN可达到控制台显示与后台打印不相同,如下一个配置文件设置: # 设置root logger为DEBUG级别,使用了两个Appender log4j.rootLogger=DEBUG, server, ca # 设置kline logger为DEBUG级别 log4j.logger.kline = DEBUG, kline, ca  # 屏蔽kline的Appender继承 log4j.additivity.kline = false log4j.logger.kline.error = WARN, kline.error, ca #log4j.additivity.kline.error = false log4j.appender.server=org.apache.log4j.RollingFileAppender log4j.appender.server.File=../log/server_output.log log4j.appender.server.Append=false log4j.appender.server.MaxFileSize=3MB log4j.appender.server.MaxBackupIndex=10 log4j.appender.server.ImmediateFlush=true log4j.appender.server.layout=org.apache.log4j.PatternLayout log4j.appender.server.layout.ConversionPattern=%d %-5p %m%n log4j.appender.server.error=org.apache.log4j.RollingFileAppender log4j.appender.server.error.File=../log/server_error.log log4j.appender.server.error.Append=false log4j.appender.server.error.Threshold=ERROR log4j.appender.server.error.MaxFileSize=3MB log4j.appender.server.error.MaxBackupIndex=10 log4j.appender.server.error.layout=org.apache.log4j.PatternLayout log4j.appender.server.error.layout.ConversionPattern=%d %-5p %m%n log4j.appender.kline=org.apache.log4j.RollingFileAppender log4j.appender.kline.File=../log/kline_output.log log4j.appender.kline.Append=false log4j.appender.kline.MaxFileSize=10MB log4j.appender.kline.MaxBackupIndex=10 log4j.appender.kline.ImmediateFlush=true log4j.appender.kline.layout=org.apache.log4j.PatternLayout log4j.appender.kline.layout.ConversionPattern=%d %-5p %m%n log4j.appender.kline.error=org.apache.log4j.RollingFileAppender log4j.appender.kline.error.File=../log/kline_error.log log4j.appender.kline.error.Append=false log4j.appender.kline.error.MaxFileSize=3MB log4j.appender.kline.error.MaxBackupIndex=10 log4j.appender.kline.error.ImmediateFlush=true log4j.appender.kline.error.layout=org.apache.log4j.PatternLayout log4j.appender.kline.error.layout.ConversionPattern=%d %-5p %m%n #对Appender ca进行设置: # 这是一个控制台类型的Appender #  输出格式(layout)为PatternLayout log4j.appender.ca=org.apache.log4j.ConsoleAppender log4j.appender.ca.Threshold=WARN log4j.appender.ca.layout=org.apache.log4j.PatternLayout log4j.appender.ca.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n   七、打印日志的方法 LOG4CXX_INFO(log4cxx::Logger::getLogger("hello"), "你好,log4cxx!"); 以上打印方法可行,不过写起来比较麻烦,建议进行一番包装。 如下代码所示: /****************************************************************************** author : luhx purpose : 日志系统,以宏log_XXX开头,封装log4cxx日志。 *******************************************************************************/ #pragma once     #include "log4cxx/logger.h" #include "log4cxx/propertyconfigurator.h" /* 日志类 */   #include
using namespace std;   class CServerlog; extern CServerlog* g_serverlog;   #define log_debug(pszFormat, ...) g_serverlog->WriteFormatDebugLog( pszFormat, __VA_ARGS__) #define log_info(pszFormat, ...) g_serverlog->WriteFormatInfoLog( pszFormat, __VA_ARGS__) #define log_warn(pszFormat, ...) g_serverlog->WriteFormatWarnLog( pszFormat, __VA_ARGS__) #define log_error(pszFormat, ...) g_serverlog->WriteFormatErrorLog( pszFormat, __VA_ARGS__)   class CServerlog { public: CServerlog(); ~CServerlog();   void WriteFormatDebugLog(char* lpszFormat, ...); void WriteFormatInfoLog(char* lpszFormat, ...);   void WriteFormatWarnLog(char* lpszFormat, ...); void WriteFormatErrorLog(char* lpszFormat, ...);   protected:   log4cxx::LoggerPtr infologger; log4cxx::LoggerPtr errorlogger; };     #include
#include
#include
#include "serverlog.h"     CServerlog* g_serverlog = new CServerlog();   CServerlog::CServerlog() { log4cxx::PropertyConfigurator::configure("log4cxx.properties"); infologger = (log4cxx::Logger::getLogger("server")); errorlogger = (log4cxx::Logger::getLogger("server.error")); }   CServerlog::~CServerlog() { }     void CServerlog::WriteFormatDebugLog(char* lpszFormat, ...) { va_list args; va_start(args, lpszFormat); CHAR szBuffer[1024]; vsprintf(szBuffer, lpszFormat, args); va_end(args); infologger->debug(szBuffer); }     void CServerlog::WriteFormatInfoLog(char* lpszFormat, ...) { va_list args; va_start(args, lpszFormat); CHAR szBuffer[1024]; vsprintf(szBuffer, lpszFormat, args); va_end(args); infologger->info(szBuffer); }   void CServerlog::WriteFormatWarnLog(char* lpszFormat, ...) { va_list args; va_start(args, lpszFormat); CHAR szBuffer[1024]; vsprintf(szBuffer, lpszFormat, args); va_end(args);   errorlogger->warn(szBuffer); }   void CServerlog::WriteFormatErrorLog(char* lpszFormat, ...) { va_list args; va_start(args, lpszFormat); CHAR szBuffer[1024]; vsprintf(szBuffer, lpszFormat, args); va_end(args); errorlogger->error(szBuffer); }     另外,发现打印出的日志在某些机器上不支持中文, 中文显示为乱码,通过在配置文件中增加如下配置项即可解决: log4j.appender.sample.encoding=UTF-8,这里,sample即为你的日志类. 前面已经说完了怎样使用log4cxx进行日志记录,今天发现问题稍有点复杂。原因是系统中用到的一个dll已经使用了log4cxx。我们在开发的过程中也想使用log4cxx,但不想与DLL中的日志写到同一个文件中,问题就来了,怎样区别打印到不同的文件中呢,DLL中采用的为应该为getRootLogger的方式。 这个网址中的文章很好,解决方案主要参考此文: log4cxx主要是由三部分组成:loggers, appenders和layouts.这三个主要组成部分,协同协作能够使我们根据实际的需要进行日志的输出,它们规定了日志信息的类型和级别,控制应用程序运行时的日志信息组成方式以及日志记录的输出方式。 Logger是Log4cxx的核心,Logger具有继承关系的层次结构,最顶层为RootLogger,每个Logger都有一个级别(Level),每个Logger可以附加多个Appender.Appender代表了日志输出的目标,对于每一个Appender可以通过Layout进行格式配置。 Logger命名:保持Logger与其所在的类的名称一致的方法是目前所知的最好的命名策略。 一个关于Logger继承的例子: #设置root logger 为DEBUG级别,使用了ca, fa两个Appender log4j.rootLogger = DEBUG, ca, fa #设置list logger log4j.logger.list = DEBUG, listApp #设置list.voice logger log4j.logger.list.voice= INFO, listVoice, listVoiceBak list是list.voice的父亲Logger, list.voice是list的儿子Logger. rootLogger是根Logger, 在此例中list和list.voice两个Logger又都继承了rootLogger,不过只是继承了Appenders,Level并没有继。(此解有待验证)   还是看配置文件:log4cxx.properties # 设置root logger为DEBUG级别,使用了ca和fa两个Appender  log4j.rootLogger=DEBUG, fa, ca  # 设置.listApp logger,屏蔽logger-list的LEVEL继承  log4j.logger.listApp=DEBUG, listApp # 设置.listApp2 logger,屏蔽logger-list的LEVEL继承  log4j.logger.listApp2=DEBUG, listApp2 #屏蔽listApp的Appender继承  log4j.additivity.listApp=false #屏蔽listApp2的Appender继承  log4j.additivity.listApp2=false   #对Appender fa进行设置:# 这是一个文件类型的Appender,  log4j.appender.fa=org.apache.log4j.FileAppender  log4j.appender.fa.ImmediateFlush=true # 其输出文件(File)为 Runlog.log,  log4j.appender.fa.File=Runlog.log  log4j.appender.fa.layout=org.apache.log4j.PatternLayout # 输出方式(Append)为覆盖方式,  log4j.appender.fa.Append=false # 输出格式(layout)为PatternLayout  log4j.appender.fa.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n     #对Appender ca进行设置: # 这是一个控制台类型的Appender  log4j.appender.ca=org.apache.log4j.ConsoleAppender # 输出格式(layout)为PatternLayout  log4j.appender.ca.layout=org.apache.log4j.PatternLayout  log4j.appender.ca.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n   #对Appender listApp进行设置# 这是一个文件类型的Appender,  log4j.appender.listApp=org.apache.log4j.FileAppender #立即写入日志文件  log4j.appender.listApp.ImmediateFlush=true # 其输出文件(File)为 listApp.log  log4j.appender.listApp.File=listApp.log # 输出方式(Append)为覆盖方式,  log4j.appender.listApp.Append=false  log4j.appender.listApp.layout=org.apache.log4j.PatternLayout  log4j.appender.listApp.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n   #对Appender listApp2进行设置  log4j.appender.listApp2=org.apache.log4j.FileAppender  log4j.appender.listApp2.ImmediateFlush=true  log4j.appender.listApp2.File=listApp2.log  log4j.appender.listApp2.Append=false  log4j.appender.listApp2.layout=org.apache.log4j.PatternLayout  log4j.appender.listApp2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %.16c - %m%n     以下为实现代码: // testlog4cxx.cpp : 定义控制台应用程序的入口点。 //   #include "stdafx.h" #include
using namespace std; #include
#include
  using namespace log4cxx; using namespace log4cxx::helpers;   int _tmain(int argc, _TCHAR* argv[]) {   PropertyConfigurator::configure("log4cxx.properties");   LOG4CXX_INFO(log4cxx::Logger::getLogger("list5"), "list,log4cxx!"); LOG4CXX_INFO(log4cxx::Logger::getLogger("list5"), "list,mylog4cxx!");   LOG4CXX_INFO(log4cxx::Logger::getLogger("listApp"), "listApp,log4cxx!");   LOG4CXX_INFO(log4cxx::Logger::getLogger("listApp2"), "listApp2, hello world!");   return 0; }   将log4cxx.properties与生成后的testlog4cxx.exe放置同一目录,运行后发现目录下生成三个文件,分别为:他们的文件名及内容分别为 Runlog.log: 2012-04-06 21:13:56 INFO  list5 - list,log4cxx!  2012-04-06 21:13:56 INFO  list5 - list,mylog4cxx!   listApp.log: 2012-04-06 21:13:56 INFO  listApp - listApp,log4cxx!  2012-04-06 21:13:56 INFO  listApp - listApp TimeRsp.nErrno: 123   listApp2.log: 2012-04-06 21:13:56 INFO  listApp2 - listApp2, hello world!   由此可以看出,所有Logger默认继承于rootLogger的Appender,一般情况下(Level级别允许)总会在Runlog.log中打出,若想有所例外,需用配置log4j.additivity.AppenderName = false将默认继承去除。

转载地址:http://wpfci.baihongyu.com/

你可能感兴趣的文章
python_time模块
查看>>
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>
JS牛客网编译环境的使用
查看>>
9、VUE面经
查看>>
关于进制转换的具体实现代码
查看>>
Golang 数据可视化利器 go-echarts ,实际使用
查看>>
mysql 跨机器查询,使用dblink
查看>>
mysql5.6.34 升级到mysql5.7.32
查看>>
dba 常用查询
查看>>
Oracle 异机恢复
查看>>
Oracle 12C DG 搭建(RAC-RAC/RAC-单机)
查看>>
Truncate 表之恢复
查看>>