百度apollo - Apollo代码解析:3. 命令行参数传递google gflags

本文详细介绍了如何在Apollo项目中使用google的gflags库进行命令行参数传递。从安装gflags、通过cmake和Bazel构建,到在C++代码中定义、访问和验证命令行参数,以及自定义帮助和版本信息,文章提供了完整的步骤和示例。

简介

  • 在百度Apollo中gflag被广泛的应用在各种全局变量中,例如节点名,变量名,各种状态标志中。
  • gflags 是google开源的一套命令行参数解析工具,比 getopt 功能更加强大,使用起来更加方便。
  • 什么是 命令行参数解析工具 呢? 这里拿python做例子,例如:python test.py cmd1 cmd2
    其中cmd1cmd2 就是命令行参数,gflags就是用来解析cmd1 cmd2 到程序中的。
  • ps: 在cpp中命令行参数就是字符串

1. 安装 gflags

下载地址:git clone https://github.com/gflags/gflags.git

build和安装教程在INSTALL文件中有, 该教程支持pkg-config, CMake, 以及 Bazel.

1.1 cmake

如果gflags不是安装在默认路径下,则环境变量gflags_DIR 需要是 <prefix>/lib/cmake/gflags 该文件夹下需要是有 gflags-config.cmake 的文件。

如果gflags安装在默认路径下CMake 可以通过 find_package(gflags REQUIRED)

或者添加单线程静态库:
find_package(gflags COMPONENTS nothreads_static)
自动找到 gflags 。

添加dependency和execute
add_executable(foo main.cc)
target_link_libraries(foo gflags)

1.2 Bazel

WORKSPACE中添加以下语句

git_repository(
    name   = "com_github_gflags_gflags",
    commit = "<INSERT COMMIT SHA HERE>",
    remote = "https://github.com/gflags/gflags.git",
)

bind(
    name = "gflags",
    actual = "@com_github_gflags_gflags//:gflags",
)

bind(
    name = "gflags_nothreads",
    actual = "@com_github_gflags_gflags//:gflags_nothreads",
)

ps
gflags_nothreads 强制单线程
gflags 多线程

然后添加到BUILD中:

cc_binary(
    name = "foo",
    srcs = ["main.cc"],
    deps = ["//external:gflags"],
)

2. 使用 gflags

2.1. 首先需要#include "gflags.h"
#include <gflags/gflags.h>
2.2. 宏定义

将需要的命令行参数使用gflags的来定义,例如:DEFINE_xxxxx(变量名,默认值,help-string) 定义在文件当中,注意:是全局的, 例如Apollo中的FLAGS_control_node_name就是一个全局的一个string。gflags支持以下类型:

DEFINE_bool: boolean
DEFINE_int32: 32-bit integer
DEFINE_int64: 64-bit integer
DEFINE_uint64: unsigned 64-bit integer
DEFINE_double: double
DEFINE_string: C++ string
2.3. main函数添加

在main函数中开始的地方加入,以下这句话:

google::ParseCommandLineFlags(&argc, &argv, true);
//如果设为true,则该函数处理完成后,argv中只保留argv[0],argc会被设置为1。
//如果为false,则argv和argc会被保留,但是注意函数会调整argv中的顺序。
2.4 调用

在后续代码中使用FLAGS_变量名访问对应的命令行参数方法如下:

printf("%s", FLAGS_mystr);
2.5 测试

在编译成可执行文件之后,使用:./exe --参数1=值1 --参数2=值2 ... 来为这些命令行参数赋值。

./mycmd --var1="test" --var2=3.141592654 --var3=32767 --mybool1=true --mybool2 --nomybool3

3. gflags进阶使用

3.1. 在其他文件中使用定义的flags变量
  • 有些时候需要在main之外的文件使用定义的flags变量,这时候可以使用宏定义DECLARE_xxx(变量名)声明一下(就和c++中全局变量的使用是一样的,extern一下一样)
DECLARE_bool: boolean
DECLARE_int32: 32-bit integer
DECLARE_int64: 64-bit integer
DECLARE_uint64: unsigned 64-bit integer
DECLARE_double: double
DECLARE_string: C++ string

在对应的.h文件中进行DECLARE_xxx声明,需要使用的文件直接include就行了。
检验输入参数是否合法:gflags库支持定制自己的输入参数检查的函数,如下:

static bool ValidatePort(const char* flagname, int32 value) {
   if (value > 0 && value < 32768)   // value is ok
     return true;
   printf("Invalid value for --%s: %d\n", flagname, (int)value);
   return false;
}
DEFINE_int32(port, 0, "What port to listen on");
static const bool port_dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
3.2 判断flags变量是否被用户使用

