更新:1、修改日志组件,使用spdlog日志库;

Signed-off-by: waiwaylee <waiwaylee@foxmail.com>
This commit is contained in:
2026-10-28 13:43:29 +08:00
parent 7e4cb2922d
commit 24ce1e6dbf
130 changed files with 27635 additions and 187 deletions
+136 -94
View File
@@ -1,32 +1,30 @@
#include "rdp_log.h"
#include "parameters.h"
#include <fstream>
#include <sstream>
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include <time.h>
#include <direct.h>
#include <io.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_sinks.h>
namespace
{
//日志模块内部状态:日志文件流 + 重定向前 std::cout 的原始缓冲区
//日志行格式:与旧版 [时间戳][文件:行号] 风格一致,另加 spdlog 级别
const char *const kPattern = "[%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] %v";
//日志模块内部状态:默认 logger(标准输出 + 日志文件)与当前日志文件路径
struct RdpLogState
{
std::ofstream file; //日志文件输出流
std::streambuf *original_buf; //重定向前 std::cout 的原始缓冲区
bool enabled; //是否已成功重定向到日志文件
std::shared_ptr<spdlog::logger> logger; //默认 logger(含标准输出 sink,成功时另含文件 sink)
std::string log_path; //当前日志文件全路径(降级为仅标准输出时为空)
bool initialized; //是否已初始化(含文件创建失败时的降级初始化)
RdpLogState() : original_buf(0), enabled(false) {}
~RdpLogState()
{
//进程退出兜底:若宿主进程未调用 Data_Process_Factory::Destroy(),
//此处恢复 std::cout,避免其仍指向即将析构的日志文件流缓冲区。
if (enabled && original_buf)
{
std::cout.rdbuf(original_buf);
enabled = false;
}
}
RdpLogState() : initialized(false) {}
};
RdpLogState &State()
@@ -35,36 +33,78 @@ namespace
return s;
}
//当前本地时间字符串,格式 "YYYY-MM-DD HH:MM:SS"
std::string CurrentTime()
//创建日志目录(目录已存在时 _mkdir 返回 EEXIST,忽略;逻辑与原 rdp_log/rdp_record 一致)
void EnsureDir(const std::string &dir_with_separator)
{
char buf[32] = {0};
time_t now = time(NULL);
std::string dir = dir_with_separator;
while (dir.size() > 0 && (dir[dir.size() - 1] == '\\' || dir[dir.size() - 1] == '/'))
{
dir.erase(dir.size() - 1);
}
if (dir.size() > 0)
{
_mkdir(dir.c_str());
}
}
//当前本地时间字符串,格式 "YYYYMMDD_HHMMSS"
bool TimeStamp(char *buf, size_t size)
{
time_t now = time(NULL);
struct tm local;
if (localtime_s(&local, &now) != 0)
{
return std::string();
return false;
}
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &local);
return std::string(buf);
return strftime(buf, size, "%Y%m%d_%H%M%S", &local) != 0;
}
//提取纯文件名(去掉路径前缀),日志前缀中只显示 文件名:行号
const char *FileName(const char *path)
//生成日志文件路径:RDP_LOG_DIR + rdp_YYYYMMDD_HHMMSS.log;
//同一秒内文件已存在(Destroy→GetB 重连、同目录多进程启动)时追加 _1~_999 后缀,不复用同一文件
bool MakeLogPath(std::string *path)
{
if (path == 0)
char stamp[32] = {0};
if (!TimeStamp(stamp, sizeof(stamp)))
{
return "";
return false;
}
const char *base = path;
for (const char *p = path; *p != '\0'; ++p)
const std::string base = std::string(RDP_LOG_DIR) + "rdp_" + stamp;
for (int suffix = 0; suffix < 1000; ++suffix)
{
if (*p == '\\' || *p == '/')
std::string candidate = base;
if (suffix > 0)
{
base = p + 1;
candidate += "_" + std::to_string(suffix);
}
candidate += ".log";
if (_access(candidate.c_str(), 0) != 0)
{
*path = candidate;
return true;
}
}
return base;
return false;
}
//初始化 logger:统一日志格式,运行期级别放开到 trace(实际输出级别由编译期
//SPDLOG_ACTIVE_LEVEL 过滤),所有级别逐条 flush(日志量小,且调试场景要求异常退出也尽量不丢日志)
void ConfigureLogger(const std::shared_ptr<spdlog::logger> &logger)
{
logger->set_pattern(kPattern);
logger->set_level(spdlog::level::trace);
logger->flush_on(spdlog::level::trace);
spdlog::set_default_logger(logger);
}
//仅标准输出 sink 的降级 logger(日志文件创建失败时使用)
std::shared_ptr<spdlog::logger> MakeStdoutLogger()
{
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
std::shared_ptr<spdlog::logger> logger =
std::make_shared<spdlog::logger>("rdp", sinks.begin(), sinks.end());
ConfigureLogger(logger);
return logger;
}
}
@@ -73,82 +113,84 @@ namespace rdp_log
bool Init()
{
RdpLogState &st = State();
if (st.enabled)
if (st.initialized)
{
return true; //已经重定向,避免重复初始化
return true; //已经初始化,避免重复创建日志文件
}
#ifdef RDP_LOG_ENABLE
//创建日志目录(目录已存在时 _mkdir 返回 EEXIST,忽略)
std::string log_dir = RDP_LOG_DIR;
while (log_dir.size() > 0 &&
(log_dir[log_dir.size() - 1] == '\\' || log_dir[log_dir.size() - 1] == '/'))
{
log_dir.erase(log_dir.size() - 1);
}
if (log_dir.size() > 0)
{
_mkdir(log_dir.c_str());
}
//按当前日期+时间生成日志文件名:rdp_YYYYMMDD_HHMMSS.log
char time_buf[32] = {0};
time_t now = time(NULL);
struct tm local;
if (localtime_s(&local, &now) != 0)
{
return false;
}
strftime(time_buf, sizeof(time_buf), "%Y%m%d_%H%M%S", &local);
std::string log_path = RDP_LOG_DIR;
log_path += "rdp_";
log_path += time_buf;
log_path += ".log";
st.file.open(log_path.c_str(), std::ios::out | std::ios::trunc);
if (!st.file.is_open())
{
//日志文件打开失败(目录不可写等):保持控制台输出,不做重定向
std::cout << "[rdp_log] cannot open log file: " << log_path << std::endl;
return false;
}
//用 rdbuf() 将 std::cout 的流缓冲区替换为日志文件输出流
st.original_buf = std::cout.rdbuf();
std::cout.rdbuf(st.file.rdbuf());
st.enabled = true;
//重定向成功后写入起始标记(该行已写入日志文件)
std::cout << prefix(__FILE__, __LINE__)
<< "rdp_log enabled, log file: " << log_path << std::endl;
return true;
#else
//日志开关关闭:不重定向,日志仍输出到标准输出
#if SPDLOG_ACTIVE_LEVEL > SPDLOG_LEVEL_CRITICAL
//编译期关闭日志(RDP_LOG_LEVEL=OFF):不初始化 logger、不创建日志文件
return false;
#else
try
{
EnsureDir(RDP_LOG_DIR);
std::string log_path;
if (!MakeLogPath(&log_path))
{
throw spdlog::spdlog_ex("no usable log file name in RDP_LOG_DIR");
}
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>());
//truncate=false:日志文件名已保证不存在(极端并发下万一被抢占则追加而非覆盖已有内容)
sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_path, false));
std::shared_ptr<spdlog::logger> logger =
std::make_shared<spdlog::logger>("rdp", sinks.begin(), sinks.end());
ConfigureLogger(logger);
//spdlog 内部错误(如日志文件写失败)打到标准错误,不影响雷达数据处理
spdlog::set_error_handler([](const std::string &msg) {
std::fprintf(stderr, "[rdp_log] spdlog error: %s\n", msg.c_str());
});
st.logger = logger;
st.log_path = log_path;
st.initialized = true;
RDP_LOG_INFO("rdp_log enabled, log file: {}", log_path);
return true;
}
catch (const std::exception &e)
{
//日志文件创建失败(目录不可写等):降级为仅标准输出,不中断雷达数据处理
try
{
st.logger = MakeStdoutLogger();
st.log_path.clear();
st.initialized = true;
std::fprintf(stderr, "[rdp_log] cannot create log file, fallback to stdout only: %s\n",
e.what());
}
catch (...)
{
std::fprintf(stderr, "[rdp_log] logger init failed\n");
}
return false;
}
#endif
}
void Shutdown()
{
RdpLogState &st = State();
if (!st.enabled)
if (!st.initialized || !st.logger)
{
return;
}
//写入结束标记后刷新、恢复 std::cout 并关闭日志文件
std::cout << prefix(__FILE__, __LINE__) << "rdp_log shutdown" << std::endl;
st.file.flush();
std::cout.rdbuf(st.original_buf);
st.enabled = false;
st.file.close();
RDP_LOG_INFO("rdp_log shutdown");
//flush 并释放默认 logger(随之关闭日志文件)
spdlog::shutdown();
st.logger.reset();
st.log_path.clear();
st.initialized = false;
}
std::string prefix(const char *file, int line)
std::string log_file_path()
{
std::ostringstream oss;
oss << "[" << CurrentTime() << "][" << FileName(file) << ":" << line << "] ";
return oss.str();
return State().log_path;
}
}