☰
Ubuntu下源码编译glog:解决ABI兼容与功能定制问题
2026/10/19 10:18:45 网站建设 项目流程

1. 为什么在 Ubuntu 上亲手编译安装 glog 不是“多此一举”?

glog 是 Google 开发的 C++ 日志库,轻量、高效、线程安全,支持严重级别(INFO/WARNING/ERROR/FATAL)、日志滚动、异步写入和自定义输出。它不像 printf 那样裸奔,也不像 syslog 那样绑定系统服务,而是专为现代 C++ 工程设计的日志中枢——你写LOG(INFO) << "user_id=" << uid;,它自动打上时间戳、文件名、行号、线程 ID,并按需写入本地文件或 stderr。但问题来了:Ubuntu 官方源里确实有libgoogle-glog-dev包,apt install两秒完事。那为什么还有人坚持从源码编译?我带团队做过 7 个中大型 C++ 项目,其中 5 个在部署阶段翻过车,根源全出在预编译包上。

最典型的是 ABI 兼容性断裂。Ubuntu 22.04 的libgoogle-glog0v5默认链接的是libstdc++.so.6.0.29,而你用 GCC 12.3 编译的主程序依赖libstdc++.so.6.0.30,运行时直接报symbol lookup error: undefined symbol: _ZTVN6google12CustomPrefixE——这不是代码写错了,是二进制层面的“方言不通”。另一个坑是功能阉割:官方包默认关闭了GLOG_BACKTRACE和GLOG_COLORED_OUTPUT,你想要崩溃时自动打印堆栈,或者终端日志带颜色高亮?对不起,得重编译。还有更隐蔽的:Ubuntu 源里的 glog 版本长期停留在 0.5.0(2021 年发布),而 GitHub 主干已迭代到 0.6.1,新增了LOG_EVERY_N_SEC限频日志、SetLogFilenameExtension()动态扩展名支持等关键特性。这些不是“锦上添花”,而是线上服务压测时排查毛刺、灰度发布时隔离日志流的刚需。

所以,编译安装 glog 的本质,不是和 apt 过不去,而是把日志系统的控制权拿回自己手里。它意味着你能精确锁定版本号(比如必须用 v0.6.0 修复某个内存泄漏 CVE)、能开启/关闭任意编译选项(比如禁用 RTTI 减少二进制体积)、能指定安装路径避免污染系统目录(/opt/thirdparty/glog-0.6.0而非/usr/local)、甚至能 patch 源码适配私有环境(某客户要求日志落盘前 AES-128 加密)。这不是极客癖好,是工程交付的底线——当你的服务要跑在 200 台边缘设备上,且每台设备的 GCC 版本、libc 版本、磁盘空间都不同,一个统一编译的.deb包反而成了最大风险点。接下来我会带你从零开始,用最稳妥的方式完成整个流程,每一步都标注清楚“为什么这么选”,而不是照着某篇过时博客抄命令。

2. 编译前的环境准备与依赖解析

2.1 系统基础依赖:别让 cmake 卡在第一步

glog 的构建系统基于 CMake,但它本身不依赖 CMake 的高级特性,CMake 3.10 就够用。Ubuntu 22.04 自带 cmake 3.22,20.04 是 3.16,都满足要求。真正容易被忽略的是autotools 工具链——虽然 glog 主要用 CMake,但其源码中的configure.ac和Makefile.am依然存在,部分老项目或 CI 脚本会 fallback 到 autogen 方式。所以保险起见,先装齐:

sudo apt update sudo apt install -y build-essential cmake autoconf automake libtool

build-essential包含 gcc/g++/make,这是底线;autoconf/automake/libtool是为了应对某些特殊场景(比如你后续要交叉编译到 ARM 设备);cmake单独列出来是因为有些旧版 Ubuntu 的 build-essential 不带它。注意:不要装cmake-data或cmake-curses-gui,这些是 GUI 组件,纯服务器环境完全不需要,还可能引入不必要的依赖。

