今天想给我的C++项目找一个开源的日志类,用于记录系统日志,结果浪费了半个下午的时间。从网上搜索相关资料,找到以下几个备选方案:

1、log4cplus  下载地址:http://sourceforge.net/projects/log4cplus/files/log4cplus-stable/1.1.0

2、log4cxx  下载地址:http://logging.apache.org/log4cxx/download.html  (log4cxx 是由JAVA实现的 log4j 开源的,用C++实现的一个开源库)

3、glog  下载地址:http://code.google.com/p/google-glog/downloads/list 或者 https://github.com/google/glog

4、log4cpp  下载地址: http://sourceforge.net/projects/log4cpp/files

  我初步看了一下,第1个和第4个是sourceforge网站上的开源项目,不知道是不是被屏蔽了,总之是打不开网页。浪费我半小时找代理和FQ,均找不到。看到第2个是Java注明的日志类log4j的姊妹C++版,顿时感觉应该不错,结果编译的过程让我直接疯掉了。先是下载log4cxx源代码,又说光下载这个还不够,还要下载另外两个Apache项目(apr、apr-util)代码,下完这三个还不行,在Windows下编译还需要下一个Windows X64版本的Sed,好吧,这还不算数,居然还是链接失败,网上还找不到相应的解决方案,整个过程浪费我4个小时。

  所以今天的教训就是,人家的开源项目根本就不待见Windows平台,或者说根本不待见我这样的菜鸟。既然我是Windows平台上的一只小菜鸟,那我就老老实实用简单的东西吧。从第三方网站上下载Google glog,编译一下居然轻松通过,很好!

一、基本用法测试

  1、从网上下载google-glog-v0.3.4-50-gde75983.zip,解压到本地,可以看到工程文件google-glog.sln,可以用Visual Studio 2008打开。

  2、直接编译就可以得到libglog.dll、libglog.lib等文件,这里的lib文件在编译时要用,而dll文件则是运行时要用的,可以看出这里的glog采用的是“隐式”动态链接库编译方法。

  3、将解压出来的文件夹路径:“google-glog\src\windows”添加到Visual Studio 2008 的工程路径中,以便于引用头文件。同时将上一步编译出来的lib文件加入路径或者直接拷贝到自定义工程路径中;

  4、使用如下代码可以测试使用:

 1 #include <iostream>
 2 using namespace std;
 3
 4 #include <glog/logging.h>
 5 #pragma comment(lib, "libglog.lib")
 6
 7 int main(int argc, char **argv)
 8 {
 9     google::InitGoogleLogging("KLH");
10     google::SetLogDestination(google::INFO, "F://");
11
12     char str[20] = "hello log!";
13     LOG(INFO) << "Found " << google::COUNTER <<endl;
14     LOG(INFO) << str ;                // << " cookies";
15     LOG(WARNING) << "warning test";    // 会输出一个Warning日志
16     LOG(ERROR) << "error test";        // 会输出一个Error日志
17
18     system("pause");
19     return 0;
20 }

  5、编译生成的exe文件还不能直接运行,需要将第3步编译的dll文件拷贝到相同目录中才能运行。测试的日志文件自动生成在F:/根目录中。类似于如下格式内容:

1 Log file created at: 2015/12/14 20:28:18
2 Running on machine: VICTO-PC
3 Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg
4 I1214 20:28:18.590252  9648 main2.cpp:13] Found 0
5 I1214 20:28:18.591253  9648 main2.cpp:14] hello log!
6 W1214 20:28:18.591253  9648 main2.cpp:15] warning test
7 E1214 20:28:18.592252  9648 main2.cpp:16] error test 

  6、其实这里可以看出,用动态链接库编译的方式有个麻烦的地方就是编译出来的exe不能单独运行,必须拷贝dll文件放到一起才行。如何采用静态链接的方式呢?答案是要看官方doc文档的说法:在自定义工程中添加“GOOGLE_GLOG_DLL_DECL=” 和 “GLOG_NO_ABBREVIATED_SEVERITIES” 这两个宏,第二个宏主要是为了避免与windows.h冲突(下面会讲到),第一个宏才是使用静态链接库时必须的!在编译时可以编译两个版本:Release 和 Debug 以供调试时使用。

  7、在使用过程中一定要注意编译参数 “/MT” 和 “/MD” 的区别,当然还有 “/MTd” 和 “/MDd” 的不同,可以免去复杂的链接错误、冲定义等问题,在下一篇日志中会专门讲到,如果不清楚这个问题将会是很费劲的,包括之前写过一篇libevent入门的文章说在使用时要忽略一大堆的系统函数库,我觉得也是这个原因导致的。

、Windows平台应用

  当我在Windows平台项目上应用这个glog时遇到了一个问题,那就是直接编译上面的代码时会出现错误:

