http://blog.csdn.net/sky_qing/article/details/7208645

一、安装:

我看网上好多人介绍log4c安装的时候都说有两个步骤:先下载expat安装包并安装expat,然后下载log4c安装包并安装log4c。这么看来,log4c是依赖expat的。但是有时候我们不想使用的日志系统还要依赖别的库,毕竟现在的开源日志系统很多,这样一来log4c就没有那么大的优势了。所以我仔细看了log4c的README文档,发现log4c模块默认情况下是使用expat库来作为XML文件的解析器(因为log4c的配置文件默认是一个叫log4crc的XML文件),我们可以在运行配置文件的时候加上--without-expat选项就可以不使用expat库而使用log4c自定义的解析器,该解析器是使用lex/yacc的代码进行解析的。
安装步骤跟很多其他的库一样,都是三个步骤:

  1. ./configure
  2. make
  3. make install

我们可以在configure的时候加一些选项,如果要设置log4c的安装路径为/usr/local/log4c,我们就可以加--prefix=/usr/local/log4c,如果不想依赖expat解析器,我们可以加--without-expat。如果我们要指定软件运行的系统平台,交叉环境下,我们可以用--host选项来设置,如果运行在arm平台下就加--host=arm-linux,如果是运行在mips平台下就加--host=mips-linux。

如果安装完的时候出现了以下错误,不要着急:
../../src/log4c/.libs/liblog4c.so: undefined reference to `rpl_malloc'
../../src/log4c/.libs/liblog4c.so: undefined reference to `rpl_realloc'
解决方法如下:
修改log4c_build/log4c-1.2.1/src/config.h.in文件:
将201行的#undef malloc注释掉。
将204行的#undef realloc注释掉。
然后执行以下命令:

  1. ./configure(同样有必要的情况下加上相应的选项)
  2. make clean
  3. make
  4. make install

二、介绍一下log4c的配置文件log4crc:

log4c中有三个重要的概念, category, appender, layout。
1. category(类型)用于区分不同的logger, 其实它就是个logger。在一个程序中我们可以通过category来指定很多的logger,用于不同的目的。
2. appdender用于描述输出流,通过为category来指定一个appdender,可以决定将log信息来输出到什么地方去,比如stdout, stderr, 文件, 或者是socket等等。说说常见的两种,stdout是输出到控制台,文件当然就是输出到文件咯,在log4c中默认的是使用轮询文件保存日志,假如我们设定的文件名为wlanLog(配置文件中是appender节点的prefix属性),文件的maxsize设置为102400(Bytes),文件的maxnum为10(文件的最多个数),那么日志会保存在wlanLog.0文件中,当该文件的大小达到102400Bytes是就会自动保存到wlanLog.1文件中,依次类推,当文件的个数达到maxnum且文件已满,接下来会自动保存到wlanLog.0文件中,这样循环保存的方式就是轮询。
3. layout用于指定日志信息的格式,通过为appender来指定一个layout,可以决定log信息以何种格式来输出,比如是否有带有时间戳, 是否包含文件位置信息等,以及他们在一条log信息中的输出格式的等,一般有basic和dated两种。大家感兴趣可以分别去试一下看看日志有什么区别。
最后,说一下log4crc文件放在项目工程生成的目标文件的那个目录下。

三、使用:

  1. // 初始化
  2. log4c_init();
  3. // 获取一个已有的category,这个category(此处为WLAN_Console)必须先配置到配置文件中。
  4. log4c_category_t* mycat = log4c_category_get("WLAN_Console");
  5. // 用该category进行日志输出,日志的类型为DEBUG,输出信息为 "Hello World!",
  6. log4c_category_log(mycat, LOG4C_PRIORITY_DEBUG, "Hello World!");
  7. // 去初始化
  8. log4c_fini();
  9. // log4c_category_log的原型为:
  10. static LOG4C_INLINE void log4c_category_log(const log4c_category_t* a_category,
  11. int a_priority,
  12. const char* a_format,
  13. ...)
  14. // 其中后面的日志输出的格式化字符串a_format跟printf的输出格式化字符串一样,后面的参量表也和printf一样。非常方便!

