简介:这是Google glog日志库的Windows编译版,面向使用Visual Studio 2017的C++开发者,帮助在Windows环境下快速集成跨平台日志系统,实时跟踪程序状态、定位致命错误。资源包共13个文件,约80KB,包含cmake构建脚本、核心头文件、预编译的lib库、dll动态库和pkg-config配置文件,可直接接入VS2017项目,也可借助cmake重新编译,无需从源码手动搭建。glog支持INFO、WARNING、ERROR、FATAL多级日志输出,发生错误时可打印调用堆栈,还提供VLOG细节日志、速率限制及异步处理等能力,并支持自定义日志级别与输出目的地,适合中大型桌面应用和服务端程序的调试与运行监控。文件结构清晰,头文件与二进制库配套齐全,开发者将其链接至工程后即可通过LOG宏记录日志,灵活控制日志落盘位置,显著提升排错效率。已有297人学习下载,是Windows平台上使用glog的轻量实用选择。 最近我在整理手头几个 Windows C++ 服务的日志模块,把之前各自为政的日志逻辑收拢成同一套输出链路。选型时转了一圈,最后落到 glog 上。glog 是 Google 开源的 C++ 日志库,接口简洁、按级别输出、支持条件日志和崩溃处理,Linux 上很多人把它当默认方案。但换到 Windows 上,事情就没那么顺了:踩坑记录少、版本差异大、链库方式也和 Linux 不完全一样。这篇文章就围绕“glog for Windows”这条主线,把我在 Windows 10/11 + MSVC 环境下从编译、接入到排错的全过程写出来,给同样需要在这套平台上落地 glog 的朋友一个可复现的操作参考。
1. glog 在 Windows 下到底能解决什么问题
先说结论:glog 在 Windows 上和 Linux 上能力基本对齐,核心日志功能都能用,不会出现“只能 Linux 用”的阉割情况。真正需要留心的,是构建入口、依赖管理和运行时库匹配这些工程层面的问题。
glog 的核心价值可以分四块看。
第一块是分级日志。它定义了 INFO、WARNING、ERROR、FATAL 四个级别,代码里用LOG(INFO) << "消息";的方式直接把任意类型拼进日志流。这点对 C++ 项目特别友好,不需要像 printf 那样纠结格式化字符,std::string、整数、指针都能直接输出。
第二块是条件日志。有些日志只在特定条件下才有意义,比如调试阶段才打印的细节、错误码不等于 0 时才记录的异常路径。glog 提供了LOG_IF(INFO, condition)、LOG_EVERY_N(ERROR, 100)、VLOG(level)这类宏,把判断直接写进日志调用里,代码看起来干净很多。
第三块是崩溃处理。glog 会在程序收到 SIGSEGV、SIGABRT 这类致命信号时,把当前的堆栈调用信息输出到日志文件里。这一点在 Windows 上对排查内存越界和非法访问特别有价值,很多时候崩溃现场比 gdb 转储更容易定位。
第四块是日志文件切分。默认情况下,glog 会按日志级别生成独立文件,并且按照日期和进程号命名。输出内容超过一定大小后会主动切分,避免单个日志文件无限膨胀。
我用一张小表概括几个最常用的宏:
| 宏 | 作用 |
|---|---|
LOG(INFO)/LOG(WARNING) | 输出指定级别日志 |
LOG_IF(INFO, cond) | 条件为真才输出 |
LOG_EVERY_N(ERROR, 100) | 每 100 次触发输出一次 |
VLOG(n) | 输出详细级别日志,受启动参数-v=n控制 |
DLOG(INFO) | 调试模式才输出,发布模式编译为空 |
CHECK(ptr != nullptr) | 条件失败直接输出 FATAL 并终止程序 |
所以,如果你在 Windows 上需要一个成熟的 C++ 日志库,glog 完全撑得住业务场景。真正的问题集中在后面几个环节:怎么编出来、怎么链进去、踩到 MSVC 的坑怎么爬出来。
2. 构建前的环境准备:工具链和依赖缺口排查
Windows 上构建 glog,本质上就是在 MSVC 工具链下用 CMake 走一遍常规的 configure + build + install 流程。很多教程省略了这一步,直接让读者去下载现成包,结果版本对不上,集成时反而浪费时间。
我建议先把环境补完整,再动手编译。需要的工具有四样:
- Visual Studio 2022(或者 2019),安装时必须勾选“使用 C++ 的桌面开发”工作负载,这一步包含 MSVC 编译器和 Windows SDK。
- CMake 3.16 以上版本,建议用最新稳定版。Windows 下安装 CMake 时选择把
cmake命令加入系统 PATH,后面敲命令省事。 - Git,用于拉取 glog 源码和可能的依赖库源码。
- 如果打算用 vcpkg 构建,还需要先完成 vcpkg 的 bootstrap。
这里有一个容易被忽略的点:MSVC 编译器分 x86 和 x64 两种架构,构建 glog 时必须和最终使用它的项目架构保持一致。现在的业务程序绝大多数是 x64 编译,所以构建 glog 也要明确选择-A x64,否则默认生成的是 Win32 版本,后面链接阶段会报一堆无法解析的外部符号,这个问题我会在排查章节详细说。
依赖方面,较新版本的 glog 默认不强制要求 gflags,CMake 配置时会自动检测。如果你用的是很老的 0.3.x 版本,依赖关系会复杂一些。我的建议是直接用最新 release 版本,避开老版本在 Windows 上的兼容性坑。
环境准备好之后,可以打开“x64 Native Tools Command Prompt for VS 2022”验证一下:
cmake --version cl第一个命令能看到 CMake 版本,第二个命令如果提示识别不了cl,说明 MSVC 编译环境没有正确加载。这一步通过后,构建前的准备就算做完了。
3. 两条构建路线实测:vcpkg 快速版与源码编译版
Windows 上构建 glog 无非两条路:包管理器直接装,或者拉源码自己编。两条路我都跑过,分别说一下效果和适用场景。
3.1 路线 A:vcpkg 一键构建
vcpkg 是微软维护的 C++ 依赖管理工具,安装之后执行一条命令就能拿到编译好的 glog 库。步骤很简单:
git clone https://github.com/microsoft/vcpkg.git cd vcpkg .\bootstrap-vcpkg.bat .\vcpkg install glog:x64-windows等待编译完成后,可以用.\vcpkg integrate install把 vcpkg 的引用信息注册到 Visual Studio 里。这样新建工程或者修改现有工程的属性时,VC++ 目录会自动带上 vcpkg 的头文件和库文件路径,省去手动配置的环节。
vcpkg 的好处是快、省心、版本统一,适合不想折腾构建细节、只希望尽快把日志库跑起来的项目。缺点是安装位置是固定的 vcpkg 目录,如果想换到私有仓库或者统一分发版本,反而多了一层管理工作。
另外要注意,vcpkg 默认构建的是动态链接版本(x64-windows triplet 对应 DLL),如果业务项目想静态链接,需要换成glog:x64-windows-static或者glog:x64-windows-static-md。后两个 triplet 编译时间更长,但产出的库在部署时不用带着 DLL 走。
3.2 路线 B:源码 + CMake 手动编译
如果你像我一样,需要在不同机器上保持完全一致的编译参数,或者要同时产出 Debug 和 Release 两种配置的库,建议走源码编译。
先拉代码:
git clone https://github.com/google/glog.git cd glog然后执行 CMake 配置:
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_INSTALL_PREFIX=D:\local\glog -DBUILD_SHARED_LIBS=ON这里的-G指定生成器,-A x64指定架构,CMAKE_INSTALL_PREFIX是最终库安装路径。BUILD_SHARED_LIBS控制动态库还是静态库,如果选 OFF,则会生成静态库版本。
接着编译并安装:
cmake --build build --config Release cmake --install build执行完,D:\local\glog目录下会生成 include、lib、bin 三个子目录。include 里是头文件,lib 里是glog.lib(导入库),bin 里是glog.dll。
3.3 两条路线的对比
我自己在实际项目中更倾向于源码编译,原因很简单:vcpkg 的全局切换机制在多个项目共用一个环境时容易互相干扰,源码编译则可以把库完整地放到项目自己的第三方目录里,可追溯性更强。但如果你是个人开发、项目规模不大,vcpkg 绝对是最省事的选择。
| 对比项 | vcpkg | 源码编译 |
|---|---|---|
| 上手速度 | 快,一条命令完成 | 中,需要掌握 CMake 参数 |
| 版本控制 | 由 vcpkg 仓库版本决定 | 自己管理版本,更灵活 |
| Debug/Release 区分 | 需要指定不同 triplet | 一次 build 可出多配置 |
| 部署体积 | 默认动态库,需携带 DLL | 可自行选择静态/动态 |
| 对 CI 友好度 | 中,第一次拉取依赖较慢 | 高,构建脚本固定即可复现 |
4. 把 glog 接进现有工程:CMake 示例与初始化陷阱
库构建好了,接下来就是集成到业务代码里。这里我用 CMake 工程做例子,这也是现在 Windows C++ 项目的主流构建方式。
先给一段完整的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.16) project(demo_app LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(glog CONFIG REQUIRED) add_executable(demo_app main.cpp) target_link_libraries(demo_app PRIVATE glog::glog)如果你是用 vcpkg 安装的 glog,并且已经执行过vcpkg integrate install,CMake 能自动找到包;如果用源码编译并按自定义路径安装,则需要提前设置CMAKE_PREFIX_PATH:
cmake -S . -B build -DCMAKE_PREFIX_PATH=D:/local/glog然后在main.cpp里初始化 glog:
#include <glog/logging.h> int main(int argc, char* argv[]) { google::InitGoogleLogging(argv[0]); FLAGS_log_dir = "logs"; FLAGS_alsologtostderr = true; LOG(INFO) << "服务启动"; LOG(WARNING) << "配置缺失,使用默认值"; LOG(ERROR) << "连接失败,重试中"; ... }这段代码里有两个初始化要点。
第一,InitGoogleLogging必须在所有宏调用之前执行,否则 glog 内部的标志系统没有初始化,后面对FLAGS_*的赋值可能不生效。虽然在多数情况下不调用也能跑,但日志输出行为会不稳定,尤其是日志文件命名和崩溃处理逻辑。
第二,FLAGS_log_dir如果不设置,日志会默认输出到当前工作目录。Windows 服务场景下,当前目录可能是 System32,权限不够时日志文件生成失败,程序运行期间没有任何报错。所以务必要在初始化阶段指定对应用户有写权限的目录,并提前创建好。
这段跑通之后,运行目录里会看到类似demo_app.hostname.username.log.INFO.20250101-120000.1234的文件。Windows 下文件名太长时资源管理器显示会截断,但打开内容没有影响。
如果你运行程序时遇到“找不到 glog.dll”,说明动态库没有放到 exe 同级目录,或者系统 PATH 里没有包含 glog 的 bin 目录。最简单的办法是把 DLL 复制到 exe 目录下,或者把安装目录的 bin 路径加入 PATH 环境变量。
5. Windows 下特有的几个坑和一次完整排查过程
Windows 上和 Linux 最大的不同在于 ABI 和运行时库。Linux 下经常“编完就能用”,Windows 下同样的代码,链错库版本、混用运行时库都是家常便饭。这一节我挑三个遇到过的典型问题,其中一个给出完整排查链路。
5.1 运行时提示“0xc000007b”,程序直接起不来
之前在一个 x64 项目里接入 glog,编译链接一次通过,运行时却弹“0xc000007b(应用程序无法正常启动)”。第一反应是系统组件缺失,但查了一圈发现不是,真正原因是 glog 库编成了 32 位版本,而主程序是 64 位。
完整的排查过程是这样的:
- 先用进程监视工具查看 exe 启动时加载的 DLL 列表,发现进程加载了
glog.dll,但地址范围异常。 - 然后用 Dependencies 工具打开 glog.dll,查看其编译架构,显示为 x86。
- 回头检查当时构建 glog 的 CMake 命令,发现没有加
-A x64,默认生成了 Win32 版本。 - 重新执行编译,清理原目录后生成 x64 版本,替换 DLL,程序正常启动。
这个问题的教训是:Windows 下任何第三方库,先确认架构再集成,省去后面一大半问题。
5.2 LNK2038 错误:运行时库不匹配
编译时如果遇到类似这样的错误:
error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'这说明 glog 库和业务项目的运行时库设置不一致。MSVC 下/MD对应动态运行库,/MT对应静态运行库,Debug 和 Release 还会多一个d后缀。glog 构建时用的是/MD,业务项目却配置成/MT,链接器就会直接拒绝。
解决办法有两种。最推荐的是统一使用动态运行库(/MD),这也是 Visual Studio 的默认值。如果你的项目因为特殊原因必须用 /MT,那就需要把 glog 源码也配置成静态运行库重新构建。在 CMake 配置阶段,可以通过-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded来指定。
5.3 FATAL 日志触发后进程直接退出,没有看到详细堆栈
Windows 下LOG(FATAL)默认行为和 Linux 不完全一样。在 Linux 上,FATAL 会触发 SIGABRT,glog 的崩溃处理器能捕获并输出堆栈。Windows 上虽然也有类似机制,但如果在初始化时没有提前设置好输出目录,崩溃现场的堆栈信息可能写到当前工作目录,排查时找不到文件。
我建议在初始化阶段就把FLAGS_log_dir设置为绝对路径,并且确保目录存在。这样即使 FATAL 导致进程退出,日志文件也能稳定落盘。另外一个相关参数是FLAGS_stderrthreshold,把它设为 2(ERROR),可以让 ERROR 和 FATAL 级别的日志同时输出到标准错误流,调试阶段看起来更直观。
5.4 日志内容中文乱码
Windows 控制台默认代码页可能是 GBK,而日志文件内容以 UTF-8 写入,两者不一致会导致终端里中文乱码。这通常不影响文件内容,只是在看输出时影响体验。
要处理的话,可以在程序入口执行SetConsoleOutputCP(CP_UTF8);,把控制台代码页切到 UTF-8。或者直接以文件内容为准,因为日志文件本身是 UTF-8 编码,用 VS Code 打开不会乱码。
6. 生产环境用得上的几个日志参数和优化习惯
glog 最有价值的一点是提供了非常丰富的运行期参数,很多都可以在代码里通过FLAGS_*直接修改,不用重新编译程序。这里列几个我在生产环境里经常用的参数:
| 参数 | 作用 | 我的推荐值 |
|---|---|---|
FLAGS_log_dir | 日志输出目录 | 绝对路径,提前创建 |
FLAGS_minloglevel | 设置最低输出级别 | 默认 0(INFO),上线可调 1 |
FLAGS_logtostderr | 只输出到标准错误 | 调试时 true,生产 false |
FLAGS_stderrthreshold | 同时输出到标准错误的级别阈值 | 2(ERROR) |
FLAGS_max_log_size | 单个日志文件大小上限(MB) | 50 |
FLAGS_v | VLOG 最大详细级别 | 默认 0,需要调试时调大 |
FLAGS_stop_logging_if_full_disk | 磁盘满时停止写日志 | true |
FLAGS_logbufsecs | 日志缓冲刷新间隔(秒) | 默认 30,金融场景调小 |
初始化代码可以这样写:
google::InitGoogleLogging(argv[0]); FLAGS_log_dir = "D:/logs/my_service"; FLAGS_stop_logging_if_full_disk = true; FLAGS_max_log_size = 50; FLAGS_stderrthreshold = 2;除了参数,还有几个使用习惯值得分享。
日志分级要克制。INFO 级别的日志不是写得越多越好,生产环境高并发下,每条 INFO 日志都涉及字符串格式化和内存分配,量大了对性能有实打实的影响。我习惯把高频路径里的日志用VLOG(1)或者LOG_IF(INFO, 条件)包起来,默认关闭,出问题时再通过启动参数打开。
另外,glog 默认会把主机名和用户名写进日志文件名。之前我觉得文件名太长,想过关掉,后来排查跨节点问题时才意识到,这个设计在多实例部署时非常友好,光看文件名就知道日志来自哪台机器、哪个用户。Windows 服务场景下建议保留这个特性。
最后是日志归档。glog 本身只做按大小切分,不做按时间归档。Windows 下部署久了,日志目录会有大量老文件。我通常配合一个简单的定时任务,把超过 7 天的.log.*文件压缩后转移到归档目录,或者直接删除。这个可以用 PowerShell 脚本实现,几行代码就能搞定:
Get-ChildItem -Path "D:/logs/my_service" -Filter "*.log.*" | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-7) } | Remove-Item -ForceWindows 下的 glog 集成并不复杂,但每一步都有它容易踩的细节。把工具链统一、架构确认好、运行时库对齐,这套日志组件就能稳定跑很久。以后如果再遇到 MSVC 下链接失败,先别急着怀疑代码,回头看一眼这三个坑,大概率就找到了。
本文还有配套的精品资源,点击获取