Files
UNSWebServerCore_LinuxSO/ServerLogger.cpp
T

919 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ServerLogger.h"
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <fmt/printf.h>
#include <fmt/args.h>
#include <sstream>
#include <iomanip>
#include <array>
// 格式化用的辅助函数
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;
}
bool StartsWith(std::string_view str, std::string_view prefix)
{
if (str.size() < prefix.size())
return false;
return str.compare(0, prefix.size(), prefix) == 0;
}
bool IsSizeUnit(std::string_view str)
{
if (str == "bit")
return true;
if (str.empty())
return false;
char last = str.back();
return last == 'b' || last == 'B';
}
bool IsNonNegativeInteger(std::string_view str, int& value)
{
if (str.empty())
return false;
int result = 0;
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
if (ec != std::errc() || ptr != str.data() + str.size())
return false;
if (result < 0)
return false;
value = result;
return true;
}
std::pair<std::string, int> ParseSizeFormat(std::string_view input)
{
constexpr std::pair<std::string_view, int> default_value = { "B", 2 };
if (!StartsWith(input, "siz"))
return { std::string(default_value.first), default_value.second };
std::string_view body = input.substr(3);
if (body.empty() || body.front() != '-')
return { std::string(default_value.first), default_value.second };
body.remove_prefix(1);
size_t first_dash = body.find('-');
if (first_dash == std::string_view::npos)
{
// siz-xx 或 siz-x
if (IsSizeUnit(body))
return { std::string(body), 2 };
int precision = 0;
if (IsNonNegativeInteger(body, precision))
return { "B", precision };
return { std::string(default_value.first), default_value.second };
}
// siz-xx-y
std::string_view unit = body.substr(0, first_dash);
std::string_view precision_str = body.substr(first_dash + 1);
if (!IsSizeUnit(unit))
return { std::string(default_value.first), default_value.second };
int precision = 0;
if (!IsNonNegativeInteger(precision_str, precision))
return { std::string(default_value.first), default_value.second };
return { std::string(unit), precision };
}
std::string FormatFileSize(size_t size, const std::string& unit, int precision)
{
static constexpr double K = 1024.0;
static constexpr std::array<const char*, 9> units =
{
"B",
"KB",
"MB",
"GB",
"TB",
"PB",
"EB",
"ZB",
"YB"
};
static constexpr std::array<const char*, 9> iec_units =
{
"B",
"KIB",
"MIB",
"GIB",
"TIB",
"PIB",
"EIB",
"ZIB",
"YIB"
};
std::string input_unit = unit;
std::transform(input_unit.begin(), input_unit.end(), input_unit.begin(), [] (unsigned char c)
{
return static_cast<char>(std::toupper(c));
});
double bytes = static_cast<double>(size);
if ((input_unit == "BIT") || (input_unit == "BITS"))
bytes /= 8.0;
else
{
size_t unit_index = 0;
bool found = false;
for (size_t i = 0; i < units.size(); ++i)
{
if ((input_unit == units[i]) || (input_unit == iec_units[i]))
{
unit_index = i;
found = true;
break;
}
}
if (!found)
return std::format("{} {}", size, input_unit);
for (size_t i = 0; i < unit_index; ++i)
bytes *= K;
}
size_t output_index = 0;
while ((bytes >= K) && (output_index < (units.size() - 1)))
{
bytes /= K;
++output_index;
}
if (precision < 0)
precision = 0;
if (std::fabs(bytes - std::round(bytes)) < std::numeric_limits<double>::epsilon())
return fmt::format("{} {}", static_cast<size_t>(std::round(bytes)), units[output_index]);
std::string value = fmt::format("{:.{}f}", bytes, precision);
return fmt::format("{} {}", value, units[output_index]);
}
std::string ServerLogger::GenerateLogHeader(uns::ServerLogLevel LogLevel)
{
std::string hstr;
// 在日志行最开头添加对应日志级别的颜色控制码
switch (LogLevel)
{
case uns::llDebug:
hstr += "\033[36m"; // 青色
break;
case uns::llInfo:
hstr += "\033[32m"; // 绿色
break;
case uns::llWarning:
hstr += "\033[33m"; // 黄色
break;
case uns::llError:
hstr += "\033[31m"; // 红色
break;
case uns::llFatal:
hstr += "\033[1;37;41m"; // 亮白字 + 红底 (极度醒目)
break;
case uns::llTrace:
default:
break; // TRACE 与未知级别保持默认颜色,不追加转义码
}
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();
}
// 高性能、100% 异常安全的 ANSI 颜色码剥离函数
inline std::string StripAnsiCodes(const std::string& input) noexcept
{
std::string result;
// 预分配内存,避免多次 Realloc(即使底层内存极度匮乏,noexcept 也会兜底)
try
{
result.reserve(input.size());
}
catch (...)
{
// 极罕见的内存耗尽情况,直接降级返回原串或空串,绝不崩溃
return input;
}
bool in_escape = false;
for (char c : input)
{
if (c == '\033') // 遇到转义字符 '\033' (ESC)
{
in_escape = true;
continue;
}
if (in_escape)
{
// ANSI 颜色控制码以 'm' 结尾(例如 \033[31m 或 \033[0m)
if (c == 'm')
in_escape = false;
continue; // 跳过转义序列内的所有字符
}
result.push_back(c);
}
return result;
}
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 << StripAnsiCodes(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);
}
}
}
size_t GetUnsignedInteger(const uns::LogVariant& value)
{
return std::visit([] (const auto& v) -> size_t
{
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_integral_v<T> && !std::is_same_v<T, char> && !std::is_same_v<T, bool>)
return static_cast<size_t>(v);
else
return 0;
}, value);
}
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 if (StartsWith(inside, "siz"))
{
auto [u, p] = ParseSizeFormat(inside);
store.push_back(FormatFileSize(GetUnsignedInteger(arg.value), u, p));
}
else
store.push_back(args[arg_index]);
}
out += "{}";
++arg_index;
i = j + 1;
continue;
}
out += c;
++i;
}
// debug
// std::string debug = "[RewriteFormatString] RAW=|" + real_format + "|, OUT=|" + out + "|\n";
// std::fwrite(debug.c_str(), 1, debug.size(), stdout);
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 += "\033[0m\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 += "\033[0m\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 += "\033[0m\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 += "\033[0m\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;