错误    2    fatal error C1189: #error :  ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.    d:\cppworkspace\opensourcelibrary\google-glog\src\windows\glog\log_severity.h    55

  双击这个错误很容易定位到出错的地方:

1 const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
2   NUM_SEVERITIES = 4;
3 #ifndef GLOG_NO_ABBREVIATED_SEVERITIES
4 # ifdef ERROR
5 #  error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
6 # endif
7 const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
8   ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
9 #endif

  其实解决这个错误倒是不难,可以看到只要是在Windows工程中预定义GLOG_NO_ABBREVIATED_SEVERITIES这个宏就可以了,但是为什么要这么做呢?找了一下,答案在官方文档中:

Notes for Windows users
Google glog defines a severity level ERROR, which is also defined in windows.h . You can make glog not define INFO, WARNING, ERROR, and FATAL by defining GLOG_NO_ABBREVIATED_SEVERITIES before including glog/logging.h . Even with this macro, you can still use the iostream like logging facilities:#define GLOG_NO_ABBREVIATED_SEVERITIES#include <windows.h>#include <glog/logging.h>// ...LOG(ERROR) << "This should work";LOG_IF(ERROR, x > y) << "This should be also OK";
However, you cannot use INFO, WARNING, ERROR, and FATAL anymore for functions defined in glog/logging.h .#define GLOG_NO_ABBREVIATED_SEVERITIES#include <windows.h>#include <glog/logging.h>// ...// This won't work.// google::FlushLogFiles(google::ERROR);// Use this instead.
  google::FlushLogFiles(google::GLOG_ERROR);
If you don't need ERROR defined by windows.h, there are a couple of more workarounds which sometimes don't work:
#define WIN32_LEAN_AND_MEAN or NOGDI before you #include windows.h .
#undef ERROR after you #include windows.h .
See this issue for more detail.

  这下就清楚了,原来是glog中原来定义的ERROR宏与windows.h中的ERROR冲突了,为了避免冲突,glog作出了改变,增加了GLOG_NO_ABBREVIATED_SEVERITIES宏定义用以区分,那么在代码中用google::GLOG_ERROR来代替原来的google::ERROR

、自定义glog日志格式

  要自定义glog输出格式并不难,可以直接修改logging.cc文件中的LogMessage::Init函数,直接给出修改的位置:

 1 void LogMessage::Init(const char* file,
 2                       int line,
 3                       LogSeverity severity,
 4                       void (LogMessage::*send_method)()) {
 5 ... ...
 6   if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
 7       /*
 8     stream() << LogSeverityNames[severity][0]
 9              << setw(2) << 1+data_->tm_time_.tm_mon
10              << setw(2) << data_->tm_time_.tm_mday
11              << ' '
12              << setw(2) << data_->tm_time_.tm_hour  << ':'
13              << setw(2) << data_->tm_time_.tm_min   << ':'
14              << setw(2) << data_->tm_time_.tm_sec   << "."
15              << setw(6) << usecs
16              << ' '
17              << setfill(' ') << setw(5)
18              << static_cast<unsigned int>(GetTID()) << setfill('0')
19              << ' '
20              << data_->basename_ << ':' << data_->line_ << "] ";
21              */
22       // Change output format. By KuLiuheng.    2015.12.15
23       stream()    << LogSeverityNames[severity][0]
24                 << ' '
25                 << setw(4) << 1900+data_->tm_time_.tm_year    << '-'
26                 << setw(2) << 1+data_->tm_time_.tm_mon    << '-'
27                 << setw(2) << data_->tm_time_.tm_mday
28                 << ' '
29                 << setw(2) << data_->tm_time_.tm_hour  << ':'
30                 << setw(2) << data_->tm_time_.tm_min   << ':'
31                 << setw(2) << data_->tm_time_.tm_sec   << "."
32                 << setw(6) << usecs
33                 << ' '
34                 << setfill(' ') << setw(5)
35                 << static_cast<unsigned int>(GetTID()) << setfill('0')
36                 << ' '
37                 << data_->basename_ << ':' << data_->line_ << "] ";
38   }
39 ... ...
40 }

  这样一来输出的格式就是:

Log file created at: 2015/12/15 14:31:05
Running on machine: VICTO-PC
Log line format: [IWEF] yyyy-mm-dd hh:mm:ss.uuuuuu threadid file:line] msg
I 2015-12-15 14:31:05.341013  2928 main2.cpp:14] Found 0
I 2015-12-15 14:31:05.343014  2928 main2.cpp:15] hello log!
W 2015-12-15 14:31:05.343014  2928 main2.cpp:16] warning test
E 2015-12-15 14:31:05.344014  2928 main2.cpp:17] error test

