C++学习之道:glog

2024-06-10 10:58
文章标签 c++ 学习 之道 glog

本文主要是介绍C++学习之道:glog,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、安装配置

1、简介

  google 出的一个C++轻量级日志库,支持以下功能:

复制代码
◆ 参数设置,以命令行参数的方式设置标志参数来控制日志记录行为;
◆ 严重性分级,根据日志严重性分级记录日志;
◆ 可有条件地记录日志信息;
◆ 条件中止程序。丰富的条件判定宏,可预设程序终止条件;
◆ 异常信号处理。程序异常情况,可自定义异常处理过程;
◆ 支持debug功能;
◆ 自定义日志信息;
◆ 线程安全日志记录方式;
◆ 系统级日志记录;
◆ google perror风格日志信息;
◆ 精简日志字符串信息
复制代码

 

2、安装

  下载地址:https://code.google.com/p/google-glog/downloads/list

  解压安装:

tar zxvf glog-0.3.3.tar.gz && cd glog-0.3.3 && ./configure && make

  头文件目录为 /src/glog ,链接库为 .libs/libglog.{a,so}

  帮助文档为 doc/glog.html 或直接访问以下 URL: http://google-glog.googlecode.com/svn/trunk/doc/glog.html

 

3、简单 Demo 

#include <glog/logging.h>int main(int argc,char* argv[])
{LOG(INFO) << "Hello,GLOG!";
}

  链接时,需要 -lglog ,也可能会需要 -lunwind -lpthread (有一次遇到的,记不起来了,一般不需要)

  执行时,可使用 ./glogdemo 将日志输出到 stderr,可使用 valgrind 检测,未发现内存泄漏。

 

 

二、使用方法

1、错误级别

  GLOG 有四个错误级别,枚举如下:

复制代码
enum SeverityLevel
{google::INFO = 0,google::WARNING = 1,google::ERROR = 2,google::FATAL = 3,
};
复制代码

 

2、Flags 设置:

  在上面的简单 Demo 中,只能将日志输出到 stderr ,如果想将日志重定向到文件,需要:

google::InitGoogleLogging(argv[0]);
/*
GLOG代码
*/
google::ShutdownGoogleLogging();

  则默认运行会将日志输出到 /tmp 目录下(格式为 "<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>"),也可以使用设置临时环境变量的方式(给命令行参数加上 GLOG_ 前缀),如 GLOG_logtostderr=1 ./your_application 将日志输出到 stderr。

  另外,glog 使用了 gflags 库,如果已经安装好了 gflags 库(./configure && make && make install 然后再配置编译GLOG库)还可以通过 ./your_application --logtostderr=1 来指定运行参数,但需要在使用时加上如下代码:(详见 http://www.cnblogs.com/tianyajuanke/p/3467572.html)

google::ParseCommandLineFlags(&argc, &argv, true);
/*
GLOG代码
*/
google::ShutDownCommandLineFlags();

  但此方法会使 valgrind 检测有内存泄漏(截止 valgrind 3.9.0 依然如此),这是由于使用 gflags 库造成的。(即使不使用此方法,但只要在编译 glog 库之前安装好了 gflags 库,就会使 libglog.so 有内存泄漏,介意者可进入 gflags 目录 make uninstall 之后,再对 glog 进行 ./configure && make )。

  常用的运行参数如下:

复制代码
logtostderr (bool, default=false)    //是否将所有日志输出到 stderr,而非文件
alsologtostderr(bool,default=false)  //是否同时将日志输出到文件和stderr
minloglevel (int, default=google::INFO)  //限制输出到 stderr 的部分信息,包括此错误级别和更高错误级别的日志信息 
stderrthreshold (int, default=google::ERROR)  //除了将日志输出到文件之外,还将此错误级别和更高错误级别的日志同时输出到 stderr,这个只能使用 -stderrthreshold=1 或代码中设置,而不能使用环境变量的形式。(这个参数可以替代上面两个参数)
colorlogtostderr(bool, default=false)  //将输出到 stderr 上的错误日志显示相应的颜色 
v (int, default=0)  //只记录此错误级别和更高错误级别的 VLOG 日志信息
log_dir (string, default="")  //设置日志文件输出目录 
v (int, default=0)  //只有当自定义日志(VLOG)级别值小于此值时,才进行输出,默认为0(注:自定义日志的优先级与GLOG内置日志优级相反,值越小优先级越高!!!)。
vmodule (string, default="")  //分文件(不包括文件名后缀,支持通配符)设置自定义日志的可输出级别,如:GLOG_vmodule=server=2,client=3 表示文件名为server.* 的只输出小于 2 的日志,文件名为 client.* 的只输出小于 3 的日志。如果同时使用 GLOG_v 选项,将覆盖 GLOG_v 选项。
复制代码

  更多运行参数见 logging.cc 中的 DEFINE_ 开头的定义。

  运行参数设置的第三种方法是,可以在代码里通过加上 FLAGS_ 前缀来设置,如:

FLAGS_stderrthreshold=google::INFO;
FLAGS_colorlogtostderr=true;

 

3、条件输出:

LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";   //当条件满足时输出日志
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";  //google::COUNTER 记录该语句被执行次数,从1开始,在第一次运行输出日志之后,每隔 10 次再输出一次日志信息
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER << "th big cookie";  //上述两者的结合,不过要注意,是先每隔 10 次去判断条件是否满足,如果滞则输出日志;而不是当满足某条件的情况下,每隔 10 次输出一次日志信息。
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";  //当此语句执行的前 20 次都输出日志,然后不再输出

  演示代码如下:

复制代码
#include <glog/logging.h>int main(int argc,char* argv[])
{google::InitGoogleLogging(argv[0]);FLAGS_stderrthreshold=google::INFO;FLAGS_colorlogtostderr=true;for(int i = 1; i <= 100;i++){LOG_IF(INFO,i==100)<<"LOG_IF(INFO,i==100)  google::COUNTER="<<google::COUNTER<<"  i="<<i;LOG_EVERY_N(INFO,10)<<"LOG_EVERY_N(INFO,10)  google::COUNTER="<<google::COUNTER<<"  i="<<i;LOG_IF_EVERY_N(WARNING,(i>50),10)<<"LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER="<<google::COUNTER<<"  i="<<i;LOG_FIRST_N(ERROR,5)<<"LOG_FIRST_N(INFO,5)  google::COUNTER="<<google::COUNTER<<"  i="<<i;}google::ShutdownGoogleLogging();
}
复制代码

   输出结果如下:

复制代码
I1210 13:23:20.059790  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=1  i=1
E1210 13:23:20.060670  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=1  i=1
E1210 13:23:20.061272  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=2  i=2
E1210 13:23:20.061337  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=3  i=3
E1210 13:23:20.061393  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=4  i=4
E1210 13:23:20.061450  6322 test01.cpp:13] LOG_FIRST_N(INFO,5)  google::COUNTER=5  i=5
I1210 13:23:20.061506  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=11  i=11
I1210 13:23:20.061529  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=21  i=21
I1210 13:23:20.061553  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=31  i=31
I1210 13:23:20.061575  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=41  i=41
I1210 13:23:20.061599  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=51  i=51
W1210 13:23:20.061621  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=51  i=51
I1210 13:23:20.061667  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=61  i=61
W1210 13:23:20.061691  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=61  i=61
I1210 13:23:20.061738  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=71  i=71
W1210 13:23:20.061761  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=71  i=71
I1210 13:23:20.061807  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=81  i=81
W1210 13:23:20.061831  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=81  i=81
I1210 13:23:20.061877  6322 test01.cpp:11] LOG_EVERY_N(INFO,10)  google::COUNTER=91  i=91
W1210 13:23:20.061902  6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10)  google::COUNTER=91  i=91
I1210 13:23:20.062140  6322 test01.cpp:10] LOG_IF(INFO,i==100)  google::COUNTER=0  i=100
复制代码

 

4、日志类型

复制代码
LOG    //内置日志
VLOG    //自定义日志
DLOG    //DEBUG模式可输出的日志
DVLOG    //DEBUG模式可输出的自定义日志
SYSLOG    //系统日志,同时通过 syslog() 函数写入到 /var/log/message 文件
PLOG    //perror风格日志,设置errno状态并输出到日志中
RAW_LOG        //线程安全的日志,需要#include <glog/raw_logging.h>
复制代码

  前六种的日志使用方法完全相同(包括条件日志输出),而 RAW_LOG 使用方法比较特殊,且不支持条件日志输出,另外不接受  colorlogtostderr 的颜色设置。自定义日志也不接受 colorlogtostderr 的颜色设置,另外其日志严重级别也为自定义数字,且与默认日志严重级别相反,数字越小严重级别越高。如:

复制代码
 1 #include <glog/logging.h>
 2 #include <glog/raw_logging.h>
 3 
 4 class GLogHelper
 5 {
 6 public:
 7     GLogHelper(char* program)
 8     {
 9         google::InitGoogleLogging(program);
10         FLAGS_stderrthreshold=google::INFO;
11         FLAGS_colorlogtostderr=true;
12         FLAGS_v = 3;
13     }
14     ~GLogHelper()
15     {
16         google::ShutdownGoogleLogging();
17     }
18 };
19 
20 int main(int argc,char* argv[])
21 {
22     GLogHelper gh(argv[0]);
23     LOG(ERROR)<<"LOG";
24     VLOG(3)<<"VLOG";
25     DLOG(ERROR)<<"DLOG";
26     DVLOG(3)<<"DVLOG";
27     SYSLOG(ERROR)<<"SYSLOG";
28     PLOG(ERROR)<<"PLOG";
29     RAW_LOG(ERROR,"RAW_LOG");
30 }
复制代码

  输出结果如下:

复制代码
E1211 03:04:22.718116 13083 test01.cpp:23] LOG
I1211 03:04:22.719225 13083 test01.cpp:24] VLOG
E1211 03:04:22.719297 13083 test01.cpp:25] DLOG
I1211 03:04:22.719365 13083 test01.cpp:26] DVLOG
E1211 03:04:22.719391 13083 test01.cpp:27] SYSLOG
E1211 03:04:22.719650 13083 test01.cpp:28] PLOG: Success [0]
E1211 03:04:22.719650 13083 test01.cpp:29] RAW: RAW_LOG
复制代码

 

5、CHECK 宏

  当通过该宏指定的条件不成立的时候,程序会中止,并且记录对应的日志信息。功能类似于ASSERT,区别是 CHECK 宏不受 NDEBUG 约束,在 release 版中同样有效。

  目前这个功能我暂时不需要,就不实践了,简单介绍下,如:

CHECK(port == 80)<<"HTTP port 80 is not exit.";

  其它还有:CHECK_EQ、 CHECK_NOTNULL、CHECK_STREQ、CHECK_DOUBLE_EQ 等判断数字、空指针,字符串,浮点数的 CHECK 宏,需要使用时可以搜索 glog/logging.h 文件中以 CHECK_ 开头的宏定义。

  此外,类似的,还有 PCHECK 和 RAW_CHECK 版本,使用方法类似,只是 RAW_CHECK 使用方法特殊,形如 RAW_CHECK(i<3,"RAW_CHECK");

 

6、core dumped 

  通过 google::InstallFailureSignalHandler(); 即可注册,将 core dumped 信息输出到 stderr,如:

复制代码
#include <glog/logging.h>
#include <string>
#include <fstream>

//将信息输出到单独的文件和 LOG(ERROR)
void SignalHandle(const char* data, int size)
{std::ofstream fs("glog_dump.log",std::ios::app);std::string str = std::string(data,size);fs<<str;fs.close();LOG(ERROR)<<str;
}class GLogHelper
{
public:GLogHelper(char* program){google::InitGoogleLogging(program);FLAGS_colorlogtostderr=true;google::InstallFailureSignalHandler();//默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,可以通过下面的方法自定义输出方式:google::InstallFailureWriter(&SignalHandle);}~GLogHelper(){google::ShutdownGoogleLogging();}
};void fun()
{int* pi = new int;delete pi;pi = 0;int j = *pi;
}int main(int argc,char* argv[])
{GLogHelper gh(argv[0]);fun();
}
复制代码

  输出的错误报告如下,可定位错误于 fun() 函数内:

复制代码

E1211 06:07:04.787719 15444 test01.cpp:11] *** Aborted at 1386742024 (unix time) try "date -d @1386742024" if you are using GNU date ***
E1211 06:07:04.789120 15444 test01.cpp:11] PC: @           0x401227 fun()
E1211 06:07:04.789481 15444 test01.cpp:11] *** SIGSEGV (@0x0) received by PID 15444 (TID 0x7f03ce478720) from PID 0; stack trace: ***
E1211 06:07:04.791168 15444 test01.cpp:11]     @     0x7f03cd505960 (unknown)
E1211 06:07:04.791453 15444 test01.cpp:11]     @           0x401227 fun()
E1211 06:07:04.791712 15444 test01.cpp:11]     @           0x40125b main
E1211 06:07:04.792908 15444 test01.cpp:11]     @     0x7f03cd4f1cdd __libc_start_main
E1211 06:07:04.793227 15444 test01.cpp:11]     @           0x400fc9 (unknown)
段错误 (core dumped)

