feat(logger): 增强日志服务功能并添加颜色支持
添加新的Registry日志级别和颜色支持功能 实现Windows控制台ANSI颜色和UTF-8支持 新增日志级别颜色自定义功能 添加带颜色参数的日志宏 移除不必要的头文件引用并优化注册表日志输出
This commit is contained in:
parent
65b143573c
commit
62b03144a1
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/core/types.h>
|
||||
|
|
@ -8,6 +9,41 @@
|
|||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 日志颜色结构
|
||||
*/
|
||||
struct LogColor {
|
||||
uint8_t r, g, b;
|
||||
|
||||
constexpr LogColor() : r(255), g(255), b(255) {}
|
||||
constexpr LogColor(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {}
|
||||
|
||||
static constexpr LogColor White() { return LogColor(255, 255, 255); }
|
||||
static constexpr LogColor Gray() { return LogColor(128, 128, 128); }
|
||||
static constexpr LogColor Red() { return LogColor(255, 85, 85); }
|
||||
static constexpr LogColor Green() { return LogColor(85, 255, 85); }
|
||||
static constexpr LogColor Yellow() { return LogColor(255, 255, 85); }
|
||||
static constexpr LogColor Blue() { return LogColor(85, 85, 255); }
|
||||
static constexpr LogColor Magenta() { return LogColor(255, 85, 255); }
|
||||
static constexpr LogColor Cyan() { return LogColor(85, 255, 255); }
|
||||
static constexpr LogColor Orange() { return LogColor(255, 165, 0); }
|
||||
|
||||
static constexpr LogColor Slate() { return LogColor(100, 116, 139); }
|
||||
static constexpr LogColor SlateLight() { return LogColor(148, 163, 184); }
|
||||
static constexpr LogColor Sky() { return LogColor(14, 165, 233); }
|
||||
static constexpr LogColor SkyLight() { return LogColor(125, 211, 252); }
|
||||
static constexpr LogColor Emerald() { return LogColor(16, 185, 129); }
|
||||
static constexpr LogColor EmeraldLight() { return LogColor(110, 231, 183); }
|
||||
static constexpr LogColor Amber() { return LogColor(245, 158, 11); }
|
||||
static constexpr LogColor AmberLight() { return LogColor(252, 211, 77); }
|
||||
static constexpr LogColor Rose() { return LogColor(244, 63, 94); }
|
||||
static constexpr LogColor RoseLight() { return LogColor(253, 164, 175); }
|
||||
static constexpr LogColor Violet() { return LogColor(139, 92, 246); }
|
||||
static constexpr LogColor VioletLight() { return LogColor(196, 181, 253); }
|
||||
static constexpr LogColor Indigo() { return LogColor(99, 102, 241); }
|
||||
static constexpr LogColor IndigoLight() { return LogColor(165, 180, 252); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 日志级别枚举
|
||||
*/
|
||||
|
|
@ -15,10 +51,11 @@ enum class LogLevel {
|
|||
Trace = 0,
|
||||
Debug = 1,
|
||||
Info = 2,
|
||||
Warn = 3,
|
||||
Error = 4,
|
||||
Fatal = 5,
|
||||
Off = 6
|
||||
Registry = 3,
|
||||
Warn = 4,
|
||||
Error = 5,
|
||||
Fatal = 6,
|
||||
Off = 7
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -68,6 +105,11 @@ public:
|
|||
*/
|
||||
virtual void info(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Registry级别日志(用于模块/服务注册显示)
|
||||
*/
|
||||
virtual void registry(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief Warn级别日志
|
||||
*/
|
||||
|
|
@ -83,6 +125,31 @@ public:
|
|||
*/
|
||||
virtual void fatal(const char *fmt, ...) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置日志级别颜色
|
||||
* @param level 日志级别
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void setLevelColor(LogLevel level, const LogColor &color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取日志级别颜色
|
||||
* @param level 日志级别
|
||||
* @return 颜色
|
||||
*/
|
||||
virtual LogColor getLevelColor(LogLevel level) const = 0;
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用颜色输出
|
||||
* @param enabled 是否启用
|
||||
*/
|
||||
virtual void setColorEnabled(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 是否启用颜色输出
|
||||
*/
|
||||
virtual bool isColorEnabled() const = 0;
|
||||
|
||||
ServiceInfo getServiceInfo() const override {
|
||||
ServiceInfo info;
|
||||
info.name = "Logger";
|
||||
|
|
@ -113,15 +180,24 @@ public:
|
|||
void trace(const char *fmt, ...) override;
|
||||
void debug(const char *fmt, ...) override;
|
||||
void info(const char *fmt, ...) override;
|
||||
void registry(const char *fmt, ...) override;
|
||||
void warn(const char *fmt, ...) override;
|
||||
void error(const char *fmt, ...) override;
|
||||
void fatal(const char *fmt, ...) override;
|
||||
|
||||
void setLevelColor(LogLevel level, const LogColor &color) override;
|
||||
LogColor getLevelColor(LogLevel level) const override;
|
||||
void setColorEnabled(bool enabled) override;
|
||||
bool isColorEnabled() const override;
|
||||
|
||||
private:
|
||||
void output(LogLevel level, const char *msg);
|
||||
const char *getLevelString(LogLevel level);
|
||||
std::string getAnsiColor(LogLevel level);
|
||||
|
||||
LogLevel level_;
|
||||
bool colorEnabled_;
|
||||
LogColor levelColors_[7];
|
||||
class Impl;
|
||||
UniquePtr<Impl> impl_;
|
||||
|
||||
|
|
@ -167,7 +243,6 @@ void format_impl(std::string &result, const char *fmt, T &&value,
|
|||
}
|
||||
result += *p++;
|
||||
}
|
||||
// 没有更多的 {},追加剩余参数(不应该发生)
|
||||
result += " ";
|
||||
result += to_string(std::forward<T>(value));
|
||||
format_impl(result, p, std::forward<Args>(args)...);
|
||||
|
|
@ -198,23 +273,58 @@ std::string format_str(const char *fmt, Args &&...args) {
|
|||
} while (0)
|
||||
|
||||
#define E2D_LOG_TRACE(...) E2D_LOG(::extra2d::LogLevel::Trace, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_DEBUG(...) E2D_LOG(::extra2d::LogLevel::Debug, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_INFO(...) E2D_LOG(::extra2d::LogLevel::Info, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_REGISTRY(...) \
|
||||
E2D_LOG(::extra2d::LogLevel::Registry, __VA_ARGS__)
|
||||
#define E2D_LOG_WARN(...) E2D_LOG(::extra2d::LogLevel::Warn, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_ERROR(...) E2D_LOG(::extra2d::LogLevel::Error, __VA_ARGS__)
|
||||
|
||||
#define E2D_LOG_FATAL(...) E2D_LOG(::extra2d::LogLevel::Fatal, __VA_ARGS__)
|
||||
|
||||
// 简写宏
|
||||
#define E2D_INFO(...) E2D_LOG_INFO(__VA_ARGS__)
|
||||
#define E2D_REGISTRY(...) E2D_LOG_REGISTRY(__VA_ARGS__)
|
||||
#define E2D_WARN(...) E2D_LOG_WARN(__VA_ARGS__)
|
||||
#define E2D_ERROR(...) E2D_LOG_ERROR(__VA_ARGS__)
|
||||
#define E2D_FATAL(...) E2D_LOG_FATAL(__VA_ARGS__)
|
||||
|
||||
// 带颜色参数的日志宏
|
||||
#define E2D_LOG_COLOR(level, color, ...) \
|
||||
do { \
|
||||
if (auto logService = ::extra2d::ServiceLocator::instance() \
|
||||
.tryGetService<::extra2d::ILogger>()) { \
|
||||
if (logService->isEnabled(level)) { \
|
||||
auto prevColor = logService->getLevelColor(level); \
|
||||
logService->setLevelColor(level, color); \
|
||||
logService->log(level, ::extra2d::format_str(__VA_ARGS__)); \
|
||||
logService->setLevelColor(level, prevColor); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define E2D_LOG_TRACE_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Trace, color, __VA_ARGS__)
|
||||
#define E2D_LOG_DEBUG_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Debug, color, __VA_ARGS__)
|
||||
#define E2D_LOG_INFO_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Info, color, __VA_ARGS__)
|
||||
#define E2D_LOG_REGISTRY_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Registry, color, __VA_ARGS__)
|
||||
#define E2D_LOG_WARN_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Warn, color, __VA_ARGS__)
|
||||
#define E2D_LOG_ERROR_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Error, color, __VA_ARGS__)
|
||||
#define E2D_LOG_FATAL_COLOR(color, ...) \
|
||||
E2D_LOG_COLOR(::extra2d::LogLevel::Fatal, color, __VA_ARGS__)
|
||||
|
||||
// 简写带颜色宏
|
||||
#define E2D_INFO_COLOR(color, ...) E2D_LOG_INFO_COLOR(color, __VA_ARGS__)
|
||||
#define E2D_REGISTRY_COLOR(color, ...) \
|
||||
E2D_LOG_REGISTRY_COLOR(color, __VA_ARGS__)
|
||||
#define E2D_WARN_COLOR(color, ...) E2D_LOG_WARN_COLOR(color, __VA_ARGS__)
|
||||
#define E2D_ERROR_COLOR(color, ...) E2D_LOG_ERROR_COLOR(color, __VA_ARGS__)
|
||||
#define E2D_FATAL_COLOR(color, ...) E2D_LOG_FATAL_COLOR(color, __VA_ARGS__)
|
||||
|
||||
#ifdef E2D_DEBUG
|
||||
#define E2D_DEBUG_LOG(...) E2D_LOG_DEBUG(__VA_ARGS__)
|
||||
#define E2D_TRACE(...) E2D_LOG_TRACE(__VA_ARGS__)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -13,30 +11,24 @@ Registry &Registry::instance() {
|
|||
|
||||
bool Registry::init() {
|
||||
auto sorted = topologicalSort();
|
||||
|
||||
std::cout << "[Registry] Initializing " << sorted.size() << " modules..."
|
||||
<< std::endl;
|
||||
E2D_REGISTRY("Initializing {} modules...", sorted.size());
|
||||
|
||||
for (auto *module : sorted) {
|
||||
std::cout << "[Registry] Initializing module: " << module->name()
|
||||
<< std::endl;
|
||||
E2D_REGISTRY("Initializing module: {}", module->name());
|
||||
if (!module->init()) {
|
||||
std::cerr << "[Registry] Failed to initialize module: " << module->name()
|
||||
<< std::endl;
|
||||
E2D_ERROR("Failed to initialize module: {}", module->name());
|
||||
return false;
|
||||
}
|
||||
std::cout << "[Registry] Module " << module->name()
|
||||
<< " initialized successfully" << std::endl;
|
||||
E2D_REGISTRY("Module {} initialized successfully", module->name());
|
||||
}
|
||||
|
||||
std::cout << "[Registry] All modules initialized" << std::endl;
|
||||
E2D_REGISTRY("All modules initialized");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Registry::shutdown() {
|
||||
auto sorted = topologicalSort();
|
||||
|
||||
// 反向关闭
|
||||
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it) {
|
||||
(*it)->shutdown();
|
||||
}
|
||||
|
|
@ -52,7 +44,6 @@ std::vector<Module *> Registry::topologicalSort() {
|
|||
std::unordered_map<Module *, int> inDegree;
|
||||
std::unordered_map<Module *, std::vector<Module *>> adj;
|
||||
|
||||
// 构建图
|
||||
for (auto &[typeIdx, module] : modules_) {
|
||||
inDegree[module.get()] = 0;
|
||||
}
|
||||
|
|
@ -67,7 +58,6 @@ std::vector<Module *> Registry::topologicalSort() {
|
|||
}
|
||||
}
|
||||
|
||||
// 优先级队列(优先级小的先处理)
|
||||
auto cmp = [](Module *a, Module *b) { return a->priority() > b->priority(); };
|
||||
std::priority_queue<Module *, std::vector<Module *>, decltype(cmp)> pq(cmp);
|
||||
|
||||
|
|
@ -77,7 +67,6 @@ std::vector<Module *> Registry::topologicalSort() {
|
|||
}
|
||||
}
|
||||
|
||||
// 拓扑排序
|
||||
while (!pq.empty()) {
|
||||
Module *curr = pq.top();
|
||||
pq.pop();
|
||||
|
|
|
|||
|
|
@ -4,18 +4,65 @@
|
|||
#include <extra2d/services/logger_service.h>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ConsoleLogger 实现
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief 初始化 Windows 控制台(ANSI 颜色 + UTF-8)
|
||||
*/
|
||||
static bool enableWindowsConsoleFeatures() {
|
||||
bool success = true;
|
||||
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hOut != INVALID_HANDLE_VALUE) {
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hOut, &dwMode)) {
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(hOut, dwMode)) {
|
||||
success = false;
|
||||
}
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
SetConsoleCP(CP_UTF8);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool g_windowsConsoleInitialized = false;
|
||||
#endif
|
||||
|
||||
class ConsoleLogger::Impl {
|
||||
public:
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
ConsoleLogger::ConsoleLogger()
|
||||
: level_(LogLevel::Info), impl_(std::make_unique<Impl>()) {
|
||||
: level_(LogLevel::Info), colorEnabled_(true),
|
||||
impl_(std::make_unique<Impl>()) {
|
||||
info_.name = "ConsoleLogger";
|
||||
info_.priority = ServicePriority::Core;
|
||||
|
||||
levelColors_[static_cast<int>(LogLevel::Trace)] = LogColor::Gray();
|
||||
levelColors_[static_cast<int>(LogLevel::Debug)] = LogColor::Cyan();
|
||||
levelColors_[static_cast<int>(LogLevel::Info)] = LogColor::SkyLight();
|
||||
levelColors_[static_cast<int>(LogLevel::Registry)] = LogColor::IndigoLight();
|
||||
levelColors_[static_cast<int>(LogLevel::Warn)] = LogColor::Yellow();
|
||||
levelColors_[static_cast<int>(LogLevel::Error)] = LogColor::Red();
|
||||
levelColors_[static_cast<int>(LogLevel::Fatal)] = LogColor::Magenta();
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!g_windowsConsoleInitialized) {
|
||||
g_windowsConsoleInitialized = enableWindowsConsoleFeatures();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ConsoleLogger::~ConsoleLogger() = default;
|
||||
|
|
@ -87,6 +134,17 @@ void ConsoleLogger::info(const char *fmt, ...) {
|
|||
output(LogLevel::Info, buffer);
|
||||
}
|
||||
|
||||
void ConsoleLogger::registry(const char *fmt, ...) {
|
||||
if (!isEnabled(LogLevel::Registry))
|
||||
return;
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
output(LogLevel::Registry, buffer);
|
||||
}
|
||||
|
||||
void ConsoleLogger::warn(const char *fmt, ...) {
|
||||
if (!isEnabled(LogLevel::Warn))
|
||||
return;
|
||||
|
|
@ -120,6 +178,32 @@ void ConsoleLogger::fatal(const char *fmt, ...) {
|
|||
output(LogLevel::Fatal, buffer);
|
||||
}
|
||||
|
||||
void ConsoleLogger::setLevelColor(LogLevel level, const LogColor &color) {
|
||||
int idx = static_cast<int>(level);
|
||||
if (idx >= 0 && idx < 7) {
|
||||
levelColors_[idx] = color;
|
||||
}
|
||||
}
|
||||
|
||||
LogColor ConsoleLogger::getLevelColor(LogLevel level) const {
|
||||
int idx = static_cast<int>(level);
|
||||
if (idx >= 0 && idx < 7) {
|
||||
return levelColors_[idx];
|
||||
}
|
||||
return LogColor::White();
|
||||
}
|
||||
|
||||
void ConsoleLogger::setColorEnabled(bool enabled) { colorEnabled_ = enabled; }
|
||||
|
||||
bool ConsoleLogger::isColorEnabled() const { return colorEnabled_; }
|
||||
|
||||
std::string ConsoleLogger::getAnsiColor(LogLevel level) {
|
||||
const LogColor &c = getLevelColor(level);
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "\033[38;2;%d;%d;%dm", c.r, c.g, c.b);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
void ConsoleLogger::output(LogLevel level, const char *msg) {
|
||||
std::lock_guard<std::mutex> lock(impl_->mutex_);
|
||||
|
||||
|
|
@ -137,36 +221,16 @@ void ConsoleLogger::output(LogLevel level, const char *msg) {
|
|||
#endif
|
||||
|
||||
const char *levelStr = getLevelString(level);
|
||||
|
||||
// 颜色代码
|
||||
const char *color = "";
|
||||
const char *reset = "\033[0m";
|
||||
|
||||
switch (level) {
|
||||
case LogLevel::Trace:
|
||||
color = "\033[90m";
|
||||
break;
|
||||
case LogLevel::Debug:
|
||||
color = "\033[36m";
|
||||
break;
|
||||
case LogLevel::Info:
|
||||
color = "\033[32m";
|
||||
break;
|
||||
case LogLevel::Warn:
|
||||
color = "\033[33m";
|
||||
break;
|
||||
case LogLevel::Error:
|
||||
color = "\033[31m";
|
||||
break;
|
||||
case LogLevel::Fatal:
|
||||
color = "\033[35m";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (colorEnabled_) {
|
||||
std::string color = getAnsiColor(level);
|
||||
printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color.c_str(), tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec, (int)ms.count(), levelStr, msg, reset);
|
||||
} else {
|
||||
printf("[%02d:%02d:%02d.%03d] [%s] %s\n", tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
(int)ms.count(), levelStr, msg);
|
||||
}
|
||||
|
||||
printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color, tm.tm_hour, tm.tm_min,
|
||||
tm.tm_sec, (int)ms.count(), levelStr, msg, reset);
|
||||
}
|
||||
|
||||
const char *ConsoleLogger::getLevelString(LogLevel level) {
|
||||
|
|
@ -177,6 +241,8 @@ const char *ConsoleLogger::getLevelString(LogLevel level) {
|
|||
return "DEBUG";
|
||||
case LogLevel::Info:
|
||||
return "INFO";
|
||||
case LogLevel::Registry:
|
||||
return "REGISTRY";
|
||||
case LogLevel::Warn:
|
||||
return "WARN";
|
||||
case LogLevel::Error:
|
||||
|
|
|
|||
Loading…
Reference in New Issue