log4c的日志优先级有11个,在src/log4c/目录下的priority.h中。我们常用的也就error、warn、info、debug和trace。

  1. /**
  2. * Predefined Levels of priorities. These correspond to the priority levels
  3. * used by syslog(3).
  4. **/
  5. typedef enum {
  6. /** fatal */        LOG4C_PRIORITY_FATAL    = 000,
  7. /** alert */        LOG4C_PRIORITY_ALERT    = 100,
  8. /** crit */         LOG4C_PRIORITY_CRIT     = 200,
  9. /** error */        LOG4C_PRIORITY_ERROR    = 300,
  10. /** warn */         LOG4C_PRIORITY_WARN     = 400,
  11. /** notice */       LOG4C_PRIORITY_NOTICE   = 500,
  12. /** info */         LOG4C_PRIORITY_INFO     = 600,
  13. /** debug */        LOG4C_PRIORITY_DEBUG    = 700,
  14. /** trace */        LOG4C_PRIORITY_TRACE    = 800,
  15. /** notset */       LOG4C_PRIORITY_NOTSET   = 900,
  16. /** unknown */      LOG4C_PRIORITY_UNKNOWN  = 1000
  17. } log4c_priority_level_t;

有时候为了方便,我们可以将log4c_category_log用宏定义封装起来,这个网上有例子,我给个链接吧:

http://www.cnblogs.com/jyli/archive/2010/02/11/1660606.html

我们也可以用一个函数封装起来,这个网上我没找到,我就把我作的封装分享一下吧,因为这个牵扯到变参函数的参数传递,所以可能好多刚接触到变参函数的童鞋不是很清楚。

  1. /**********************************************************************
  2. 函数名称          :       logOut
  3. 创建日期          :       2011-12-27
  4. 作者              :<span style="white-space:pre">     </span>  丶小小小威
  5. 函数描述          :       将日志输出到控制台
  6. 输入参数          :
  7. const LOG_LEVEL level :   日志输出的级别
  8. const char *format    :   日志输出的格式化字符串
  9. 输出参数          :
  10. 返回值            :
  11. **********************************************************************/
  12. void CLogger::logOut(const LOG_LEVEL level, const char *format, ...)
  13. {
  14. char temp[MAX_LEN] = {0};
  15. int ret = 0;
  16. va_list ap;
  17. va_start(ap, format);
  18. ret = vsnprintf(temp, MAX_LEN, format, ap);
  19. assert((-1<ret) && (MAX_LEN>ret));
  20. switch (m_logMode)
  21. {
  22. case TO_CONSOLE_AND_FILE:    //既输出到控制台又输出到文件
  23. {
  24. if (m_consoleCategory && m_fileCategory)
  25. {
  26. log4c_category_log(m_consoleCategory, level, "%s", temp);
  27. log4c_category_log(m_fileCategory, level, "%s", temp);
  28. }
  29. break;
  30. }
  31. case TO_CONSOLE:             //输出到控制台
  32. {
  33. log4c_category_log(m_consoleCategory, level, "%s", temp);
  34. break;
  35. }
  36. case TO_FILE:                //输出到文件
  37. {
  38. log4c_category_log(m_fileCategory, level, "%s", temp);
  39. break;
  40. }
  41. default:
  42. break;
  43. }
  44. va_end(ap);
  45. }

说明:我这里的LOG_LEVEL是我自己定义的一个枚举类型,成员为常用的几种日志类型(或者说优先级),m_logMode是我Log模块封装类的一个成员变量,表示日志输出的方式,上面的三种。我想这个我就不用多说了吧,你懂的,= =!

