C++ glog使用教程与代码演示

glog源码编译介绍

glog repo: https://github.com/google/glog

clone代码之后,可以使用CMake进行编译,
在这里插入图片描述
使用vs2019编译后,会产生include lib dll, 在项目中包含之后就可以使用了。

也可以直接使用vcpkg进行安装
在这里插入图片描述

glog的日志级别

glog 支持四种日志级别,INFO、WARNING、ERROR和FATAL。不同级别的日志信息会输出到不同文件,同时高级别的日志也会写入到低级别中。默认情况下,在打印完FATAL日志之后,程序将会终止。ERROR和FATAL的日志除了会写到日志中,还会输出到 stderr。

enum SeverityLevel
{
  google::INFO = 0,
  google::WARNING = 1,
  google::ERROR = 2,
  google::FATAL = 3,
};

日志格式

日志格式:I+日期 时:分:秒.微秒 线程号 源文件名:行数] 信息

设置输出到指定目录

// 设置特定严重级别的日志的输出目录和前缀
// 第一个参数为日志级别,第二个参数表示输出目录及日志文件名前缀
google::SetLogDestination(google::GLOG_INFO, "D:/glog_path/INFO_");  
google::SetLogDestination(google::GLOG_WARNING, "D:/glog_path/WARNING_");
google::SetLogDestination(google::GLOG_ERROR, "D:/glog_path/ERROR_");
google::SetLogDestination(google::GLOG_FATAL, "D:/glog_path/FATAL_");

//在日志文件名中级别后添加一个扩展名
google::SetLogFilenameExtension(".log");  

glog C++类封装示例代码

下面提供一种glog的C++类封装
GLogHelper.h

/*

glog封装类

使用方法

    # 基本用法
        #include "GLogHelper.h"

        std::wstring exePath = GetExecutablePath();
	    std::string  strLogPath = wstringTostring(exePath) + "/Log/agent_" + GenerateLogFileName();

	    GLogHelper& glogHelper = GLogHelper::Instance();
	    glogHelper.InitLog(true, strLogPath);

        LOG_INFO << "This is a INFO message.";
        LOG_WARNING << "This is a WARNING message.";
        LOG_ERROR << "This is a ERROR message.";

        std::string str1 = "test std::string log";
        LOG_INFO << str1;

        int age = 20;
        LOG_INFO << "age = " << age;
    
    # 调整log输出等级
        // 设置日志等级
	    FLAGS_minloglevel = 0; // 0, 1, 2 对应 INFO  WARNING ERROR
*/

#define GLOG_NO_ABBREVIATED_SEVERITIES

#pragma once
#include <glog/logging.h>
#include "CustomLogSink.h"

#define LOG_INFO    LOG(INFO)
#define LOG_WARNING LOG(WARNING)
#define LOG_ERROR   LOG(ERROR)

class GLogHelper
{
private:
	GLogHelper();

public:
    GLogHelper(const GLogHelper&) = delete;
    GLogHelper& operator=(const GLogHelper&) = delete;

    static GLogHelper& Instance() {
        static GLogHelper instance;
        return instance;
    }

	~GLogHelper();

    // singleLog: true每天生成一个log, false按照运行时间点生成log
    // log_fileName: log文件名
    void InitLog(bool singleLog = true, const std::string& log_fileName = "");

private:
    CustomLogSink* custom_sink;
};

GLogHelper.cpp

#include "GLogHelper.h"
#include <windows.h>
#include <direct.h>
#include <io.h>
#include <string>


GLogHelper::GLogHelper()
{
	
}

GLogHelper::~GLogHelper()
{
	google::RemoveLogSink(custom_sink);
	delete custom_sink;

	// 关闭glog
	google::ShutdownGoogleLogging();
}

void GLogHelper::InitLog(bool singleLog, const std::string& log_fileName)
{
	if (log_fileName.empty())
		return;

	// 查找最后一个反斜杠的位置,它之前的就是目录
	std::string::size_type pos = std::string(log_fileName).find_last_of("\\/");
	std::string _log_path = std::string(log_fileName).substr(0, pos);

	if (_access(_log_path.c_str(), 0) == -1)
	{
		_mkdir(_log_path.c_str());
	}

	google::InitGoogleLogging("");

	// 设置日志等级
	FLAGS_minloglevel = 0; // 0, 1, 2 对应 INFO  WARNING ERROR

	// 设置单个日志文件的最大大小为1GB
	FLAGS_max_log_size = 1000; // 单位为MB

	// 禁用日志回滚
	FLAGS_stop_logging_if_full_disk = true;

	if (singleLog)
	{
		custom_sink = new CustomLogSink(log_fileName);
		google::AddLogSink(custom_sink);
	}
	else
	{
		std::string info_log_path = _log_path + "/INFO_";
		std::string warn_log_path = _log_path + "/WARNING_";
		std::string error_log_path = _log_path + "/ERROR_";

		// 设置特定严重级别的日志的输出目录和前缀
		// 第一个参数为日志级别,第二个参数表示输出目录及日志文件名前缀
		google::SetLogDestination(google::GLOG_INFO, info_log_path.c_str());
		google::SetLogDestination(google::GLOG_WARNING, warn_log_path.c_str());
		google::SetLogDestination(google::GLOG_ERROR, error_log_path.c_str());
	}
}

