glog的编译和使用

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, 不升级工具链。
编译工程
在这里插入图片描述
测试工程
在这里插入图片描述
安装工程
在这里插入图片描述
整理库输出
在这里插入图片描述

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值