下面调用的时候也很简单:

  1. char c = '\x41';
  2. char s[20];
  3. const char *p = "How do you do";
  4. int a = 1234;
  5. int ha = 12;
  6. int *i;
  7. i = &ha;
  8. float f = 3.141592653589;
  9. double x = 0.12345678987654321;
  10. strcpy(s, "Hello, Comrade");
  11. logger->logOut(ERROR, "a=%d", a);        /*结果输出十进制整数a=1234*/
  12. printf("===============================> a=%d\n\n", a);
  13. logger->logOut(ERROR, "a=%6d", a);   /*结果输出6位十进制整数a=  1234*/
  14. printf("===============================> a=%6d\n\n", a);
  15. logger->logOut(ERROR, "a=%06d", a);  /*结果输出6位十进制整数a=001234*/
  16. printf("===============================> a=%06d\n\n", a);
  17. logger->logOut(ERROR, "a=%2d", a);   /*a超过2位,按实际值输出a=1234*/
  18. printf("===============================> a=%2d\n\n", a);
  19. logger->logOut(ERROR, "*i=%4d", *i); /*输出4位十进制整数×i=  12*/
  20. printf("===============================> *i=%4d\n\n", *i);
  21. logger->logOut(ERROR, "*i=%-4d", *i);    /*输出左对齐4位十进制整数×i=12*/
  22. printf("===============================> *i=%-4d\n\n", *i);
  23. logger->logOut(ERROR, "i=%p", i);        /*输出地址i=0xbf96538c*/
  24. printf("===============================> i=%p\n\n", i);
  25. logger->logOut(ERROR, "f=%f", f);        /*输出浮点数f=3.141593*/
  26. printf("===============================> f=%f\n\n", f);
  27. logger->logOut(ERROR, "f=6.4f", f);  /*输出6位其中小数点后4位的浮点数 f=3.1416*/
  28. printf("===============================> f=6.4f\n", f);
  29. logger->logOut(ERROR, "x=%lf", x);   /*输出长浮点数x=0.123457*/
  30. printf("===============================> x=%lf\n\n", x);
  31. logger->logOut(ERROR, "x=%18.16lf", x);  /*输出18位其中小数点后16位的长浮点数 x=0.1234567898765432*/
  32. printf("===============================> x=%18.16lf\n\n", x);
  33. logger->logOut(ERROR, "c=%c", c);        /*输出字符c=A*/
  34. printf("===============================> c=%c\n\n", c);
  35. logger->logOut(ERROR, "c=%x", c);        /*输出字符ASCII码值c=41*/
  36. printf("===============================> c=%x\n\n", c);
  37. logger->logOut(ERROR, "s[]=%s", s);  /*输出数组字符串s[]=Hello, Comrade*/
  38. printf("===============================> s[]=%s\n\n", s);
  39. logger->logOut(ERROR, "s[]=%6.9s", s);   /*输出最多9个字符的字符串s[]=Hello, Co*/
  40. printf("===============================> s[]=%6.9s\n\n", s);
  41. logger->logOut(ERROR, "s=%p", s);        /*输出数组字符串首字符地址s=FFBE*/
  42. printf("===============================> s=%p\n\n", s);
  43. logger->logOut(ERROR, "*p=%s", p);   /*输出指针字符串p=How do you do*/
  44. printf("===============================> *p=%s\n\n", p);
  45. logger->logOut(ERROR, "p=%p", p);        /*输出指针的值p=0x8049a70*/
  46. printf("===============================> p=%p\n\n", p);

说明:logger是我写的日志封装类的一个对象,大家可以把上面的部分代码加到自己的程序中,看看输出结果和printf到底是不是一样?我测试过,完全一样,这样一看,使用log4c日志模块更让人一目了然,尤其是在一个比较大的项目中,有一个好的日志模块将是非常重要的!差点忘了还有个编译运行。

四、编译运行:

编译的时候要链接上库和头文件。编译的格式如下:

说明:我用的是mips,所以编译时使用mips-linux-g++,我的log4c安装默认的路径下:/usr/local。这里用到的libxml2是因为我涉及修改log4c的配置文件log4crc,是一个XML文件,我选择libxml2。在mips上运行的时候要先告诉mips库所在的位置,使用export LD_LIBRARY_PATH=“库所在的位置”,建议大家写个Makefile。

五、log4crc配置文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE log4c SYSTEM "">
  3. <log4c version="1.2.1">
  4. <config>
  5. <bufsize>0</bufsize>
  6. <debug level="2"/>
  7. <nocleanup>0</nocleanup>
  8. <reread>1</reread>
  9. </config>
  10. <category name="root" priority="notice"/>
  11. <category name="six13log.log" priority="error" appender="stdout"/>
  12. <!--输出到控制台-->
  13. <category name="WLAN_Console" priority="trace" appender="stdout"/>
  14. <!--保存日志到文件-->
  15. <category name="WLAN_File" priority="trace" appender="myrollingfileappender"/>
  16. <!--logdir为日志输出路径  prefix为文件名  layout为输出格式 -->
  17. <appender name="myrollingfileappender" type="rollingfile" logdir="." prefix="wlan_log" layout="dated" rollingpolicy="myrollingpolicy"/>
  18. <!--sizewin表示达到最大值后新建日志文件  值由maxsize设定,单位Bytes     maxnum为最大文件数目-->
  19. <rollingpolicy name="myrollingpolicy" type="sizewin" maxsize="102400" maxnum="10"/>
  20. <appender name="stdout" type="stream" layout="basic"/>
  21. <appender name="stderr" type="stream" layout="dated"/>
  22. <appender name="syslog" type="syslog" layout="basic"/>
  23. <appender name="s13file" type="s13_file" layout="basic"/>
  24. <appender name="plain_stderr" type="s13_stderr" layout="none"/>
  25. <appender name="cat_stderr" type="s13_stderr" layout="catlayout"/>
  26. <appender name="xml_stderr" type="s13_stderr" layout="xmllayout"/>
  27. <appender name="user_stderr" type="s13_stderr" layout="userlayout"/>
  28. <layout name="basic" type="basic"/>
  29. <layout name="dated" type="dated"/>
  30. <layout name="catlayout" type="s13_cat"/>
  31. <layout name="xmllayout" type="s13_xml"/>
  32. <layout name="none" type="s13_none"/>
  33. <layout name="userlayout" type="s13_userloc"/>
  34. <category name="six13log.log.app.application2" priority="debug" appender="cat_stderr"/>
  35. <category name="six13log.log.app.application3" priority="debug" appender="user_stderr"/>
  36. <category name="six13log.log.app" priority="debug" appender="myrollingfileappender"/>
  37. <category name="log4c.examples.helloworld" priority="debug" appender="stdout"/>
  38. </log4c>

Over~~~
  最后祝大家工作顺利!有什么不准确的地方希望大家提出来,共同探讨。谢谢~