在上面的代码中,我提供了两种记录log的方式,当singleLog为true时,每天只生成一个log文件,所有级别的日志也在一个文件中;当当singleLog为false时, 将在程序启动时创建新的log文件,每种类型的log单独一个文件

CustomLogSink.h

#define GLOG_NO_ABBREVIATED_SEVERITIES

#pragma once

#include <glog/logging.h>
#include <fstream>
#include <string>
#include <mutex>

class CustomLogSink : public google::LogSink {
public:
    CustomLogSink(const std::string& base_filename);

    void send(google::LogSeverity severity, const char* full_filename,
        const char* base_filename, int line,
        const struct ::tm* tm_time,
        const char* message, size_t message_len) override;

private:
    void UpdateLogFile();
    std::string GetCurrentTimeWithMilliseconds();

private:
    std::ofstream log_file_;
    std::string base_filename_;
    std::mutex mutex_;
    int last_day_ = -1;
};

CustomLogSink.cpp

#include "CustomLogSink.h"
#include <sstream>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <string>
#include <codecvt>

CustomLogSink::CustomLogSink(const std::string& base_filename) : base_filename_(base_filename) {
    UpdateLogFile();
}

void CustomLogSink::send(google::LogSeverity severity, const char* full_filename,
    const char* base_filename, int line,
    const struct ::tm* tm_time,
    const char* message, size_t message_len) 
{
    std::lock_guard<std::mutex> lock(mutex_);

    // 检查是否需要更新日志文件
    UpdateLogFile();

    // 写入日志消息
    log_file_ << "[" << google::GetLogSeverityName(severity)
        << "] " << GetCurrentTimeWithMilliseconds()
        << ": " << message;
}

void CustomLogSink::UpdateLogFile() {
    time_t now = time(nullptr);
    struct tm now_tm;
    localtime_s(&now_tm, &now);

    if (now_tm.tm_mday != last_day_) {
        if (log_file_.is_open()) {
            log_file_.close();
        }

        std::string log_filename = base_filename_;
        log_file_.open(log_filename, std::ios_base::app);
        last_day_ = now_tm.tm_mday;
    }
}

std::string CustomLogSink::GetCurrentTimeWithMilliseconds() {
    // 获取当前系统时间点
    auto now = std::chrono::system_clock::now();

    // 转换为time_t时间类型
    auto now_as_time_t = std::chrono::system_clock::to_time_t(now);

    // 转换为tm结构
    struct tm timeinfo;
    localtime_s(&timeinfo, &now_as_time_t); // 使用localtime_s为了线程安全

    // 获取当前时间的毫秒部分
    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()) % 1000;

    // 使用wstringstream进行格式化
    std::wstringstream wss;
    wss << std::put_time(&timeinfo, L"%Y-%m-%d %H:%M:%S")
        << L'.' << std::setfill(L'0') << std::setw(3) << milliseconds.count();

    std::wstring wstr = wss.str();

    std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    return converter.to_bytes(wstr);
}

main测试glog的使用

/*

测试glog

*/

#include <iostream>
#include "GLogHelper.h"
#include <locale>
#include <codecvt>
#include <ctime>
#include <iomanip>

std::string GenerateLogFileName() {
	// 获取当前时间
	std::time_t now = std::time(nullptr);
	std::tm* now_tm = std::localtime(&now);

	// 生成基于日期的日志文件名
	std::ostringstream oss;
	oss << (now_tm->tm_year + 1900) << "-"
		<< std::setfill('0') << std::setw(2) << (now_tm->tm_mon + 1) << "-"
		<< std::setfill('0') << std::setw(2) << now_tm->tm_mday << ".log";

	return oss.str();
}

// 获取exe所在的路径
std::wstring GetExecutablePath() {
	wchar_t path[MAX_PATH] = { 0 };
	HMODULE hModule = GetModuleHandleW(NULL);

	if (hModule != NULL) {
		if (GetModuleFileNameW(hModule, path, MAX_PATH) > 0) {
			// 查找最后一个反斜杠的位置,它之前的就是目录
			std::wstring::size_type pos = std::wstring(path).find_last_of(L"\\/");
			return std::wstring(path).substr(0, pos);
		}
	}

	return std::wstring();
}

std::string wstringTostring(const std::wstring& wideStr) {
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.to_bytes(wideStr);
}

int main()
{
	std::cout << "test glog\n";

	std::wstring exePath = GetExecutablePath();
	std::string  strLogPath = wstringTostring(exePath) + "/Log/agent_" + GenerateLogFileName();

	GLogHelper& glogHelper = GLogHelper::Instance();
	glogHelper.InitLog(true, strLogPath);

	LOG_INFO << "This is a INFO message.";
	LOG_WARNING << "This is a WARNING message.";
	LOG_ERROR << "This is a ERROR message.";

	std::string str1 = "test std::string log";
	LOG_INFO << str1;

	int age = 20;
	LOG_INFO << "age = " << age;

	return 0;
}

在项目中可以根据需求自行调整。

相比log4cplus, glog目测更好。在项目中应用时,需要自己封装类进行使用。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

令狐掌门

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值