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目测更好。在项目中应用时,需要自己封装类进行使用。