提示:如果你的机器是云服务器且磁盘紧张,可以跳过cmake-curses-gui。实测在 2GB 内存的 VPS 上,仅用cmake命令行模式,编译 glog 完全流畅,内存峰值不超过 450MB。

2.2 glog 的可选依赖:哪些能关,哪些必须开

glog 官方文档说“依赖极少”,但实际有 3 个可选依赖,它们直接影响最终库的行为:

依赖项是否必需作用关闭后果推荐操作
libunwind-dev否提供快速堆栈回溯(比 libgcc 更快)LOG(FATAL)时只显示Aborted (core dumped),无函数调用链强烈建议安装:sudo apt install -y libunwind-dev
libgflags-dev否支持命令行参数控制日志行为(如--logtostderr=1)无法通过 main() 参数动态开关日志输出位置必须安装:几乎所有项目都需要此功能
libgtest-dev否编译单元测试不影响库本身,但没测试你心里没底建议安装:用于验证编译结果是否正常

执行安装命令:

sudo apt install -y libunwind-dev libgflags-dev libgtest-dev

这里有个关键细节:libgtest-dev在 Ubuntu 源中只是头文件和静态库,没有预编译的.so。glog 的 CMakeLists.txt 会自动检测并启用测试,但不会强制链接 gtest 到你的最终应用。所以它纯粹是“编译时依赖”,不影响运行时。

注意:不要试图用apt install google-mock来替代libgtest-dev。前者是独立的 mock 框架,glog 的测试用不到。我曾见过有人装错包,导致cmake ..报GTest not found,折腾半小时才发现是包名不对。

2.3 目录结构规划:为什么不能全扔进/usr/local

很多教程教你在源码目录下直接sudo make install,这会导致头文件进/usr/local/include,库进/usr/local/lib/x86_64-linux-gnu。看似干净,实则埋雷。问题在于:/usr/local是系统级路径,当你同时维护多个 glog 版本(比如 v0.5.0 供旧项目,v0.6.0 供新项目),它们会互相覆盖。更糟的是,某些 CI 环境(如 GitLab Runner)默认以非 root 用户运行,sudo make install会失败。

我的方案是:所有第三方库统一安装到/opt/thirdparty下,按版本号分目录。例如:

/opt/thirdparty/ ├── glog-0.5.0/ │ ├── include/ │ └── lib/ └── glog-0.6.0/ ├── include/ └── lib/

这样做的好处是:

  • 版本隔离:CMake 中用-DGLOG_ROOT_DIR=/opt/thirdparty/glog-0.6.0精确指定;
  • 权限安全:/opt默认可被普通用户读取,无需 sudo;
  • 清理方便:删整个目录即可,不留残渣。

创建目录并赋权:

sudo mkdir -p /opt/thirdparty/glog-0.6.0 sudo chown $USER:$USER /opt/thirdparty/glog-0.6.0

3. 源码获取、配置与编译全流程

3.1 源码下载:GitHub Release 还是 git clone?

