news 2026/7/16 1:44:41

C++项目glog日志库实战:从编译集成到高级配置全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++项目glog日志库实战:从编译集成到高级配置全解析

1. 项目概述

如果你在C++项目里用过Google Logging(glog),大概率对它又爱又恨。爱的是它那套基于C++流式风格的日志API,用起来确实顺手,LOG(INFO) << “Something happened: “ << value;这种写法,既直观又符合C++程序员的直觉,比printf或者sprintf安全,也比一些复杂的日志库要轻量。恨的是,当你兴致勃勃地把它集成到项目里,编译、链接、运行时,各种稀奇古怪的问题就冒出来了:链接时找不到符号、运行时日志文件不生成、多线程下日志错乱、或者想自定义个输出格式却无从下手。更让人头大的是,这个项目在2025年6月30日已经被官方归档(Archived),不再维护了。这意味着,你遇到的新问题可能再也等不到官方的修复,社区支持的力度也会逐渐减弱。

但这并不意味着glog就完全不能用了。恰恰相反,作为一个曾经被广泛使用、代码质量极高的库,它在很多存量项目和特定场景下依然有很强的生命力。很多问题并非无解,只是需要一些“踩坑”后总结出来的经验。这篇文章,就是基于我过去几年在多个C++服务端项目中深度使用glog的经验,为你梳理出一份“避坑指南”和“解决方案手册”。我会覆盖从编译安装、基础配置、高级用法到疑难杂症排查的全过程,所有方案都是亲测有效,并且完全基于免费、开源的生态。无论你是刚刚接触glog的新手,还是在维护一个使用了glog的老项目,这篇文章都能帮你节省大量折腾的时间。

2. 核心问题全景与解决思路拆解

在深入具体问题之前,我们有必要先对glog可能遇到的问题做一个全景式的扫描,并理解其背后的根源。这能帮助你在遇到问题时快速定位方向,而不是盲目搜索。

2.1 问题分类与根源分析