在gflags.h中,还定义了一些平常用不到的函数和结构体。这里举一个例子,判断参数port有没有被用户设定过

    google::CommandLineFlagInfo info;
    if(GetCommandLineFlagInfo("port" ,&info) && info.is_default) {
        FLAGS_port = 27015;
    }
3.3 定制你自己的help信息与version信息
  • version信息:使用google::SetVersionString设定,使用google::VersionString访问
  • help信息:使用google::SetUsageMessage设定,使用google::ProgramUsage访问
  • 注意:google::SetUsageMessagegoogle::SetVersionString这两个函数的调用必须google::ParseCommandLineFlags之前执行
Apollo 配置中心在配置更新时会通过 `AutoUpdateConfigChangeListener` 监听配置的变化,并在检测到变化后自动更新相关的 Bean 属性值。通过日志信息可以分析出具体的配置更新行为和更新结果。 ### 日志信息分析 1. **日志结构解析**: - 日志条目通常包含时间戳、日志级别、线程名称、日志内容等信息。 - 示例日志: ``` 2025-07-02 12:06:21.197 INFO 68185 --- [Apollo-Config-1] c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: val, key: apollo.value, beanName: scopedTarget.apollo, field: com.csh.springcloud.apolloclient.controller.ApolloConfigController.apolloValue ``` 该日志表明 `AutoUpdateConfigChangeListener` 成功更新了配置值,新的值为 `val`,对应的键为 `apollo.value`,更新的 Bean 名称为 `scopedTarget.apollo`,字段为 `com.csh.springcloud.apolloclient.controller.ApolloConfigController.apolloValue`。 2. **配置更新过程**: -Apollo 配置发生变化时,`AutoUpdateConfigChangeListener` 会接收到 `ConfigChangeEvent` 事件。 - 在 `onChange` 方法中,系统会根据变更的配置键值更新对应的 Bean 属性。 - 更新成功后,会在日志中记录更新的详细信息,包括新值、键名、Bean 名称和字段名[^1]。 3. **热更新验证**: - 通过日志可以确认热更新是否生效。 - 例如,以下日志表明 `mysql.password` 和 `mysql.username` 的配置值成功更新为 `root123`: ``` c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.password, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlPassword c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: root123, key: mysql.username, beanName: configProperties, field: com.example.config.ConfigProperties.mysqlUsername ``` 4. **日志中的版本信息**: - 日志中提到的 Apollo 版本为 1.4(公司内部二次开发版),基于此版本的行为可能会与开源版本(如 1.9)有所不同。 - 特别是 `AutoUpdateConfigChangeListener` 的实现逻辑可能因版本差异而略有不同[^4]。 5. **日志输出的 Bean 更新信息**: - 日志详细记录了每个配置项的更新情况,包括更新前后的值。 - 示例: ``` 2025-07-02 12:06:21.193 INFO 68185 --- [Apollo-Config-2] c.c.s.a.r.SpringBootApolloRefreshConfig : apollo value before refresh -1449272902 defaultValue 2025-07-02 12:06:21.204 INFO 68185 --- [Apollo-Config-2] c.c.s.a.r.SpringBootApolloRefreshConfig : apollo value after refresh -1449272902 val ``` 该日志表明配置值从 `defaultValue` 更新为 `val`。 ### 日志分析建议 - **关注关键字段**:查看日志中的 `key` 和 `new value` 字段,以确认哪些配置项发生了变化。 - **检查更新时间**:通过时间戳可以确定配置更新的时间点。 - **验证 Bean 更新**:检查 `beanName` 和 `field` 字段,确保配置更新作用在正确的 Bean 和字段上。 - **对比更新前后值**:如果日志中记录了更新前后的值,可以通过对比确认热更新是否按预期生效。 ### 示例日志分析代码 如果需要通过代码解析日志文件,可以使用以下 Python 示例代码: ```python import re def parse_apollo_log(log_line): # 正则表达式匹配日志格式 pattern = r&#39;(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) INFO \d+ --- $([A-Za-z0-9\-]+)$: (.+)&#39; match = re.match(pattern, log_line) if match: timestamp, thread, message = match.groups() print(f"Timestamp: {timestamp}, Thread: {thread}, Message: {message}") else: print("Log line does not match expected format.") # 示例日志行 log_line = &#39;2025-07-02 12:06:21.197 INFO 68185 --- [Apollo-Config-1] c.f.a.s.p.AutoUpdateConfigChangeListener : Auto update apollo changed value successfully, new value: val, key: apollo.value, beanName: scopedTarget.apollo, field: com.csh.springcloud.apolloclient.controller.ApolloConfigController.apolloValue&#39; parse_apollo_log(log_line) ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值