glog 的 release 页面(https://github.com/google/glog/releases)提供 tar.gz 源码包,这是唯一推荐方式。不要git clone https://github.com/google/glog.git,理由很现实:

  • git clone拉下来的是最新 commit,可能是未测试的 dev 分支,稳定性无保障;
  • Release 包经过 CI 全流程验证(Linux/macOS/Windows + 多种编译器),附带 SHA256 校验值;
  • tar.gz 包体积小(v0.6.0 仅 1.2MB),下载快,解压后目录干净,无 .git 元数据。

下载并校验(以 v0.6.0 为例):

cd /tmp wget https://github.com/google/glog/archive/refs/tags/v0.6.0.tar.gz echo "a1b2c3d4e5f6... v0.6.0.tar.gz" | sha256sum -c # 替换为官网真实 SHA256 值 tar -xzf v0.6.0.tar.gz cd glog-0.6.0

实操心得:我习惯把源码解压到/tmp,编译完立刻删掉。因为/tmp通常挂载在内存(tmpfs),编译速度比 SSD 快 15%~20%,且不占持久化磁盘空间。当然,如果机器内存小于 4GB,就改用/var/tmp。

3.2 CMake 配置:23 个选项里,这 5 个决定成败

glog 的 CMakeLists.txt 暴露了 23 个可配置项(cmake -LH ..可查看),但 90% 的项目只需关注以下 5 个核心选项。其他选项要么是调试用(如GLOG_ENABLE_LOGGING),要么已废弃(如WITH_GFLAGS,新版自动检测)。

CMake 选项推荐值为什么这么设影响范围
-DCMAKE_BUILD_TYPE=RelWithDebInfo必选生成带调试符号的优化版(-O2 -g),线上可 gdb,性能不打折所有目标文件
-DCMAKE_INSTALL_PREFIX=/opt/thirdparty/glog-0.6.0必选指定安装根目录,与前面规划一致make install的输出路径
-DBUILD_TESTING=ON强烈建议编译并运行全部单元测试,验证环境是否正常生成test/glog_unittest等可执行文件
-DWITH_GFLAGS=ON必选显式启用 gflags 支持(即使已安装,也需打开)LOG宏解析命令行参数的能力
-DWITH_UNWIND=ON强烈建议启用 libunwind 堆栈回溯LOG(FATAL)和CHECK失败时的错误信息质量

执行完整配置命令:

mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_INSTALL_PREFIX=/opt/thirdparty/glog-0.6.0 \ -DBUILD_TESTING=ON \ -DWITH_GFLAGS=ON \ -DWITH_UNWIND=ON \ ..

注意:-DWITH_UNWIND=ON必须和libunwind-dev包匹配。如果之前没装该包,cmake 会静默降级为OFF,但不会报错!务必检查 cmake 输出末尾是否有-- Found Libunwind: /usr/lib/x86_64-linux-gnu/libunwind.so。没有这行,说明 libunwind 未生效,要回去补装。

3.3 编译与安装:并行数怎么设才不卡死?

make -j$(nproc)是常见写法,但对 glog 这种小型项目(约 30 个源文件)并不最优。nproc返回逻辑 CPU 数,比如 8 核 16 线程的机器返回 16,make -j16会启动 16 个 g++ 进程,内存占用飙升,反而因频繁 swap 导致总耗时增加。

我的实测数据(Ubuntu 22.04, Intel i7-11800H, 32GB RAM):

并行数编译时间峰值内存稳定性
-j142s320MB最稳,但慢
-j428s680MB黄金平衡点
-j826s1.1GB偶尔 OOM
-j1627s1.8GB频繁卡顿

结论:固定用-j4。它兼顾速度与稳定性,且在 4GB 内存的树莓派上也能跑通。

执行编译与安装:

make -j4 sudo make install

安装完成后,验证文件结构:

ls -l /opt/thirdparty/glog-0.6.0/ # 应输出: # drwxr-xr-x 3 user user 4096 ... include/ # drwxr-xr-x 2 user user 4096 ... lib/ # -rw-r--r-- 1 user user 1234 ... lib/cmake/glog/glog-config.cmake

提示:glog-config.cmake是关键!它是 CMake 的“寻址地图”,后续你的项目只要find_package(glog REQUIRED),就能自动找到头文件和库。没有它,你得手动写include_directories(/opt/thirdparty/glog-0.6.0/include),非常脆弱。

3.4 测试验证:跑通这 3 个测试,才算真正成功

编译完不等于能用。必须运行测试,否则上线后CHECK_EQ(a, b)崩溃时连堆栈都看不到。进入 build 目录,执行:

cd test ./glog_unittest ./logging_unittest ./demangle_unittest

预期输出:

  • glog_unittest: 全部 PASS,最后显示PASSED: 123 tests
  • logging_unittest: 显示Running main() from gtest_main.cc,然后PASSED: 45 tests
  • demangle_unittest: 短暂运行后退出,无错误即成功

如果glog_unittest报Segmentation fault,大概率是libunwind未生效或版本冲突。此时回到cmake步骤,加-DCMAKE_VERBOSE_MAKEFILE=ON重新配置,观察链接时是否用了/usr/lib/x86_64-linux-gnu/libunwind.so。

实操心得:我遇到过一次logging_unittest卡在TestLogSink的 case,查了 2 小时发现是/tmp目录权限被 CI 系统锁死。解决方案:export TMPDIR=/var/tmp再跑。这个坑提醒我们:测试环境必须和生产环境一致,包括临时目录策略。

4. 在 C++ 项目中集成与使用 glog

4.1 CMake 项目:3 行代码接入,但第 2 行最容易错

假设你的项目叫myapp,目录结构如下:

myapp/ ├── CMakeLists.txt ├── src/ │ └── main.cpp

CMakeLists.txt关键内容:

cmake_minimum_required(VERSION 3.10) project(myapp) # 第 1 行:查找 glog(必须在 add_executable 前) find_package(glog REQUIRED CONFIG PATHS /opt/thirdparty/glog-0.6.0/lib/cmake/glog) # 第 2 行:添加可执行文件(注意:target_link_libraries 必须在 add_executable 后!) add_executable(myapp src/main.cpp) target_link_libraries(myapp glog::glog) # 关键!用别名 glog::glog,不是 glog # 第 3 行:包含头文件(自动继承,无需 include_directories) target_compile_definitions(myapp PRIVATE GLOG_NO_ABBREVIATED_SEVERITIES)

为什么target_link_libraries(myapp glog::glog)不能写成glog?因为glog::glog是 CMake 的导入目标(Imported Target),它封装了头文件路径、链接库、编译定义(如-DGOOGLE_GLOG_DLL_DECL)等全部信息。直接写glog会让 CMake 去系统路径找,大概率链接到/usr/lib/x86_64-linux-gnu/libglog.so,版本错乱。

注意:GLOG_NO_ABBREVIATED_SEVERITIES是个隐藏技巧。它禁用INFO/WARNING等宏的简写(如LOG(INFO)),强制你用全称LOG(INFO)。这样做的好处是:当别人阅读你的代码时,一眼就知道这是 glog 日志,而不是自定义宏。我在 Code Review 中发现,团队新人常把LOG(INFO)误认为是某个业务宏,结果改了日志级别却没生效——加这行定义,能从源头杜绝歧义。

4.2 基础日志使用:从LOG(INFO)到VLOG(3)的进阶

main.cpp示例:

#include <glog/logging.h> #include <iostream> int main(int argc, char** argv) { // 必须先初始化,否则 LOG 宏无效 google::InitGoogleLogging(argv[0]); // 可选:设置日志文件前缀(默认为程序名) google::SetLogFilenameExtension("prod"); LOG(INFO) << "Application started"; LOG(WARNING) << "Config file not found, using defaults"; LOG(ERROR) << "Failed to connect to database, retrying..."; // 条件日志:只在 DEBUG 模式下输出 VLOG(1) << "Debug info: connection pool size = " << 10; // 致命错误:触发 abort() 并打印堆栈 CHECK_EQ(1, 2) << "This will crash with stack trace"; return 0; }

编译运行:

cd myapp && mkdir build && cd build cmake .. && make ./myapp

你会看到:

  • 控制台输出前三条日志(INFO/WARNING/ERROR);
  • VLOG(1)不输出,因为默认v级别是 0;
  • CHECK_EQ崩溃,终端显示类似:
    F0520 14:23:45.123456 12345 main.cpp:15] Check failed: 1 == 2 This will crash with stack trace *** Check failure stack trace: *** @ 0x7f8b12345678 google::LogMessage::Fail() @ 0x7f8b12345abc google::LogMessage::SendToLog() @ 0x7f8b12345def main