glog的问题大致可以归结为以下几类,每一类都有其特定的发生场景和解决思路:

  1. 构建与集成问题:这是新手遇到最多的第一道坎。问题通常表现为编译错误、链接错误(如undefined reference togoogle::InitGoogleLogging`)。根源在于:

    • 依赖缺失:glog本身依赖不多,但在某些系统(如较老的Linux发行版)上,可能需要libunwindgflags(Google的命令行标志库)。虽然glog可以不依赖gflags,但很多示例和旧文档默认你装了。
    • 构建系统不匹配:你的项目可能用CMake、Bazel、Makefile或Autotools,而glog的源码构建方式需要与之适配。直接#include源码或使用预编译的不匹配的库文件,很容易出问题。
    • C++标准版本冲突:glog要求C++14,如果你的项目用的是C++11或更老的标准,或者用的是C++17/20的某些新特性,可能在编译时遇到语法或标准库兼容性问题。
  2. 运行时配置与行为问题:库能编译链接,但一运行就发现和预期不符。比如:

    • 日志文件不输出:程序运行了,但当前目录下没有生成<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>这样的文件。
    • 日志级别不生效:设置了FLAGS_minloglevel,但DEBUG或INFO日志依然满天飞。
    • 日志格式不符合预期:想添加线程ID、自定义时间格式,却发现无从下手。
    • 性能问题:在高并发场景下,日志输出成为性能瓶颈。 根源在于对glog的运行时初始化流程、标志位(Flags)系统以及内部缓冲机制不了解。
  3. 高级特性与兼容性问题:当你想用一些更强大的功能时,会遇到障碍。

    • 自定义日志接收器(Sink):想把日志同时输出到文件、网络和标准错误,需要深入glog的内部接口。
    • 信号处理与崩溃日志:glog内置了信号处理,能在程序崩溃时生成堆栈跟踪,但这需要正确的编译选项和系统支持(如libunwind)。
    • 与其它日志库共存:项目历史遗留,部分模块用了log4cxx、spdlog等,如何让glog与之和平共处?
    • 官方归档后的替代方案:既然官方不维护了,是硬着头皮继续用,还是迁移?有哪些平滑迁移的选项?

2.2 总体解决思路

面对这些问题,我的解决思路遵循一个从基础到高级、从通用到特定的路径:

  1. 确保环境纯净与依赖正确:这是所有工作的基础。使用包管理器(如apt, yum, vcpkg, conan)安装通常是避免编译问题的最快方法。
  2. 理解初始化与标志位:花半小时读懂InitGoogleLogging和几个核心标志位(FLAGS_log_dir,FLAGS_minloglebug,FLAGS_stderrthreshold),能解决80%的运行时问题。
  3. 掌握日志流与宏的语义LOG(LEVEL),VLOG(n),DLOG,PLOG这些宏有什么区别?什么时候用CHECK而不是assert?理解这些能写出更健壮、信息量更足的日志。
  4. 深入内部机制以定制化:当标准功能不满足时,需要研究LogMessageLogSink等内部类,这是解决高级需求的钥匙。
  5. 建立监控与排查习惯:将日志问题本身也纳入监控,比如定期检查日志目录磁盘空间、设置日志文件滚动(Rotate)策略,防患于未然。

接下来,我们就按照这个思路,进入具体的实操环节。

3. 构建、集成与环境配置的坑与解法

让我们从第一步开始,把glog稳稳地“请”进你的项目。

3.1 选择正确的安装方式

首选:系统包管理器对于快速验证和大多数开发环境,这是最推荐的方式。它能自动处理依赖和库路径。

# Ubuntu/Debian sudo apt-get install libgoogle-glog-dev # CentOS/RHEL (需要EPEL仓库) sudo yum install epel-release sudo yum install google-glog-devel # macOS (使用Homebrew) brew install glog

注意:包管理器提供的版本可能不是最新的。如果遇到需要特定版本或补丁的情况,才需要考虑从源码编译。

次选:从源码编译当包管理器版本不合适,或者你需要开启某些特定编译选项(如调试符号、定制化的安装路径)时,需要源码编译。

# 1. 克隆代码 (注意:主仓库已归档,可考虑fork或使用社区维护的镜像) git clone https://github.com/google/glog.git cd glog # 2. 创建构建目录并配置 mkdir build && cd build # 关键配置项: # -DWITH_GFLAGS=OFF # 如果不需gflags支持,建议关闭,减少依赖 # -DWITH_UNWIND=ON # 如果需要更好的崩溃堆栈信息,开启(需系统有libunwind) # -DBUILD_SHARED_LIBS=ON # 默认静态库,如需动态库则开启 cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GFLAGS=OFF .. # 3. 编译并安装 make -j$(nproc) sudo make install # 默认安装到 /usr/local

避坑点1:安装路径冲突如果你系统里已经通过包管理器安装了glog,再从源码make install/usr/local,可能会造成头文件和库文件版本混乱。一个干净的做法是使用CMAKE_INSTALL_PREFIX指定一个独立路径,并在你的项目中显式引用这个路径。

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/myglog .. make -j$(nproc) sudo make install

之后在你的项目CMakeLists.txt中,可以通过find_package(glog REQUIRED PATHS /opt/myglog)来定位。

避坑点2:Windows下的编译Windows下编译glog相对麻烦,缺少一些Unix特有的头文件和功能。最省事的方法是使用vcpkg。

# 安装vcpkg后 vcpkg install glog:x64-windows

然后在你的CMake项目中配置-DCMAKE_TOOLCHAIN_FILE=[path/to/vcpkg]/scripts/buildsystems/vcpkg.cmake即可。

3.2 项目集成:CMake最佳实践

假设你的项目使用CMake,集成glog的最佳实践如下:

cmake_minimum_required(VERSION 3.10) project(MyGlogProject) # 方式1:使用find_package (推荐,清晰) find_package(glog REQUIRED CONFIG) # 如果是从源码安装到标准路径或vcpkg # 或者指定路径 # find_package(glog REQUIRED PATHS /opt/myglog/lib/cmake/glog) add_executable(my_app main.cpp) target_link_libraries(my_app PRIVATE glog::glog) # 方式2:使用pkg-config (如果glog提供了.pc文件) find_package(PkgConfig REQUIRED) pkg_check_modules(GLOG REQUIRED libglog) target_include_directories(my_app PRIVATE ${GLOG_INCLUDE_DIRS}) target_link_libraries(my_app PRIVATE ${GLOG_LIBRARIES})

关键点:使用glog::glog这个CMake导入目标(Imported Target),它能自动传递所有必要的编译定义和依赖关系,比手动指定include_directorieslink_libraries更可靠。

3.3 一个可运行的“Hello Log”示例

创建一个main.cpp文件,验证集成是否成功:

#include <glog/logging.h> #include <iostream> int main(int argc, char* argv[]) { // 初始化glog。argv[0]用于生成默认日志文件名。 google::InitGoogleLogging(argv[0]); // 设置日志输出到标准错误(除了ERROR和FATAL,它们默认就输出) // 这行很重要,否则你可能在控制台看不到任何输出 google::InstallFailureSignalHandler(); // 可选:安装失败信号处理器,用于捕获崩溃 LOG(INFO) << "This is an informational message."; LOG(WARNING) << "This is a warning message."; LOG(ERROR) << "This is an error message."; // DLOG(INFO) << "This debug log will only be printed in debug builds."; // 使用VLOG进行分级详细日志记录,级别由FLAGS_v控制 VLOG(1) << "I'm printed when you run the program with --v=1 or higher"; VLOG(2) << "I'm printed when you run the program with --v=2 or higher"; // 使用CHECK宏进行断言,比assert更强大,失败会记录FATAL日志 int x = 10; CHECK_GT(x, 0) << "x must be positive"; // 检查 x > 0 std::cout << "Program finished. Check the log files in the current directory." << std::endl; // 关闭日志库(非必须,程序退出时会自动清理) google::ShutdownGoogleLogging(); return 0; }

编译并运行:

g++ -std=c++14 -o my_app main.cpp -lglog -lpthread ./my_app

运行后,你应该能在当前目录看到生成的日志文件(如my_app.yourhostname.yourusername.log.INFO.20250315-123456.7890),并在控制台看到ERROR和FATAL级别的日志(因为默认FLAGS_stderrthreshold=2,即ERROR及以上级别输出到stderr)。

如果这一步成功了,恭喜你,最基础的集成已经完成。如果失败了,请根据错误信息回溯到前面的安装和集成步骤。

4. 运行时配置:让日志听话的关键

glog的行为几乎完全由一系列gflags管理的命令行标志控制。即使你不链接gflags库,glog内部也有一套兼容的实现来解析这些标志。理解并正确设置它们是驯服glog的关键。

4.1 核心标志位详解与设置方法

你可以在代码中直接设置这些标志,也可以通过命令行参数传递。

在代码中设置(程序启动时):

int main(int argc, char* argv[]) { // 必须在InitGoogleLogging之前设置一些标志! FLAGS_logtostderr = false; // 默认false。为true时,所有日志输出到stderr,不生成日志文件。 FLAGS_alsologtostderr = false; // 默认false。为true时,日志除了写入文件,也同时输出到stderr。 FLAGS_stderrthreshold = google::GLOG_ERROR; // 默认2(ERROR)。设置输出到stderr的最低级别。0(INFO), 1(WARNING), 2(ERROR), 3(FATAL) FLAGS_log_dir = "/var/log/myapp"; // 默认空(当前目录)。日志文件输出目录。务必确保进程有写权限! FLAGS_minloglevel = google::GLOG_INFO; // 默认0(INFO)。全局最低日志级别,低于此级别的日志将被直接丢弃。 FLAGS_v = 0; // 默认0。VLOG的全局级别,只有VLOG(n)中 n < FLAGS_v 的日志才会被记录。 google::InitGoogleLogging(argv[0]); // ... 其余代码 }

通过命令行参数设置(更灵活):

# 将日志同时输出到文件和stderr ./my_app --alsologtostderr # 只输出到stderr,不生成文件 (常用于调试) ./my_app --logtostderr # 设置stderr只输出ERROR及以上 ./my_app --stderrthreshold=2 # 设置日志目录 ./my_app --log_dir=/tmp/my_logs # 只记录WARNING及以上级别的日志 ./my_app --minloglevel=1 # 启用VLOG级别为1的详细日志 ./my_app --v=1

实操心得:初始化顺序的坑FLAGS_log_dirFLAGS_logtostderr等影响输出目标的标志,必须在google::InitGoogleLogging之前设置,否则初始化可能不会采用你的设置。而像FLAGS_v这种控制日志内容的标志,在初始化前后设置都可以。一个好习惯是,在main函数开头,紧接在gflags解析(如果有的话)之后,InitGoogleLogging之前,集中设置所有输出相关的标志。

4.2 日志文件命名与滚动策略

默认的日志文件名很长,包含了程序名、主机名、用户名、级别、时间戳和PID,这保证了唯一性,但也可能让人眼花缭乱。你可以通过设置FLAGS_log_file_name来影响基础命名(但不建议完全自定义,因为唯一性可能被破坏)。

更重要的管理在于日志文件滚动(Rotate),防止单个文件过大。

// 在代码中设置滚动策略 FLAGS_max_log_size = 100; // 单位MB,默认1800MB。单个日志文件达到此大小后,会滚动到下一个文件。 FLAGS_stop_logging_if_full_disk = true; // 默认false。当磁盘空间不足时,停止日志记录,避免写满磁盘。

glog的滚动是自动的。当myapp.xxx.log.INFO.20250315-120000.12345达到max_log_size后,会被重命名为myapp.xxx.log.INFO.20250315-120000.12345.1,然后创建一个新的myapp.xxx.log.INFO.20250315-120001.12345继续写入。旧文件会以.1,.2后缀依次递增。

避坑点:日志文件清理glog不会自动删除旧的日志文件!这是一个潜在的磁盘空间杀手。你必须自己实现清理逻辑,例如通过crontab定时任务:

# 每天凌晨2点,删除超过7天的glog日志文件 0 2 * * * find /path/to/log/dir -name \"*.log.*\" -mtime +7 -delete

或者在你的应用程序启动或关闭时,调用一个清理函数。千万不要指望glog帮你做这件事。

4.3 多线程与异步日志(性能考量)

glog的日志输出默认是线程安全的,但它是同步的。这意味着每次调用LOG(INFO) << ...,当前线程都会等待I/O操作(写文件或写stderr)完成。在高并发、高频率打日志的场景下,这可能会成为性能瓶颈。

glog本身不提供内置的异步日志机制。社区有一些方案,比如将日志先写入一个内存队列,再由后台线程批量写出,但这需要你自行实现或集成第三方库(如spdlog的异步模式)。

一个简单的性能优化技巧:对于极度频繁的调试日志(例如在紧凑循环中),使用VLOG并默认将FLAGS_v设为0来禁用。在需要排查问题时,再通过命令行动态开启--v=2。这比用LOG(DEBUG)配合FLAGS_minloglevel更灵活,因为VLOG的调用开销在禁用时极低。

5. 高级用法与定制化技巧

当基础功能满足不了你时,就需要深入了解glog的内部接口了。

5.1 自定义日志格式

glog默认的日志格式是固定的:[级别][月/日 时:分:秒.微秒][线程ID?] 文件名:行号] 消息体。有时你可能想添加更多上下文,比如协程ID、请求ID,或者改变时间格式。

这需要通过自定义LogMessage的生成逻辑来实现,比较底层。一个更实用的方法是继承google::LogSinkLogSink允许你拦截每一条日志消息,然后以任意格式输出到任意地方。

#include <glog/logging.h> #include <iomanip> #include <sstream> class MyCustomSink : public google::LogSink { public: void send(google::LogSeverity severity, const char* full_filename, const char* base_filename, int line, const google::LogMessageTime& logmsgtime, const char* message, size_t message_len) override { // 忽略某些级别的日志 if (severity < google::GLOG_WARNING) { return; } std::ostringstream oss; // 自定义格式: [时间][级别][文件:行] 消息 auto t = logmsgtime.time(); std::time_t tt = std::chrono::system_clock::to_time_t(t); oss << "[" << std::put_time(std::localtime(&tt), "%Y-%m-%d %H:%M:%S") << "][" << google::GetLogSeverityName(severity) << "]" << "[" << base_filename << ":" << line << "] " << std::string(message, message_len) << std::endl; // 输出到标准错误(也可以写到网络、数据库等) std::cerr << oss.str(); // 同时,你也可以继续让默认的文件日志生效(如果你还添加了默认的file sink) } }; int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); MyCustomSink sink; google::AddLogSink(&sink); // 注册自定义Sink LOG(INFO) << "This info will be filtered out by our sink."; LOG(WARNING) << "This warning will be formatted by our sink."; LOG(ERROR) << "This error will also be formatted by our sink."; // 注意:sink对象必须在程序生命周期内有效,所以通常定义为全局或静态变量。 // 程序结束前,可以调用 google::RemoveLogSink(&sink); 但非必须。 google::ShutdownGoogleLogging(); return 0; }

5.2 条件日志与调试宏

glog提供了一系列强大的宏,用于有条件的日志记录和检查,这比简单的if语句加LOG更高效、更安全。

  • LOG_IF(LEVEL, CONDITION): 当条件满足时才记录日志。
    int error_count = 5; LOG_IF(ERROR, error_count > 0) << "Encountered " << error_count << " errors.";
  • LOG_EVERY_N(LEVEL, N): 每执行到第N次时记录一次日志。非常适合记录周期性事件,避免日志刷屏。
    for (int i = 0; i < 10000; ++i) { LOG_EVERY_N(INFO, 1000) << "Processed " << google::COUNTER << " items."; // COUNTER是内部计数器 // ... 处理逻辑 }
  • LOG_FIRST_N(LEVEL, N): 前N次执行时记录日志。
  • DLOG(LEVEL),DLOG_IF,DVLOG: 这些是调试版本专用的宏,在非调试(NDEBUG定义)构建中会被完全编译掉,不产生任何运行时开销。强烈推荐在调试日志中使用
  • CHECK系列宏:这是glog的王牌功能之一。它不仅是断言,失败时会生成FATAL级别日志,打印堆栈跟踪(如果编译时支持),并终止程序。比标准assert更强大。
    CHECK_NOTNULL(pointer); // 检查指针非空 CHECK_EQ(a, b); // 检查相等 CHECK_GE(a, b); // 检查 a >= b CHECK_STREQ(str1, str2); // 检查C风格字符串相等 // 所有CHECK宏都支持 << 流操作符附加额外信息 CHECK_LT(index, vector.size()) << "Index out of bounds. index=" << index << ", size=" << vector.size();

实操心得:善用DLOGVLOG将开发调试用的日志全部用DLOGVLOG来写。DLOG在发布版本中自动消失,零开销。VLOG可以通过命令行动态调整级别,在线上排查问题时非常有用,无需重新编译部署。而LOG(INFO)/LOG(WARNING)等则用于记录程序正常运行时的关键状态和事件。

5.3 信号处理与崩溃堆栈

google::InstallFailureSignalHandler();这行代码非常有用。它会让glog捕获SIGSEGV(段错误)、SIGILL(非法指令)等致命信号,并在程序崩溃前,将堆栈跟踪信息输出到stderr和日志文件。这对于定位线上崩溃原因至关重要。

要使堆栈跟踪信息更可读(包含函数名和行号,而不是一堆地址),你需要:

  1. 编译你的程序时加上-g-rdynamic选项(GCC/Clang),以包含调试符号或动态符号表。
  2. 确保系统安装了libunwindglibcbacktrace相关功能,并且glog在编译时开启了WITH_UNWINDWITH_STACKTRACE支持。

6. 疑难杂症排查实录

即使按照最佳实践操作,一些奇怪的问题还是会出现。下面是我遇到过的典型问题及其解决方法。

6.1 常见问题速查表

问题现象可能原因解决方案
编译错误:undefined reference to ‘google::InitGoogleLogging’1. 没有链接glog库 (-lglog)。
2. 链接顺序不对,-lglog需要放在源文件/目标文件之后。
3. 使用了C++编译器链接C库(罕见)。
1. 确保编译命令包含-lglog,CMake中使用target_link_libraries
2. 调整链接顺序:g++ main.cpp -o app -lglog -lpthread
3. 如果是C项目,使用extern “C”包含头文件,并链接glog
运行时无日志文件生成1.FLAGS_log_dir路径不存在或进程无写权限。
2.FLAGS_logtostderrFLAGS_alsologtostderr被设为true
3. 当前目录不可写。
1. 检查目录权限,或在代码中创建目录mkdir(FLAGS_log_dir.c_str(), 0755)
2. 确认这些标志在InitGoogleLogging前被正确设置为false
3. 使用--log_dir指定一个绝对路径。
日志同时输出到屏幕和文件,但只想保留一种FLAGS_alsologtostderr被设置为true如果想只输出到文件,确保FLAGS_logtostderr=falseFLAGS_alsologtostderr=false。如果想只输出到屏幕,设置FLAGS_logtostderr=true
CHECK宏失败时没有堆栈信息1. 程序编译时未包含调试符号 (-g)。
2. 编译时被优化(如-O2)可能导致行号信息不准确。
3. glog编译时未启用栈回溯支持。
1. 开发/调试版本编译时加上-g选项。
2. 对于发布版本,考虑使用-rdynamic并保留一份带调试符号的二进制用于调试。
3. 从源码编译glog时,确保-DWITH_UNWIND=ON
多线程程序日志内容错乱或丢失虽然glog内部是线程安全的,但极端高并发下,如果多个线程同时写一条很长的日志(多次<<操作),可能会交叉。对于单条日志,确保在一条LOG语句内完成构建。避免先构建字符串再输出,因为中间状态可能被其他线程打断。LOG(INFO) << “Key: “ << key << “, Value: “ << value;是原子的。
程序退出时报告内存泄漏(google::LogMessage::~LogMessage通常是因为没有调用google::ShutdownGoogleLogging(),或者日志线程还未完全结束程序就退出了。1. 在main函数返回前调用google::ShutdownGoogleLogging()
2. 确保所有全局/静态对象的析构函数中不再打日志。
3. 对于某些检测工具(如Valgrind),这可能是误报,可以忽略glog内部的内存池。
日志文件体积增长过快1.FLAGS_max_log_size设置过大。
2. 日志级别太低(如INFO),打印了过多无关紧要的日志。
3. 没有清理旧日志文件的策略。
1. 根据需求调整max_log_size(如100MB)。
2. 提高FLAGS_minloglevelWARNINGERROR,减少日志量。
3.必须实现外部日志清理(如crontab脚本)。
在动态库中使用glog,主程序也使用,冲突符号冲突或重复初始化。理想情况下,整个进程应该只使用一份glog。如果动态库是第三方库,你无法控制,可以考虑:1. 让动态库静态链接glog并隐藏符号。2. 与库提供者协商使用统一的glog版本。这是一个复杂问题,可能需具体分析。

6.2 深入排查:使用GDB调试glog问题

当遇到一些玄学问题,比如日志偶尔丢失、程序在打日志时卡住,可能需要更深入的调试。

  1. 查看glog内部状态:glog提供了一些未公开但有用的函数。例如,你可以通过google::GetLoggingDirectories()来检查它当前认为的日志目录是什么。
  2. GDB断点:如果你怀疑问题在glog内部,可以编译一份带调试符号的glog,然后在关键函数上设断点。
    gdb your_program (gdb) break google::LogMessage::SendToLog (gdb) break google::LogFileObject::Write
    这可以帮助你观察每条日志是如何被处理和写入的。
  3. 跟踪系统调用:使用strace查看写文件是否失败。
    strace -e trace=file -o strace.out ./your_program
    然后查看strace.out文件中对日志文件的openwriteclose等调用是否返回错误(如-1 EACCES权限错误)。

6.3 官方归档后的出路与迁移考量

最后,我们无法回避glog已被归档的事实。对于新项目,我建议慎重考虑。对于老项目,你有几个选择:

  1. 继续使用,自行维护:glog代码很稳定,如果你的使用场景简单,且当前版本工作良好,可以继续使用。将源码作为第三方库引入你的项目,并做好不再有更新的心理准备。关注社区是否有重要的安全补丁分支。
  2. 迁移到absl::Log(Abseil Logging):这是Google官方推荐的继任者,属于Abseil库的一部分。它设计更现代,性能可能更好,并且与Google内部的C++生态集成更紧密。但API与glog不完全相同,迁移需要一定工作量。
  3. 迁移到ng-log:这是一个社区维护的、旨在API兼容glog的项目。目标是让现有使用glog的代码只需极少的修改就能切换过去。如果你的项目严重依赖glog的特定API,这是一个平滑迁移的选项。
  4. 评估其他日志库:如spdlog(高性能,特性丰富,头文件库)、fmtlog(基于fmt库,高性能)、Boost.Log(功能强大但较重)。这需要重新评估需求和进行大量代码修改。

迁移建议:如果项目处于活跃开发期,且对日志功能有更高要求(如异步、更灵活的格式、sink),趁早规划迁移到spdlogabsl::Log。如果项目稳定,且glog完全满足需求,可以暂时不动,但要在构建系统中固定glog的版本和源码,避免未来因系统环境变化导致的不兼容。

说到底,工具是为人服务的。glog虽然“年事已高”,但其简洁的设计和稳定的表现,在无数C++项目中证明了它的价值。希望这份汇集了多年踩坑经验的指南,能让你在使用glog的路上走得更顺畅一些。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 1:42:03

LinkSwift:一站式网盘直链下载助手,告别九大网盘限速烦恼

LinkSwift&#xff1a;一站式网盘直链下载助手&#xff0c;告别九大网盘限速烦恼 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移…

作者头像 李华
网站建设 2026/7/16 1:40:36

Understat Python库终极指南:三步解锁专业足球数据分析

Understat Python库终极指南&#xff1a;三步解锁专业足球数据分析 【免费下载链接】understat An asynchronous Python package for https://understat.com/. 项目地址: https://gitcode.com/gh_mirrors/un/understat 想要获取专业的足球统计数据却苦于技术壁垒&#x…

作者头像 李华
网站建设 2026/7/16 1:38:10

分布式锁的工程实践:Redlock算法的正确实现与边界条件分析

分布式锁的工程实践&#xff1a;Redlock算法的正确实现与边界条件分析 一、引言 分布式锁是微服务架构中最基础的同步原语之一。很多团队引入Redis后&#xff0c;顺手用SET NX EX实现了锁&#xff0c;以为这样就能解决并发问题。直到某天线上出现重复扣款或者数据不一致&#x…

作者头像 李华
网站建设 2026/7/16 1:36:48

【避坑指南】MyBatis-Plus中TypeHandler不生效的常见场景与解决方案

1. 为什么你的TypeHandler突然失效了&#xff1f;第一次在MyBatis-Plus里用TableField(typeHandler)注解时&#xff0c;很多人都会遇到这样的场景&#xff1a;明明按照文档配置了自定义TypeHandler&#xff0c;但查询时字段死活返回null&#xff0c;更新时类型转换直接报错。这…

作者头像 李华
网站建设 2026/7/16 1:33:24

30m高精度|地貌类型分布(海底+陆地)|栅格

&#x1f50d; 数据简介 本次分享30m高精度全球地貌类型分布栅格数据&#xff08;含海底陆地&#xff09;&#xff0c;2026版权威分类&#xff0c;完整覆盖陆地与海底地貌&#xff0c;30m精细刻画地形单元&#xff0c;适配地貌制图、地质灾害与生态环境研究&#xff0c;支持多尺…

作者头像 李华