开源日志系统 log4c 使用心得+总结的更多相关文章

  1. 开源日志系统比较:scribe、chukwa、kafka、flume

    1. 背景介绍 许多公司的平台每天会产生大量的日志(一般为流式数据,如,搜索引擎的pv,查询等),处理这些日志需要特定的日志系统,一般而言,这些系统需要具有以下特征: (1) 构建应用系统和分析系统的 ...

  2. 使用 SLF4J + LogBack 构建日志系统(转)

    转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogB ...

  3. c++开源日志log4cplus使用开发文档

    下载地址:http://files.cnblogs.com/files/lizhigang/LOG4CPLUS%E5%BC%80%E5%8F%91%E4%B8%8E%E4%BD%BF%E7%94%A8 ...

  4. 开源社交系统ThinkSNS v4.6.1更新日志及功能详解!

    ThinkSNS 开源社交系统 v4.6.1更新日志 [修复]聊天无法使用emoji问题 [修复]后台禁用用户后,app第三方登录可登录问题 [修复]部分接口问题 [修复]h5个人中心获取用户信息问题 ...

  5. 利用开源架构ELK构建分布式日志系统

    问题导读 1.ELK产生的背景?2.ELK的基本组成模块以及各个模块的作用?3.ELK的使用总计有哪些? 背景 日志,对每个系统来说,都是很重要,又很容易被忽视的部分.日志里记录了程序执行的关键信息, ...

  6. C++ 高性能无锁日志系统

    服务器编程中,日志系统需要满足几个条件 .高效,日志系统不应占用太多资源 .简洁,为了一个简单的日志功能引入大量第三方代码未必值得 .线程安全,服务器中各个线程都能同时写出日志 .轮替,服务器不出故障 ...

  7. [Asp.net 5] Logging-其他日志系统的实现

    Microsoft.Framework.Logging.NLog 使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger.ILoggerProvider.所以在当 ...

  8. 【转载】scribe、chukwa、kafka、flume日志系统对比

    原文地址:http://www.ttlsa.com/log-system/scribe-chukwa-kafka-flume-log-system-contrast/ 1. 背景介绍许多公司的平台每天 ...

  9. 爆料喽!!!开源日志库Logger的剖析分析

    导读 Logger类提供了多种方法来处理日志活动.上一篇介绍了开源日志库Logger的使用,今天我主要来分析Logger实现的原理. 库的整体架构图 详细剖析 我们从使用的角度来对Logger库抽茧剥 ...

随机推荐

  1. 不可小觑的Web开发编码规范

    http://www.csdn.net/article/2013-10-21/2817235-coding-conventions-in-web-development 摘要:编码规范是一套规章制度, ...

  2. VMware虚拟机相关文件问题

    .vmx VM的配置文件 .vmdk VM的虚拟硬盘 .vmsd VM快照和相关联的vmdk的字典文件 .vswap 虚拟交换文件 .nvram 虚拟机的BIOS信息.VM会生成VMX, VMDK, ...

  3. Android SDK 下载速度慢解决方法

    Mac 本搞Android开发,遇到Android SDK 下载速度慢,解决方法大概有两种.第一,FQ.这种方法比较彻底,但是要想有稳定的效果还的要花大价钱.第二,有些高人直接给了SDK中各软件的下载 ...

  4. zoj2314 经典 无源汇有上下界最大流 并输出可行流

    ZOJ Problem Set - 2314 Reactor Cooling Time Limit: 5 Seconds      Memory Limit: 32768 KB      Specia ...

  5. Row Cache Objects

    This latch comes into play when user processes are attempting to access or update the cached data di ...

  6. iOS 9之SFSafariViewController

    金田( github 示例源码) 有时候需要在App内部打开一个网页,例如为了展示公司官网,产品列表信息,Facebook,微博等.以前都是使用 UIWebView,iOS 8引入了WKWebView ...

  7. leetcode:Multiply Strings(字符串的乘法)【面试算法题】

    题目: Given two numbers represented as strings, return multiplication of the numbers as a string. Note ...

  8. 线程、线程句柄、线程ID

     什么是句柄:句柄是一种指向指针的指针.我们知道,所谓指针是一种内存地址.应用程序启动后,组成这个程序的各对象是住留在内存的.如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址 ...

  9. MongoDB 和 mySql 的关系

    1. mysql 和 MongoDb MySQL与MongoDB都是开源的常用数据库,但是MySQL是传统的关系型数据库,MongoDB则是非关系型数据库,也叫文档型数据库,是一种NoSQL的数据库. ...

  10. jQuery.extend 和 jQuery.fn.extend

    1.jQuery.extend 我们先把jQuery看成了一个类,这样好理解一些.jQuery.extend(),是扩展的jQuery这个类. 假设我们把jQuery这个类看成是人类,能吃饭能喝水能跑 ...