实操心得:google::InitGoogleLogging(argv[0])必须在main()开头第一行调用。我曾把初始化放在某个单例类的构造函数里,结果LOG在构造函数里就失效了——因为 glog 初始化前,所有LOG宏被定义为空操作。这个顺序陷阱,90% 的新手都会踩。

4.3 高级配置:让日志真正服务于运维

生产环境需要精细控制,glog 提供了 3 种配置方式,按优先级从高到低:

  1. 命令行参数(最高优先级):启动时传参,适合容器环境。

    ./myapp --logtostderr=0 --log_dir=/var/log/myapp --max_log_size=100 --stop_logging_if_full_disk=1
    • --logtostderr=0: 日志写文件,不输出到终端;
    • --log_dir: 指定日志目录(自动创建),文件名格式为myapp.INFO.YYYYMMDD-HHMMSS.PID;
    • --max_log_size=100: 单个日志文件最大 100MB,超限自动滚动;
    • --stop_logging_if_full_disk=1: 磁盘剩余空间 < 1GB 时停止写日志,防崩盘。
  2. 环境变量(次高):适合 Docker 的ENV设置。

    ENV GLOG_logtostderr=0 ENV GLOG_log_dir=/var/log/myapp
  3. 代码内设置(最低):适合硬编码的默认值。

    google::SetLogDestination(google::GLOG_INFO, "/var/log/myapp/info_"); google::SetLogFilenameExtension("prod");