四、使用glog严重错误DUMP功能

  使用google::InstallFailureSignalHandler(); 和 google::InstallFailureWriter(&FatalMessageDump); 可以在程序出现严重错误时将详细的错误信息打印出来,但是使用默认编译的glog将会出现找不到此函数定义的问题,类似于:

error LNK2019: 无法解析的外部符号 "__declspec(dllimport) void __cdecl google::InstallFailureWriter(void (__cdecl*)(char const *,int))" (__imp_?InstallFailureWriter@google@@YAXP6AXPBDH@Z@Z),该符号在函数 "public: void __thiscall EnvironmentManager::Initialize(int,char * *,int)" (?Initialize@EnvironmentManager@@QAEXHPAPADH@Z) 中被引用
error LNK2019: 无法解析的外部符号 "__declspec(dllimport) void __cdecl google::InstallFailureSignalHandler(void)" (__imp_?InstallFailureSignalHandler@google@@YAXXZ),该符号在函数 "public: void __thiscall EnvironmentManager::Initialize(int,char * *,int)" (?Initialize@EnvironmentManager@@QAEXHPAPADH@Z) 中被引用

  这个时候只需要在默认的glog工程中,将signalhandler.cc 纳入到libglog工程中,重新编译即可。重新初始化glog的方法如下:

 1 // Start google log system:
 2 google::InitGoogleLogging(argv[0]);
 3 google::SetLogDestination(google::GLOG_INFO, ".//");
 4 google::SetStderrLogging(google::GLOG_INFO);
 5 google::SetLogFilenameExtension("log_");
 6 google::InstallFailureSignalHandler();
 7 google::InstallFailureWriter(&FatalMessageDump);
 8 FLAGS_colorlogtostderr = true;        // Set log color
 9 FLAGS_logbufsecs = 0;                // Set log output speed(s)
10 FLAGS_max_log_size = 1024;            // Set max log file size(GB)
11 FLAGS_stop_logging_if_full_disk = true;    // If disk is full

五、Linux/Uinux平台应用

  下载安装包之后,输入解压命令,直接进入解压后的目录准备编译:

./configue
make
make install

  特别提示一下,直接解压后的configure 以及相关.sh文件有可能是没有可执行权限的,用chmod a+x 给一下权限。如果要指定生成的文件路径,那么就在配置的时候输入:./configue --prefix=your_dir

  假设你的glog库的路径为/usr/local/lib/libglog.a,头文件路径为/usr/local/include/glog/logging.h,那么编译命令如下:

g++ test.cpp -o test -L/usr/local/lib -lglog -I/usr/local/include/glog

  glog可以采用命令行的模式配置参数,这也是它灵活易用的体现,有两种指定参数的方法,一种依赖于gflag如下:

./your_application --logtostderr=1     // 或者下面这种:
GLOG_logtostderr=1 ./your_application

  所有的环境变量均以GLOG_开头,我们推荐使用第二种,一来不必依赖于gflag,二来当参数很多时,可以写成脚本的形式,看起来更直观,GLOG支持的flag如下(只列出常用的,如果想看全部的,可以在源码的logging.cc文件下看到):

GLOG_logtostderr
  bool,默认为FALSE,将日志打印到标准错误,而不是日志文件
GLOG_alsologtostderr
  bool,默认为FALSE,将日志打印到日志文件,同时也打印到标准错误
GLOG_stderrthreshold
  int,默认为2(ERROR),大于等于这个级别的日志才打印到标准错误,当指定这个参数时,GLOG_alsologtostderr参数将会失效
GLOG_minloglevel
  int,默认为0(INFO), 小于这个日志级别的将不会打印
GLOG_log_dir
  string类型,指定日志输出目录,目录必须存在
GLOG_max_log_size
  int,指定日志文件最大size,超过会被切割,单位为MB
GLOG_stop_logging_if_full_disk
  bool,默认为FALSE,当磁盘满了之后不再打印日志
GLOG_v
  int,默认为0,指定GLOG_v=n时,对vlog(m),当m<=n时才会打印日志

  知道了这些参数之后,我们可以在脚本中指定这些变量,还是以test程序为例,test.sh如下:

#!/bin/sh
export GLOG_log_dir=log
export GLOG_minloglevel=1
export GLOG_stderrthreshold=1
export GLOG_v=3
export GLOG_max_log_size=1
./test

