文章目录
glog的编译和使用
概述
想在DLL中打些日志,测试用。
没用起来。
将gflags和gtest都测试编译测试过了,再整一下glog。
笔记
库地址 https://github.com/google/glog.git
迁出到本地后,切到最新的发布版0.7
用 cmake-gui.exe 配置工程
按照自己工程的要求配置,我这里只配置VS2019X64的版本
勾选DLL, 测试,安装路径, 剩下的不选。
产生VS工程。
最后一次用的下面的CMake配置,差别不大。都能用。
打开工程
重新生成解决方案
测试,安装
将release_x64版本也编译了。
将安装结果分别保存为glog_x64_debug/glog_x64_release,归档,供自己的工程用。
测试工程
// testGlogConsole.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "glog/logging.h"
#if (defined(_WIN64) && defined(_DEBUG))
#pragma comment(lib, "glogd.lib")
#elif (defined(_WIN64) && defined(NDEBUG))
#pragma comment(lib, "glog.lib")
#endif
int main(int argc, char** argv)
{
// fLU::FLAGS_max_log_size = 1000;
return 0;
}
glog0.7这个版本是有问题的
已启动重新生成…
1>------ 已启动全部重新生成: 项目: testGlogConsole, 配置: Debug x64 ------
1>testGlogConsole.cpp
1>D:\my_dev\lib\glog_x64_debug\include\glog\logging.h(94,51): warning C4244: “return”: 从“_Rep”转换到“long”,可能丢失数据
1> with
1> [
1> _Rep=__int64
1> ]
1>D:\my_dev\lib\glog_x64_debug\include\glog\logging.h(105,28): warning C4244: “return”: 从“_Rep”转换到“long”,可能丢失数据
1> with
1> [
1> _Rep=__int64
1> ]
1>D:\my_dev\lib\glog_x64_debug\include\glog\logging.h(503,38): error C4996: 'google::CustomPrefixCallback': Use PrefixFormatterCallback instead.
1>已完成生成项目“testGlogConsole.vcxproj”的操作 - 失败。
========== 全部重新生成: 成功 0 个,失败 1 个,跳过 0 个 ==========
是不是只有vs2022才能编译过?
看着不像,是头文件就有问题。手工调整头文件内容,可以编译过,不过那样的话,不知道影响内存布局没有?
确定有问题,就不用这个最新发布版了。
那只能将版本往旧版本方向退,直到找到一个能用的最新版本。
退到了glog-0.6版本,包含上这个库, release/debug x64版本都可以编译过。
但是编译glog-0.6版本时,测试不是都通过,估计和我没有勾选所有选项有关系,不管了。
0.6~0.7版本之间,和还有0.6rc1,0.6rc2,我试试。
试了,glog-v0.6-rc2可以,那就这个版本了。
工程的预处理宏
如果用新建的VS2019X64工程的默认预处理宏,程序编译报错,必须加上GLOG需要的预处理宏。
GLOG_NO_SYMBOLIZE_DETECTION
GLOG_NO_ABBREVIATED_SEVERITIES
GLOG_CUSTOM_PREFIX_SUPPORT
GLOG_STATIC_DEFINE
日志测试代码
将工程根目录下的README.rst转成html(python - rst file to html), 按照官方说的,来具体的日志。
int main(int argc, char** argv) {
google::InitGoogleLogging("myApp");
// 1 > testGlogConsole.obj : error LNK2001 : 无法解析的外部符号 "bool fLB::FLAGS_logtostderr" (? FLAGS_logtostderr@fLB@@3_NA)
FLAGS_logtostderr = false;
LOG(INFO) << "hello glog";
google::ShutdownGoogleLogging();
return 0;
}
设置标志时,找不到DLL定义的全局变量。
用IDA看,是有的。
经过试验,调用glog的工程,要去掉 GLOG_STATIC_DEFINE 的预定义宏才行。
好使的代码
// testGlogConsole.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
// glog预处理宏
/*
WIN32
_WINDOWS
GLOG_NO_SYMBOLIZE_DETECTION
GLOG_NO_ABBREVIATED_SEVERITIES
GLOG_CUSTOM_PREFIX_SUPPORT
// GLOG_STATIC_DEFINE // 不能加这个宏,用DLL导出变量时,编译报错
*/
#include "glog/logging.h"
#include "glog/raw_logging.h"
#if (defined(_WIN64) && defined(_DEBUG))
#pragma comment(lib, "glogd.lib")
#elif (defined(_WIN64) && defined(NDEBUG))
#pragma comment(lib, "glog.lib")
#endif
int main(int argc, char** argv) {
int status = 0;
// 1 > testGlogConsole.obj : error LNK2001 : 无法解析的外部符号 "bool fLB::FLAGS_logtostderr" (? FLAGS_logtostderr@fLB@@3_NA)
// 工程的预编译宏要去掉 GLOG_STATIC_DEFINE
google::InitGoogleLogging("my_app_log");
// FLAGS_max_log_size = 1000; // max log size is 1GB
FLAGS_minloglevel = 0; // log all
FLAGS_logtostderr = false;
FLAGS_logtostdout = false;
FLAGS_stderrthreshold = 999; // don't send log info to stderr
FLAGS_log_prefix = "my_app_log";
FLAGS_minloglevel = 0;
FLAGS_log_dir = "d:\\my_tmp"; // 这里必须是一个存在的文件夹,glog不会自动创建不存在的目录
// 指定日志的前缀名称
google::SetLogFilenameExtension("test_glog.");
// FLAGS_stop_logging_if_full_disk = true;
// google::EnableLogCleaner(1); // // keep the logs for 1 days
LOG(INFO) << "hello glog";
// 只有C++风格的日志好使
// RAW_XLOG不好使
RAW_LOG(INFO, "log info");
RAW_VLOG(3, "status is %i", status);
RAW_LOG(INFO, "show info %d: %s", 1, "info");
RAW_LOG(WARNING, "show warning %d: %s", 1, "warning");
RAW_LOG(ERROR, "show error %d: %s", 1, "error");
RAW_LOG(FATAL, "show fatal info %d: %s", 1, "fatal");
google::ShutdownGoogleLogging();
return 0;
}
效果
备注 - 只有C++风格的日志才好使
通过实验,只有C++风格的日志好使. e.g. LOG(INFO) << “hello glog”;
RAW_LOG 这种日志都打印不出来。
备注 - glog用不到gflag
这次CMake编译没有配置gflag, 编译出来好使。
备注 - glog初始化/反初始化必须成对调用
google::InitGoogleLogging("x");
google::ShutdownGoogleLogging();
glog初始化/反初始化必须成对调用,否则报错。
如果是根据条件进行日志的初始化,需要做个标记,必须已经初始化了,才去反初始化。
在glog没有初始化的情况下,进行日志记录,是不会报错的。
备注 - glog自带初始化标记
if (google::IsGoogleLoggingInitialized()) {
LOG(INFO);
}
}
void my_dll_uninit(void) {
if (google::IsGoogleLoggingInitialized()) {
google::ShutdownGoogleLogging();
}
}
打日志时,最好在已经glog初始化的情况下打日志,否则glog会向stderr打印错误消息。
备注 - 让日志有确定的前缀和后缀名称
void my_dll_init(HMODULE hModule) {
DWORD dw_rc = 0;
bool b_err = false;
TCHAR szBuf[MAX_PATH + 1];
std::string strA;
std::wstring strW;
std::wstring strDir;
std::wstring strExeName;
dw_rc = GetModuleFileName(hModule, szBuf, sizeof(szBuf));
b_err = ((dw_rc <= 0) || (dw_rc >= sizeof(szBuf)));
if (!b_err) {
// GetModuleFileName ok
strW = szBuf;
strDir = strW.substr(0, strW.find_last_of(L"\\") +
1); // D:\my_dev\my_local_git_prj\soft\exp\exp012_MemoryModule\src\MyMemoryDllLoader\x64Debug\
strExeName = strW.substr(strW.find_last_of(L"\\") + 1, -1); // DllForTest_x64Debug.dll
strA = wstring2string(strExeName).data();
// 日志前缀名称, 只能是用常量字符串赋值, 不能是变量赋值, 否则日志名称开头是随机的字符
google::InitGoogleLogging("LsGlog");
strA = '_' + strA;
strA += ".log.txt";
google::SetLogFilenameExtension(strA.data()); // 日志后缀名称
strA = wstring2string(strDir).data();
FLAGS_log_dir = strA.data();
FLAGS_logtostderr = false;
FLAGS_logtostdout = false;
FLAGS_stderrthreshold = 999; // don't send log info to stderr
LOG(INFO) << "glog was init now";
}
if (google::IsGoogleLoggingInitialized()) {
LOG(INFO) << "log begin";
}
}
void my_dll_uninit(void) {
if (google::IsGoogleLoggingInitialized()) {
LOG(INFO) << "log end";
google::ShutdownGoogleLogging();
}
}
产生的日志名称效果
如果查找自己的日志,就很方便了。
e.g. LsGlog*.log.txt
备注 - 日志级别不同,日志内容在不同的日志文件中
如果不是特意想让不同的日志级别在不同文件中,可以都使用一个日志级别。
自己用字符串关键字来表明,然后用现成的日志过滤程序,在一个日志文件中,找不同级别的日志。
DLOG(INFO) << "[info]" << "dwSize =" << dwSize;
DLOG(INFO) << "[warn]" << "dwSize =" << dwSize;
DLOG(INFO) << "[error]" << "dwSize =" << dwSize;
为了更安全,编译时最好替换__FILE_为""
如果使用默认的glog实现,release版也会留下__FILE__, 在IDA中很扎眼。
在编译工程前,全局搜索替换 FILE 为 “”, 编译,测试,安装。
再包含进工程来用时,不影响日志的功能和效果。在IDA中也看不到和__FILE__相关的字符串,安全很多。
备注 - 实时输出日志
glog默认是只有错误等级日志发生时,才会更新日志。
如果都是INFO级别日志,等程序退出后才会更新日志。
如果要实时输出日志,可以设置FLAGS_logbuflevel值为负数。
备注 - 整理glog设置初始化/反初始化实现
void my_glog_init()
{
std::string strA;
std::wstring strW;
// 在内存载入的DLL中无法使用 GetModuleFileName(), 因为载入的DLL地址不在系统记录的DLL载入地址表中, 得不到DLL路径名称
if (true) {
strA = "my_app.exe";
// 日志前缀名称, 只能是用常量字符串赋值, 不能是变量赋值, 否则日志名称开头是随机的字符
google::InitGoogleLogging("LsLog");
strA = '_' + strA;
strA += ".log.txt";
google::SetLogFilenameExtension(strA.data()); // 日志后缀名称
// FLAGS_log_dir = strA.data(); // 如果不设置日志路径, 应该是就在临时目录中
FLAGS_logtostderr = false;
FLAGS_logtostdout = false;
FLAGS_stderrthreshold = 999; // don't send log info to stderr
FLAGS_logbuflevel = -1; // 实时输出
LOG(INFO) << "glog was init now";
}
LOG(INFO) << "log begin";
}
void my_glog_uninit()
{
if (google::IsGoogleLoggingInitialized()) {
LOG(INFO) << "log end";
google::ShutdownGoogleLogging();
}
}
DLL只需要在调用者上初始化一次,否则报错
EXE载入DLL, glog的初始化只需要在EXE中初始化,不需要在DLL中初始化,否则报错。
VS2013环境编译glog
和VS2019环境编译,有点不同。
glog版本0.6.0-rc2
用cmake-gui.exe(3.29)来配置工程。
工程路径 D:\3rd_prj\google\glog
配置工程,有CMake版本警告,去不掉,可能是CMake的bug,不管了
产生工程
有提示,需要关掉VS2013的警告。
重新配置,生成工程。
用VS2019打开工程glog.sln, 工具链还是用VS2013, 不升级工具链。
编译工程
测试工程
安装工程
整理库输出