复制代码

  如果不使用  google::InstallFailureSignalHandler();  则只会输出 “段错误” 三个字,难于排查。

 

7、其它常用配置

google::SetLogDestination(google::ERROR,"log/prefix_");   //第一个参数为日志级别,第二个参数表示输出目录及日志文件名前缀。
google::SetStderrLogging(google::INFO);   //输出到标准输出的时候大于 INFO 级别的都输出;等同于 FLAGS_stderrthreshold=google::INFO;
FLAGS_logbufsecs =0;  //实时输出日志
FLAGS_max_log_size =100;  //最大日志大小(MB)
#define GOOGLE_STRIP_LOG 3    // 小于此级别的日志语句将在编译时清除,以减小编译后的文件大小,必须放在 #include 前面才有效。

 

8、日志文件说明

  如果可执行文件名为 "test",则将日志输出到文件后,还会生成 test.ERROR,test.WARNING,test.INFO 三个链接文件,分别链接到对应级别的日志文件。如果日志输出超过 FLAGS_max_log_size 设置的大小,则会分为多个文件存储,链接文件就会指向其中最新的对应级别的日志文件。所以当日志文件较多时,查看链接文件来查看最新日志挺方便的。

 

三、实用封装

  GLogHelper.h 如下:

复制代码
#include <glog/logging.h>
#include <glog/raw_logging.h>//将信息输出到单独的文件和 LOG(ERROR)
void SignalHandle(const char* data, int size);class GLogHelper
{
public://GLOG配置:GLogHelper(char* program);//GLOG内存清理:~GLogHelper();
};
复制代码

  GlogHelper.cpp 如下:

复制代码
#include <stdlib.h>
#include "GLogHelper.h"//配置输出日志的目录:
#define LOGDIR "log"
#define MKDIR "mkdir -p "LOGDIR//将信息输出到单独的文件和 LOG(ERROR)
void SignalHandle(const char* data, int size)
{std::string str = std::string(data,size);/*std::ofstream fs("glog_dump.log",std::ios::app);fs<<str;fs.close();*/LOG(ERROR)<<str;//也可以直接在这里发送邮件或短信通知,不过这个方法是被回调多次的(每次回调只输出一行错误信息,所以如上面的记录到文件,也需要>以追加模式方可),所以这里发邮件或短信不是很适合,不过倒是可以调用一个 SHELL 或 PYTHON 脚本,而此脚本会先 sleep 3秒左右,然后将错
误信息通过邮件或短信发送出去,这样就不需要监控脚本定时高频率执行,浪费效率了。
}//GLOG配置:
GLogHelper::GLogHelper(char* program)
{system(MKDIR);google::InitGoogleLogging(program);google::SetStderrLogging(google::INFO); //设置级别高于 google::INFO 的日志同时输出到屏幕FLAGS_colorlogtostderr=true;    //设置输出到屏幕的日志显示相应颜色//google::SetLogDestination(google::ERROR,"log/error_");    //设置 google::ERROR 级别的日志存储路径和文件名前缀google::SetLogDestination(google::INFO,LOGDIR"/INFO_"); //设置 google::INFO 级别的日志存储路径和文件名前缀google::SetLogDestination(google::WARNING,LOGDIR"/WARNING_");   //设置 google::WARNING 级别的日志存储路径和文件名前缀google::SetLogDestination(google::ERROR,LOGDIR"/ERROR_");   //设置 google::ERROR 级别的日志存储路径和文件名前缀FLAGS_logbufsecs =0;        //缓冲日志输出,默认为30秒,此处改为立即输出FLAGS_max_log_size =100;  //最大日志大小为 100MBFLAGS_stop_logging_if_full_disk = true;     //当磁盘被写满时,停止日志输出google::SetLogFilenameExtension("91_");     //设置文件名扩展,如平台?或其它需要区分的信息google::InstallFailureSignalHandler();      //捕捉 core dumpedgoogle::InstallFailureWriter(&SignalHandle);    //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,可以通过下面的方法自定义输出>方式:
}
//GLOG内存清理:
GLogHelper::~GLogHelper()
{google::ShutdownGoogleLogging();
}
复制代码

  测试文件 test.cpp 如下:

复制代码
#include "GLogHelper.h"int main(int argc,char* argv[])
{//要使用 GLOG ,只需要在 main 函数开始处添加这句即可GLogHelper gh(argv[0]);LOG(INFO)<<"INFO";LOG(ERROR)<<"ERROR";
}
复制代码

 

这篇关于C++学习之道:glog的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1047978

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]