This commit is contained in:
UnknownObject
2026-06-30 17:49:51 +08:00
commit 292c09619e
200 changed files with 23718 additions and 0 deletions
+704
View File
@@ -0,0 +1,704 @@
#include "ServerLogger.h"
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <fmt/printf.h>
#include <fmt/args.h>
#include <sstream>
#include <iomanip>
// 格式化用的辅助函数
struct DurationView
{
long double value;
const char* unit;
};
inline std::tm ToTm(std::chrono::system_clock::time_point tp)
{
return fmt::localtime(std::chrono::system_clock::to_time_t(tp));
}
inline std::string FormatTime(const std::tm& tm, const std::string& spec)
{
char buf[128] = {};
const char* fmt = spec.empty() ? "%Y-%m-%d %H:%M:%S" : spec.c_str();
std::strftime(buf, sizeof(buf), fmt, &tm);
return buf;
}
inline DurationView NormalizeDuration(std::chrono::nanoseconds ns)
{
long double v = (long double)ns.count();
constexpr long double ns_1 = 1.0L;
constexpr long double us = 1000.0L;
constexpr long double ms = 1000000.0L;
constexpr long double s = 1000000000.0L;
constexpr long double m = 60.0L * s;
constexpr long double h = 60.0L * m;
constexpr long double d = 24.0L * h;
if (v >= d)
return { v / d, "d" };
if (v >= h)
return { v / h, "h" };
if (v >= m)
return { v / m, "m" };
if (v >= s)
return { v / s, "s" };
if (v >= ms)
return { v / ms, "ms" };
if (v >= us)
return { v / us, "us" };
return { v / ns_1, "ns" };
}
// ==================== 1. 锁死在 .cpp 内部的隐藏格式化器 ====================
// 让 ServerLogger.cpp 内部的 fmt 彻底看懂 uns::LogArg 变体
template <>
struct fmt::formatter<uns::LogArg>
{
constexpr auto parse(format_parse_context& ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const uns::LogArg& la, FormatContext& ctx) const
{
return std::visit([&] (auto&& arg) -> decltype(ctx.out())
{
using T = std::decay_t<decltype(arg)>;
// A. 针对容器的运行时展开
if constexpr (std::is_same_v<T, uns::RangeCapturer>)
{
std::vector<uns::LogArg> items;
// 【修正】去掉瞎编的 container_ptr,直接传入 items 容器供内部闭包填充
arg.to_log_args(arg.ptr, items);
fmt::format_to(ctx.out(), "[");
for (size_t i = 0; i < items.size(); ++i)
{
if (i > 0)
fmt::format_to(ctx.out(), ", ");
fmt::format_to(ctx.out(), fmt::runtime("{}"), items[i]);
}
return fmt::format_to(ctx.out(), "]");
}
// B. 针对键值对的运行时展开
else if constexpr (std::is_same_v<T, uns::PairCapturer>)
{
std::vector<uns::LogArg> items;
arg.to_log_args(arg.ptr, items); // 假设 PairCapturer 也是相同的解包逻辑
if (items.size() >= 2)
fmt::format_to(ctx.out(), "{}: {}", items[0], items[1]);
return ctx.out();
}
// C. 针对延迟执行函数的运行时展开
else if constexpr (std::is_same_v<T, uns::FuncCapturer>)
{
// 【注意】请根据你 FuncCapturer 内部实际的求值函数名修改(如 .to_string() 或 .eval())
return fmt::format_to(ctx.out(), "Function{{ptr: {}, type: {}}}", arg.code_ptr, arg.is_closure ? "Closure" : "PureFunc");
}
// D. 时间相关的内容
else if constexpr (std::is_same_v<T, uns::TimeCapturer>)
{
auto out = ctx.out();
try
{
if (arg.mode == uns::TimeMode::Point)
{
std::tm tm = ToTm(arg.tp);
std::string s = FormatTime(tm, arg.format_spec);
return fmt::format_to(out, "{}", s);
}
else if (arg.mode == uns::TimeMode::TMPoint)
{
std::string s = FormatTime(arg._tm, arg.format_spec);
return fmt::format_to(out, "{}", s);
}
else
{
auto norm = NormalizeDuration(arg.duration);
return fmt::format_to(out, "{:.3f}{}", norm.value, norm.unit);
}
}
catch (...)
{
return fmt::format_to(out, "[time_error]");
}
}
// E. 基础原生类型
else
return fmt::format_to(ctx.out(), "{}", arg);
}, la.value);
}
};
std::string uns::toBinary(long number, int bits)
{
bool negitive = (number < 0);
unsigned long positive = (negitive ? -number : number);
return (negitive ? "-" + toBinary(positive, bits) : toBinary(positive, bits));
}
std::string uns::toBinary(std::uint32_t number, int bits)
{
return toBinary(static_cast<unsigned long>(number), bits);
}
std::string uns::toBinary(unsigned long number, int bits)
{
std::string res;
while (true)
{
res += std::to_string(number % 2);
number = number / 2;
if (number == 0)
break;
}
std::reverse(res.begin(), res.end());
while (res.size() < bits)
res = "0" + res;
return "0b" + res;
}
std::string ServerLogger::GenerateLogHeader(uns::ServerLogLevel LogLevel)
{
std::string hstr;
time_t lt = time(NULL);
tm* loctim = localtime(&lt);
char timestr[250] = {};
sprintf(timestr, "{%04d-%02d-%02d %02d:%02d:%02d} ", loctim->tm_year + 1900, loctim->tm_mon + 1, loctim->tm_mday, loctim->tm_hour, loctim->tm_min, loctim->tm_sec);
hstr = timestr;
switch (LogLevel)
{
case uns::llTrace:
hstr += "[TRACE] ";
break;
case uns::llDebug:
hstr += "[DEBUG] ";
break;
case uns::llInfo:
hstr += "[INFO] ";
break;
case uns::llWarning:
hstr += "[WARNING] ";
break;
case uns::llError:
hstr += "[ERROR] ";
break;
case uns::llFatal:
hstr += "[FATAL] ";
break;
default:
hstr += "[UNKNOWN] ";
break;
}
return hstr;
}
std::string ServerLogger::GenerateFileInfo(std::string filename, int line_num)
{
// 使用 stringstream 替代 new/memset/sprintf
std::ostringstream oss;
oss << "(" << filename << " -> LINE=" << line_num << ") ";
return oss.str();
}
void ServerLogger::WriteBatchToOutputs(const std::deque<std::string>& batch)
{
if (batch.empty())
return;
std::time_t now = std::time(nullptr);
for (const auto& item : batch)
{
if (item.empty())
continue;
std::fwrite(item.c_str(), 1, item.size(), stdout);
if (LogStream.is_open())
LogStream << item;
RotateIfNeeded(now, true);
}
std::fflush(stdout);
if (LogStream.is_open())
LogStream.flush();
}
void ServerLogger::WorkerLoop()
{
constexpr std::size_t kMaxBatchCount = 128;
while (WorkerRunning)
{
std::deque<std::string> local_batch;
{
std::unique_lock<std::mutex> lock(QueueMutex);
QueueCV.wait(lock, [this] ()
{
return !LogQueue.empty() || !WorkerRunning;
});
if (!WorkerRunning && LogQueue.empty())
break;
std::size_t count = 0;
while (!LogQueue.empty() && (count < kMaxBatchCount))
{
local_batch.push_back(std::move(LogQueue.front()));
LogQueue.pop_front();
count++;
}
}
if (!local_batch.empty())
WriteBatchToOutputs(local_batch);
}
// 退出前把剩余日志尽量写完
for (;;)
{
std::deque<std::string> local_batch;
{
std::lock_guard<std::mutex> lock(QueueMutex);
if (LogQueue.empty())
break;
std::size_t count = 0;
while (!LogQueue.empty() && (count < kMaxBatchCount))
{
local_batch.push_back(std::move(LogQueue.front()));
LogQueue.pop_front();
count++;
}
}
WriteBatchToOutputs(local_batch);
}
ThreadRunningFlag = false;
}
std::string ServerLogger::MakeRotatedFileName(const std::string& base, std::time_t t, int osl_index)
{
tm* loctim = std::localtime(&t);
std::ostringstream oss;
oss << base;
if (RotatePeriod == uns::RP_Hourly)
oss << "_" << std::setw(4) << (loctim->tm_year + 1900) << std::setw(2) << std::setfill('0') << (loctim->tm_mon + 1) << std::setw(2) << std::setfill('0') << loctim->tm_mday << "_" << std::setw(2) << std::setfill('0') << loctim->tm_hour;
else if (RotatePeriod == uns::RP_Daily)
oss << "_" << std::setw(4) << (loctim->tm_year + 1900) << std::setw(2) << std::setfill('0') << (loctim->tm_mon + 1) << std::setw(2) << std::setfill('0') << loctim->tm_mday;
if (osl_index > 0)
oss << "_OSL" << osl_index;
oss << ".log";
return oss.str();
}
void ServerLogger::RotateIfNeeded(std::time_t now, bool check_size_after_write)
{
//控制台模式不进行轮转
if (LogFileName.empty())
return;
// 时间轮转优先:若 period 发生变化则重建文件并重置 OSL 索引
if (RotatePeriod != uns::RP_None)
{
std::time_t new_period_start = (RotatePeriod == uns::RP_Hourly ? (now / 3600) * 3600 : (now / 86400) * 86400);
if (new_period_start != CurrentFilePeriodStart)
{
// 时间轮转:关闭流并打开新的 period 文件,重置 OSL 索引
if (LogStream.is_open())
{
LogStream.flush();
LogStream.close();
}
CurrentOSLIndex = 0;
std::string actual_file = MakeRotatedFileName(LogFileName.empty() ? "UNSC" : LogFileName, now, CurrentOSLIndex);
LogStream.open(actual_file.c_str(), std::ios::out | std::ios::app);
CurrentFilePeriodStart = new_period_start;
// 完成时间轮转后不做 size 检查(新文件刚创建,肯定小于阈值)
return;
}
}
// 如果要求检查大小(一般在写入之后调用),并且 MaxFileSizeBytes > 0,则进行大小轮转
if (check_size_after_write && (MaxFileSizeBytes > 0) && LogStream.is_open())
{
// 尝试使用 tellp 获取当前文件位置
std::streampos pos = LogStream.tellp();
std::size_t filesize = 0;
if (pos != static_cast<std::streampos>(-1))
filesize = static_cast<std::size_t>(pos);
else
{
// 备用:通过打开文件获取大小
// 构造当前文件名(基于当前 period 和索引)
std::string current_file = MakeRotatedFileName(LogFileName.empty() ? "UNSC" : LogFileName, now, CurrentOSLIndex);
std::ifstream ifs(current_file.c_str(), std::ios::binary | std::ios::ate);
if (ifs.is_open())
{
filesize = static_cast<std::size_t>(ifs.tellg());
ifs.close();
}
}
if (filesize >= MaxFileSizeBytes)
{
// 增加 OSL 索引并打开新文件
if (LogStream.is_open())
{
LogStream.flush();
LogStream.close();
}
CurrentOSLIndex++;
std::string new_file = MakeRotatedFileName(LogFileName.empty() ? "UNSC" : LogFileName, now, CurrentOSLIndex);
LogStream.open(new_file.c_str(), std::ios::out | std::ios::app);
}
}
}
inline std::string RewriteFormatString(const std::string& real_format, const uns::LogArg* args, size_t count, fmt::dynamic_format_arg_store<fmt::format_context>& store)
{
std::string out;
out.reserve(real_format.size());
size_t arg_index = 0;
for (size_t i = 0; i < real_format.size();)
{
char c = real_format[i];
// escaped {{
if ((c == '{') && ((i + 1) < real_format.size()) && (real_format[i + 1] == '{'))
{
out += '{';
i += 2;
continue;
}
// escaped }}
if ((c == '}') && ((i + 1) < real_format.size()) && (real_format[i + 1] == '}'))
{
out += '}';
i += 2;
continue;
}
if (c == '{')
{
size_t j = i + 1;
while ((j < real_format.size()) && (real_format[j] != '}'))
++j;
if (j >= real_format.size())
{
out += '{';
++i;
continue;
}
std::string_view inside(real_format.data() + i + 1, j - i - 1);
if (arg_index < count)
{
uns::LogArg arg = args[arg_index];
// 只处理 time spec
if (!inside.empty() && (inside[0] == ':'))
{
if (std::holds_alternative<uns::TimeCapturer>(arg.value))
{
auto& tc = std::get<uns::TimeCapturer>(arg.value);
tc.format_spec = std::string(inside.substr(1));
arg.value = tc;
store.push_back(arg);
}
else
store.push_back(args[arg_index]);
}
else
store.push_back(args[arg_index]);
}
out += "{}";
++arg_index;
i = j + 1;
continue;
}
out += c;
++i;
}
return out;
}
void ServerLogger::LogImpl(uns::ServerLogLevel level, const std::string& format, const uns::LogArg* args, size_t count)
{
std::string formatted;
try
{
if (count == 0)
formatted = format;
else
{
fmt::dynamic_format_arg_store<fmt::basic_printf_context<char>> store;
for (size_t i = 0; i < count; ++i)
{
std::visit([&] (auto&& val)
{
using DeT = std::decay_t<decltype(val)>;
if constexpr (std::is_arithmetic_v<DeT> || std::is_convertible_v<DeT, fmt::string_view> || std::is_pointer_v<DeT>)
store.push_back(val);
else // 【修正】这里必须传入 args[i](即 LogArg 本身) 这样才能正确触发上面我们写好的 fmt::formatter<uns::LogArg> 路由
store.push_back(fmt::format("{}", args[i]));
}, args[i].value);
}
// 【修正】显式提供模板参数 <char>,彻底解决 std::string 导致的推导失败
formatted = fmt::vsprintf<char>(format, store);
}
}
catch (const fmt::format_error& e)
{
formatted = std::string("<< log format error: ") + e.what() + " >> " + format;
}
std::string logstr = GenerateLogHeader(level);
logstr += formatted;
logstr += "\n";
std::unique_lock<std::mutex> lock(QueueMutex);
LogQueue.push_back(logstr);
lock.unlock();
QueueCV.notify_one();
}
void ServerLogger::LogFImpl(uns::ServerLogLevel level, const std::string& filename, int line_num, const std::string& format, const uns::LogArg* args, size_t count)
{
std::string formatted;
std::string real_format = GenerateFileInfo(filename, line_num) + format;
try
{
if (count == 0)
formatted = real_format;
else
{
fmt::dynamic_format_arg_store<fmt::basic_printf_context<char>> store;
for (size_t i = 0; i < count; ++i)
{
std::visit([&] (auto&& val)
{
using DeT = std::decay_t<decltype(val)>;
if constexpr (std::is_arithmetic_v<DeT> || std::is_convertible_v<DeT, fmt::string_view> || std::is_pointer_v<DeT>)
store.push_back(val);
else
store.push_back(fmt::format("{}", args[i]));
}, args[i].value);
}
// 【修正】显式提供模板参数 <char>
formatted = fmt::vsprintf<char>(real_format, store);
}
}
catch (const fmt::format_error& e)
{
formatted = std::string("<< log format error: ") + e.what() + " >> " + real_format;
}
std::string logstr = GenerateLogHeader(level);
logstr += formatted;
logstr += "\n";
std::unique_lock<std::mutex> lock(QueueMutex);
LogQueue.push_back(logstr);
lock.unlock();
QueueCV.notify_one();
}
void ServerLogger::LogFMTImpl(uns::ServerLogLevel level, const std::string& format, const uns::LogArg* args, size_t count)
{
std::string formatted;
try
{
if (count == 0)
formatted = format;
else
{
// 现代 {} 风格:动态包装擦除后的类型数组
fmt::dynamic_format_arg_store<fmt::format_context> store;
std::string rewrite_format = RewriteFormatString(format, args, count, store);
formatted = fmt::vformat(rewrite_format, store);
}
}
catch (const fmt::format_error& e)
{
formatted = std::string("<< log format error: ") + e.what() + " >> " + format;
}
std::string logstr = GenerateLogHeader(level);
logstr += formatted;
logstr += "\n";
std::unique_lock<std::mutex> lock(QueueMutex);
LogQueue.push_back(logstr);
lock.unlock();
QueueCV.notify_one();
}
void ServerLogger::LogFMT_FImpl(uns::ServerLogLevel level, const std::string& filename, int line_num, const std::string& format, const uns::LogArg* args, size_t count)
{
std::string formatted;
std::string real_format = GenerateFileInfo(filename, line_num) + format;
try
{
if (count == 0)
formatted = real_format;
else
{
fmt::dynamic_format_arg_store<fmt::format_context> store;
std::string rewrite_format = RewriteFormatString(real_format, args, count, store);
formatted = fmt::vformat(rewrite_format, store);
}
}
catch (const fmt::format_error& e)
{
formatted = std::string("<< log format error: ") + e.what() + " >> " + real_format;
}
std::string logstr = GenerateLogHeader(level);
logstr += formatted;
logstr += "\n";
std::unique_lock<std::mutex> lock(QueueMutex);
LogQueue.push_back(logstr);
lock.unlock();
QueueCV.notify_one();
}
ServerLogger::ServerLogger()
{
//Default log off
//InitLogger(uns::llOff);
CurrentLevel = uns::llOff;
WorkerRunning = false;
RotatePeriod = uns::RP_None;
CurrentFilePeriodStart = 0;
MaxFileSizeBytes = 50 * 1024 * 1024;
CurrentOSLIndex = 0;
return;
}
ServerLogger::ServerLogger(uns::ServerLogLevel log_level, std::string file, uns::LogRotationPeriod rotation, std::size_t max_bytes)
{
InitLogger(log_level, file, rotation, max_bytes);
CurrentLevel = log_level;
return;
}
ServerLogger::~ServerLogger()
{
// 优雅关闭工作线程并刷新
CloseLog();
return;
}
bool ServerLogger::InitLogger(uns::ServerLogLevel log_level, const std::string& file, uns::LogRotationPeriod rotation, std::size_t max_bytes)
{
WorkerRunning = false;
RotatePeriod = rotation;
CurrentFilePeriodStart = 0;
CurrentLevel = log_level;
CurrentOSLIndex = 0;
MaxFileSizeBytes = max_bytes; // 强制开启大小轮转,默认为 50MiB(可由调用者覆盖)
LogFileName = file;
//初始化轮转
if (!LogFileName.empty())
{
time_t now = time(nullptr);
//取整点
CurrentFilePeriodStart = (RotatePeriod == uns::RP_Hourly ? ((now / 3600) * 3600) : (RotatePeriod == uns::RP_Daily ? ((now / 86400) * 86400) : now));
std::string actual_file = MakeRotatedFileName(LogFileName.empty() ? "UNSC" : LogFileName, now, CurrentOSLIndex);
LogStream.open(actual_file.c_str(), std::ios::out | std::ios::app);
// 如果当前文件已超过大小限制,生成下一个 OSL 文件
if (LogStream.is_open())
{
// 尝试获取当前位置(文件大小),并在必要时轮转
std::streampos pos = LogStream.tellp();
std::size_t filesize = 0;
if (pos != static_cast<std::streampos>(-1))
filesize = static_cast<std::size_t>(pos);
else
{
// 备用方案:用 ifstream 直接获取文件大小
std::ifstream ifs(actual_file.c_str(), std::ios::binary | std::ios::ate);
if (ifs.is_open())
{
filesize = static_cast<std::size_t>(ifs.tellg());
ifs.close();
}
}
if (filesize >= MaxFileSizeBytes)
{
// increase osl index and open new file
LogStream.close();
CurrentOSLIndex = 1;
actual_file = MakeRotatedFileName(LogFileName.empty() ? "UNSC" : LogFileName, now, CurrentOSLIndex);
LogStream.open(actual_file.c_str(), std::ios::out | std::ios::app);
}
}
}
//启动日志线程
bool started = true;
if (!WorkerRunning)
{
WorkerRunning = true;
try
{
WorkerThread = std::thread(&ServerLogger::WorkerLoop, this);
}
catch (...)
{
WorkerRunning = false;
started = false;
}
}
return ((LogStream.is_open() || LogFileName.empty()) && started);
}
void ServerLogger::CloseLog()
{
//关闭工作线程
WorkerRunning = false;
QueueCV.notify_all();
if (WorkerThread.joinable())
WorkerThread.join();
while (ThreadRunningFlag)
std::this_thread::sleep_for(std::chrono::milliseconds(5));
//关闭文件流
if (LogStream.is_open())
LogStream.close();
CurrentLevel = uns::llOff;
}
void ServerLogger::DisableLog()
{
CurrentLevel = uns::llOff;
}
void ServerLogger::FlushLogBuffer()
{
//触发写入
QueueCV.notify_all();
//等待队列清空
while (true)
{
std::unique_lock<std::mutex> lock(QueueMutex);
if (LogQueue.empty())
break;
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
if (LogStream.is_open())
LogStream.flush();
}
void ServerLogger::EnableLog(uns::ServerLogLevel level)
{
CurrentLevel = (level == uns::llOff ? uns::llAll : level);
}
ServerLogger GlobalServerLogger;