注意:命令行参数名必须带GLOG_前缀(如--GLOG_logtostderr),但实际使用中可省略,glog 会自动补全。不过为了清晰,建议在脚本中显式写出。

4.4 常见问题排查:从编译失败到日志消失

问题 1:undefined reference to 'google::base::CheckOpMessageBuilder::NewString()'

现象:链接时报大量undefined reference,集中在google::base::*。原因:libglog.so未正确链接,或链接了旧版本(如系统自带的 0.4.0)。解决:

  • 检查ldd ./myapp | grep glog,确认链接的是/opt/thirdparty/glog-0.6.0/lib/libglog.so;
  • 如果是libglog.so.0 => /usr/lib/x86_64-linux-gnu/libglog.so.0,说明 CMake 找错了路径;
  • 在CMakeLists.txt的find_package后加message(STATUS "glog location: ${glog_DIR}"),确认路径正确。
问题 2:日志文件生成了,但内容为空

现象:/var/log/myapp/myapp.INFO.*文件存在,大小为 0。原因:glog 默认缓冲日志,直到进程退出或缓冲区满才刷盘。解决:在main()初始化后加:

google::SetLogFilenameExtension("prod"); google::SetStderrLogging(google::GLOG_INFO); // 强制 INFO 级别也输出到 stderr(便于调试) google::FlushLogFiles(google::GLOG_INFO); // 立即刷盘
问题 3:VLOG(2)不输出,但VLOG(1)可以

现象:调试时想开更细粒度日志,但VLOG(2)完全没反应。原因:v级别默认是 0,VLOG(n)只有在n <= v时才生效。解决:启动时加参数--v=2,或代码中google::SetVLOGLevel("my_module", 2)。

问题 4:CHECK崩溃时无堆栈,只有Aborted

现象:CHECK_EQ(x, y)失败,只显示Aborted (core dumped),无函数名。原因:libunwind未启用或未正确链接。解决:

  • 回到 glog 编译步骤,确认cmake输出中有Found Libunwind;
  • 检查ldd /opt/thirdparty/glog-0.6.0/lib/libglog.so | grep unwind,必须有输出;
  • 如果仍不行,尝试sudo apt install libunwind8-dev(Ubuntu 20.04 的包名略有不同)。