C++日志操作开源函数库之Google-glog【Caffe源代码静态库封装--------关键错误点解决必备参考资料】相关推荐

  1. C/C++库文件全了解(包含静态库、动态库,包含windows、linux,包含dll、lib、so)

    目录 C/C++库文件全了解 一. 前言 二. 名词解释 2.1. windows的静态库:xxx.lib 2.2. windows的动态库:xxx.dll 2.3. linux的动态库:libxxx ...

  2. iOS架构-C/C++lame库在Mac下编译通用静态库.a库(13)

    C/C++ 有很多成熟的库,还有很多特殊功能的库,有时候iOS 平台开发一些比较前沿或者冷门的功能时,iOS并没有提供解决方案,这时候就可以研究C/C++的一些库,为我们使用.但是在Xcode编译C/ ...

  3. iOS静态库SDK制作(包含第三方静态库)

    本文来自简书,原文地址:http://www.jianshu.com/p/155a3cfb765e 前言 以下所涉及的框架和库只针对iOS而言,不确保在其他平台也适用. 最近由于公司业务需要,要求封装 ...

  4. c语言将程序写为动态库,VS下生成C程序静态库(LIB)及动态库(DLL)的方法

    一.前言 工作中有时候因为分工合作的原因需要让别人调用自己写的代码去完成某项功能,但是又不想让别人看到具体的实现过程,只是提供一个API形式的接口供别人调用:又或者是其他的一些原因,有必要学习静态库及 ...

  5. 编译-C语言库FFTW支持iOS平台的静态库

    // 查看xcode 的版本 $:xcodebuild -version Xcode 10.2.1 Build version 10E1001 FFTW:傅立叶变换常用库–fftw FFTW官网:ht ...

  6. aix 的c库为什么都是静态库_关于AIX  libpthread.a 静态库

    关于AIX  libpthread.a 静态库 (2011-12-20 05:32:32) 标签: 杂谈 关于AIX libpthread.a 静态库有哪位兄弟知道怎么弄 到AIXlibpthread ...

  7. linux调用qt生成静态库文件下载,Centos7下编译openssl静态库与QT引用

    1.下载openssl版本:https://www.openssl.org/source/old/ 下载地址 2.我们下载版本为:openssl-1.0.2k 3.拷贝到Linux服务器任意目录 4. ...

  8. python调用so库 undefind symbol_内嵌Python import时undefined symbol错误及解决 | 学步园

    内嵌Python import时undefined symbol错误及解决 以下代码 #include#include#includeintmain(intargc,char*argv[]) ...{ ...

  9. 添加库路经 linux,linux下的静态库与动态库

    文件名形如 libxxx.so,其中so是 Shared Object 的缩写,即可以共享的目标文件. 生成动态库常用 gcc 命令: 举例: 编写头文件:ok.h 文件 #ifndef __OK_H ...

  10. linux 静态库 解包,libcurl编译linux静态库及使用总结(编译成功库下载)

    #-------------------------------------------------------------------------- #source file #源文件,自动找所有. ...

最新文章

  1. 【学习笔记】Android视图动画学习
  2. Cookie与Session的区别
  3. 图像处理之简单脸谱检测算法
  4. raptor五个数排序流程图_经典算法系列之:选择排序
  5. Jenkins 部署vue到服务器
  6. 斜齿轮受力计算:理论计算virtual.lab motion 仿真
  7. 在 vue/cli 中使用 Module Federation
  8. 集成mysql+tomcat+apache+Eclipse的绿色版开发环境
  9. oracle plsql创建表空间,Oracle在PLSQL Developer上创建表空间和用户脚本 - 龙卷风的日志 - 网易博客...
  10. 【POJ3461】Oulipo(字符串Hash)
  11. mac high sierra开机按option怎么只有一个磁盘_Mac降级重装必备 | MacOS 制作启动U盘及安装方法!...
  12. java链表实现多项式的运算
  13. word柱状图垂直轴数值设定_EXCEL中的图表坐标轴数值 如何设置
  14. ubuntu mate 18.04官网下载,烧录及安装 SSH VNC ROS MAVROS librealsense realsense-ros vision_to_mavros(我自己亲自弄的)
  15. Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六)
  16. 在线教育投融数据(2015-2020年)
  17. 循环辅助:continue和break
  18. opencv 旋转和平移的矩阵
  19. 时序数据库基本概念学习
  20. 机器阅读理解(Neural Machine Reading Comprehension)综述,相关方法及未来趋势

热门文章

  1. 软件视频会议系统 服务器要求,视频会议系统招标要求.docx
  2. codeforces NCPC2015 GYM 100781A Adjoin the Networks 圖的直徑
  3. chia矿池积点是什么-chia矿池接入的常见问题
  4. 仿苹果手机_有没有仿ios12备忘录便签软件?
  5. 形形色色的Linux 发行版代号都在这里
  6. thinkpad开机后无法进入系统怎么办?
  7. mysql在线检测文件是否损坏,mysql数据文件损坏后的修复方法
  8. 海龟编程计算机,第一个海龟程序
  9. 计算机网络吞吐量计算
  10. java接入支付宝api实现支付宝手机扫码登录