gflags和glog - artinfo1982/demos GitHub Wiki

简介

gflags是google的开源命令行参数解析器,glog是google的开源日志系统。
在实际项目中,二者一般结合使用。

安装

1)源码编译gflags和glog

git clone https://github.com/gflags/gflags
# 进入gflags文件夹
cmake .
make -j 8
sudo make install
git clone https://github.com/google/glog
sudo apt install autoconf automake libtool
# 进入glog文件夹
./autogen.sh
./configure
make -j 8
sudo make install
# 安装完,默认头文件会在/usr/local/include下,lib文件在/usr/local/lib下

2)ubuntu下安装glog和gflags

sudo apt install libgflags-dev libgoogle-glog-dev

gflags的使用

1)简单使用

#include <iostream>
#include <gflags/gflags.h>

// 定义参数变量的默认值,如果命令行不带任何参数,将使用默认值
DEFINE_string(host, "127.0.0.1", "host");
DEFINE_int32(port, 12306, "port");

int main(int argc, char **argv)
{
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::cout << "host: " << FLAGS_host << ", port: " << FLAGS_port << std::endl;
  return 0;
}

编译:

g++ test.cpp -o test -lgflags

运行:

# 不带参数(使用默认值)
./test
# 带参数(使用输入的参数值)
./test -host "1.1.1.1" -port 2222
# 一个横杠和两个横杠的效果一样
./test --host "1.1.1.1" --port 2222

DEFINE_XXX()的第三个参数是注释,内容不限,可以写多个"""""",例如:

DEFINE_string(host, "127.0.0.1", "host""aaa""bbb");
DEFINE_int32(port, 12306, "port""111""222");

可以像使用一般的变量一样,使用gflags定义的变量,例如:

FLAGS_port++;
std::cout << "new port: " << FLAGS_port << std::endl;

2)支持的类型

DEFINE_bool
DEFINE_int32
DEFINE_int64
DEFINE_uint64
DEFINE_double
DEFINE_string

3)多文件定义、访问gflags变量

建议在.cc或者.cpp文件中定义gflags变量,DEFINE_string(a, "aa", "bb"),然后在对应的.h或者.hpp文件中声明该变量DECLARE_string(a),然后在其他需要使用该变量的.c或者.cpp文件中#include "xx.h"。
flags.h

#ifndef __FLAGS_H__
#define __FLAGS_H__

#include <gflags/gflags.h>

DECLARE_string(a);

#endif

flags.cpp

#include "flags.h"

DEFINE_string(a, "aa", "bb");

test.cpp

#include <iostream>
#include "flags.h"

int main(int argc, char **argv)
{
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::cout << "a: " << FLAGS_a << std::endl;
  return 0;
}

编译:

g++ test.cpp flags.h flags.cpp -o test -lgflags

运行:

./test -a "123"

4)参数校验

我们希望在main函数刚开始执行时,就对参数进行检查,定义static检查函数,在main刚开始运行时,就注册检查函数。例如:

#include <iostream>
#include <gflags/gflags.h>

static bool ValidatePort(const char* flagname, int32_t value)
{
  if (value > 1024 && value < 65536)
    return true;
  else
    return false;
}

DEFINE_int32(port, 10000, "port");

static const bool port_checker = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);

int main(int argc, char **argv)
{
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::cout << "port: " << FLAGS_port << std::endl;
  return 0;
}

5)过多的参数,需要使用文件flagfile

先定义一个名为test.flags的文件,里面的内容:

--host=10.123.14.11
--port=23333

再定义一个名为test.cpp的文件:

#include <iostream>
#include <gflags/gflags.h>

// 定义参数变量的默认值,如果命令行不带任何参数,将使用默认值
DEFINE_string(host, "1.1.1.1", "host");
DEFINE_int32(port, 10000, "port");

int main(int argc, char **argv)
{
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  std::cout << "host: " << FLAGS_host << ", port: " << FLAGS_port << std::endl;
  return 0;
}

编译:

g++ test.cpp -o test -lgflags

运行:

./test --flagfile test.flags

输出:

host: 10.123.14.11, port: 23333

6)定制自己的version和help信息

gflags提供如下两个函数,定制自己的版本信息和帮助信息