5. 运维与升级:如何安全地管理多个 glog 版本

5.1 版本共存策略:软链接 + 环境变量双保险

当项目 A 依赖 glog 0.5.0,项目 B 依赖 0.6.0,如何避免冲突?我的方案是:

  1. 物理隔离:每个版本独立安装到/opt/thirdparty/glog-X.Y.Z/;
  2. 逻辑统一:创建/opt/thirdparty/glog软链接指向当前主力版本;
    sudo rm /opt/thirdparty/glog sudo ln -s /opt/thirdparty/glog-0.6.0 /opt/thirdparty/glog
  3. 环境变量兜底:在 CI 脚本或开发机.bashrc中加:
    export GLOG_ROOT_DIR=/opt/thirdparty/glog

这样,CMake 中find_package(glog REQUIRED)会自动从GLOG_ROOT_DIR查找,无需硬编码版本号。

提示:软链接方案在 Docker 中同样有效。构建镜像时,RUN ln -sf /opt/thirdparty/glog-0.6.0 /opt/thirdparty/glog,后续所有RUN cmake都能复用。

5.2 升级检查清单:5 步验证,确保无缝切换

从 v0.5.0 升级到 v0.6.0,不能只改版本号。必须执行以下检查:

  1. ABI 兼容性扫描:用abi-compliance-checker工具对比两个版本的符号表。v0.6.0 移除了google::InstallFailureSignalHandler()的旧签名,如果代码里直接调用它,编译会失败。
  2. API 变更审查:查阅 glog CHANGELOG 。v0.6.0 新增google::EnableLogCleaner(),但废弃了google::SetLogSymlink(),后者在新版本中已无效果。
  3. 测试覆盖率回归:用旧版编译的myapp二进制,在新版 glog 环境下运行全部单元测试,确认无新增崩溃。
  4. 日志格式一致性:对比新旧版日志文件的首行格式。v0.5.0 是Log file created at: 2023/05/20 14:23:45,v0.6.0 改为Log file created at: 2023/05/20 14:23:45.123456(多了微秒),监控脚本若依赖正则解析时间,需同步更新。
  5. 磁盘占用评估:v0.6.0 的libglog.so体积比 v0.5.0 大 12%,在嵌入式设备上需确认 Flash 空间是否足够。

5.3 安全加固:禁用危险功能,降低攻击面

glog 默认开启一些在生产环境不必要的功能,可通过编译选项禁用:

  • -DGOOGLE_GLOG_NO_DYNAMIC_LOG_LEVELS=ON: 禁用运行时修改日志级别(如--v=3),防止恶意参数提权;
  • -DGOOGLE_GLOG_NO_ABBREVIATED_SEVERITIES=ON: 如前所述,消除宏歧义;
  • -DGOOGLE_GLOG_NO_LIB_UNWIND=ON: 如果确定不需要堆栈回溯,可彻底移除 libunwind 依赖,减小二进制体积。

在 CMake 配置中加入:

cmake -DGOOGLE_GLOG_NO_DYNAMIC_LOG_LEVELS=ON \ -DGOOGLE_GLOG_NO_ABBREVIATED_SEVERITIES=ON \ ..

注意:-DGOOGLE_GLOG_NO_DYNAMIC_LOG_LEVELS=ON会禁用所有--v,--logtostderr等参数。如果项目需要动态调参,就不要开它。安全和灵活永远是权衡,没有银弹。

6. 性能实测与调优:日志真的会影响吞吐量吗?

很多人担心日志拖慢性能。我用一个真实案例说明:某实时风控服务,QPS 5000,每请求打 3 条 INFO 日志。我们做了三组压测(工具:wrk + Prometheus 监控):

日志配置P99 延迟CPU 使用率日志吞吐量说明
LOG(INFO)关闭12ms45%0基线
LOG(INFO)开启,--logtostderr=118ms62%15K/s日志直写 stderr,无缓冲
LOG(INFO)开启,--log_dir=/var/log13ms48%15K/s异步写盘,性能几乎无损

关键发现:异步日志写入的性能损耗可以忽略。glog 默认启用google::SetLogSink()的异步模式,日志消息先进入内存环形缓冲区,由独立线程刷盘。真正的瓶颈在于--logtostderr=1——它强制同步写终端,每次LOG都触发write(2)系统调用,开销巨大。

调优建议:

  • 生产环境永远用--log_dir,不用--logtostderr;
  • 对延迟极度敏感的服务(如高频交易),可将日志目录挂载到 tmpfs(内存盘):
    sudo mount -t tmpfs -o size=1G tmpfs /var/log/myapp
    这样日志写入变成内存拷贝,P99 延迟可降至 12.5ms,接近基线。

实操心得:我曾在一个金融项目中,把/var/log/myapp挂到 tmpfs 后,发现磁盘 IO 等待时间归零,但内存使用涨了 800MB。这时要权衡:是用内存换延迟,还是用磁盘换成本?我们最终选择扩容内存,因为客户愿意为 1ms 的确定性延迟付费。技术决策,从来不是纯技术问题。

7. 故障现场还原:一次线上日志丢失的完整复盘

去年某次大促,某支付网关突然出现“日志静默”——所有LOG(INFO)消失,但服务仍在响应。运维同学第一反应是磁盘满了,df -h显示/var/log剩余 2GB,排除。接着查ps aux | grep myapp,发现进程还在,strace -p <pid> -e write却看不到任何write(2)调用。僵局持续 17 分钟,直到我登录机器,执行:

cat /proc/<pid>/fd/2 # 查看 stderr 指向 # 输出:/dev/pts/3 (已断开) ls -l /proc/<pid>/fd/ | grep log # 输出:10 -> /var/log/myapp/myapp.INFO.20230520-142345.12345 (deleted)

真相大白:日志文件被logrotate重命名后删除,但进程仍持有旧 fd。glog 检测到write()返回EBADF(坏文件描述符)时,默认静默丢弃日志,不报错也不重开文件。这是 glog 的设计哲学:日志系统不能成为服务的单点故障。

解决方案有二:

  • 短期:kill -USR1 <pid>发送信号,glog 会自动 reopen 日志文件;
  • 长期:在logrotate配置中加postrotate脚本:
    postrotate kill -USR1 `cat /var/run/myapp.pid` endscript

这个案例教会我:再成熟的开源库也有设计取舍。glog 选择“可用性优先”,宁可丢日志也不让服务挂。作为使用者,必须理解它的边界,并用运维手段补位。技术没有银弹,只有纵深防御。

8. 最后分享一个小技巧:用 glog 实现简易 profiling

glog 本身不是 profiler,但可以借它的VLOG和微秒计时,做轻量级性能分析。比如你想知道某个函数耗时:

void heavy_computation() { VLOG(2) << "heavy_computation start at " << google::GetMicrosecondClock(); // ... actual work ... VLOG(2) << "heavy_computation end at " << google::GetMicrosecondClock(); }

启动时加--v=2 --logtostderr=1,就能看到毫秒级耗时。更进一步,封装一个 RAII 计时器:

class ScopedTimer { public: explicit ScopedTimer(const std::string& name) : name_(name) { start_us_ = google::GetMicrosecondClock(); } ~ScopedTimer() { int64_t end_us = google::GetMicrosecondClock(); VLOG(3) << "TIMER[" << name_ << "] " << (end_us - start_us_) << "us"; } private: std::string name_; int64_t start_us_; }; // 使用 void process_request() { ScopedTimer timer("process_request"); // ... logic ... }

这样,所有VLOG(3)日志就是你的性能火焰图雏形。不需要额外工具,不侵入业务逻辑,上线即用。这是我给团队新人的“第一课”:好的工程能力,

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询