google::SetVersionString(const std::string& version);
google::SetUsageMessage(const std::string& usage);

分别使用如下两个函数访问

google::VersionString();
google::ProgramUsage();

注意点:google::SetVersionString、google::SetUsageMessage,必须在gflags::ParseCommandLineFlags之前执行。

glog的使用

1)简单使用

test.cpp

#include <glog/logging.h>

int main(int argc, char **argv)
{
  google::InitGoogleLogging(argv[0]);
  LOG(INFO) << "INFO";
  google::ShutdownGoogleLogging();
  return 0;
}

编译:

g++ test.cpp -o test -lglog

不指定的话,log默认重定向到/tmp/...log..-.
例如/tmp/test.linux.cd.log.ERROR.20190312-144402.1504

2)日志级别

INFO
WARNING
ERROR
FATAL

默认,在执行LOG(FATAL)之后,程序会生成一个core文件,终止程序。例如:

F0312 15:49:40.842653 1595 test.cpp:13] FATAL
*** Check failure stack trace: ***
  @ 0x7f51b5e460cd google::LogMessage::Fail()
  @ 0x7f51b5e47f33 google::LogMessage::SendToLog()
  @ 0x7f51b5e45c28 google::LogMessage::Flush()
  @ 0x7f51b5e48999 google::LogMessageFatal::~LogMessageFatal()
  @ 0x56276e26edd7 (unknown)
  @ 0x7f51b54c9b97 __libc_start_main
  @ 0x56276e26eb8a (unknown)
Aborted (core dumped)

如果不想生成core文件,而是采用自定义的错误处理函数,下面是例子:

#include <gflags/gflags.h>
#include <glog/logging.h>

void fatalHandler()
{
  exit(1);
}

int main(int argc, char **argv)
{
  ::google::InitGoogleLogging(argv[0]);
  ::google::InstallFailureFunction(&fatalHandler);
  LOG(FATAL) << "FATAL";
  return 0;
}

3)设置flag以及CHECK宏

#include <gflags/gflags.h>
#include <glog/logging.h>

int main(int argc, char **argv)
{
  FLAGS_alsologtostderr = 1; // 输出到日志文件的同时输出到控制台
  FLAGS_stderrthreshold = 2; // 控制台显示日志的阈值,0-3,对应INFO-FATAL
  FLAGS_log_dir = "/home/cd/temp/log"; // 日志文件的目录,需要确保存在
  FLAGS_colorlogtostderr = 1; // 是否彩色显示日志(根据级别)
  ::google::InitGoogleLogging(argv[0]);
  LOG(INFO) << "INFO";
  LOG(WARNING) << "WARNING";
  LOG(ERROR) << "ERROR";
  int a = 1;
  char *b = nullptr;
  CHECK(a == 1) << "a is not 1";
  CHECK_EQ(a, 1) << "a is not 1";
  CHECK_NOTNULL(b);
  return 0;
}

如果CHECK_NOTNULL检查失败,会生成一个core文件,上述代码运行的输出:

I0312 17:00:22.295601 1841 test.cpp:11] INFO
W0312 17:00:22.295732 1841 test.cpp:12] WARNING
E0312 17:00:22.295792 1841 test.cpp:13] ERROR
F0312 17:00:22.295841 1841 test.cpp:18] Check failed: 'b' Must be non NULL
*** Check failure stack trace: ***
  @ 0x7f51b5e460cd google::LogMessage::Fail()
  @ 0x7f51b5e47f33 google::LogMessage::SendToLog()
  @ 0x7f51b5e45c28 google::LogMessage::Flush()
  @ 0x7f51b5e48999 google::LogMessageFatal::~LogMessageFatal()
  @ 0x56276e26edd7 (unknown)
  @ 0x7f51b54c9b97 __libc_start_main
  @ 0x56276e26eb8a (unknown)
Aborted (core dumped)

4)发生严重错误,不想生成core,但需要看到堆栈信息

google::InstallFailureSignalHandler(),会在出现严重错误时,将堆栈信息打印在控制台。
可以使用google::InstallFailureWriter(&dumper)来重定向堆栈信息。

⚠️ **GitHub.com Fallback** ⚠️