213 lines
6.8 KiB
C++
213 lines
6.8 KiB
C++
#pragma once
|
|
|
|
#include <extra2d/core/service_interface.h>
|
|
#include <extra2d/core/service_locator.h>
|
|
#include <extra2d/core/types.h>
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
namespace extra2d {
|
|
|
|
/**
|
|
* @brief 日志颜色
|
|
*/
|
|
struct LogColor {
|
|
u8 r, g, b;
|
|
|
|
constexpr LogColor() : r(255), g(255), b(255) {}
|
|
constexpr LogColor(u8 r, u8 g, u8 b) : r(r), g(g), b(b) {}
|
|
|
|
static constexpr LogColor White() { return {255, 255, 255}; }
|
|
static constexpr LogColor Gray() { return {128, 128, 128}; }
|
|
static constexpr LogColor Red() { return {255, 85, 85}; }
|
|
static constexpr LogColor Green() { return {85, 255, 85}; }
|
|
static constexpr LogColor Yellow() { return {255, 255, 85}; }
|
|
static constexpr LogColor Blue() { return {85, 85, 255}; }
|
|
static constexpr LogColor Magenta() { return {255, 85, 255}; }
|
|
static constexpr LogColor Cyan() { return {85, 255, 255}; }
|
|
static constexpr LogColor SkyLight() { return {125, 211, 252}; }
|
|
static constexpr LogColor IndigoLight() { return {165, 180, 252}; }
|
|
};
|
|
|
|
/**
|
|
* @brief 日志级别
|
|
*/
|
|
enum class LogLevel : u8 {
|
|
Trace = 0,
|
|
Debug = 1,
|
|
Info = 2,
|
|
Warn = 3,
|
|
Error = 4,
|
|
Fatal = 5,
|
|
Off = 6
|
|
};
|
|
|
|
/**
|
|
* @brief 日志服务接口
|
|
*/
|
|
class ILogger : public IService {
|
|
public:
|
|
virtual ~ILogger() = default;
|
|
|
|
virtual void level(LogLevel lvl) = 0;
|
|
virtual LogLevel level() const = 0;
|
|
virtual bool enabled(LogLevel lvl) const = 0;
|
|
|
|
virtual void log(LogLevel lvl, const char *fmt, ...) = 0;
|
|
virtual void log(LogLevel lvl, const std::string &msg) = 0;
|
|
|
|
virtual void trace(const char *fmt, ...) = 0;
|
|
virtual void debug(const char *fmt, ...) = 0;
|
|
virtual void info(const char *fmt, ...) = 0;
|
|
virtual void warn(const char *fmt, ...) = 0;
|
|
virtual void error(const char *fmt, ...) = 0;
|
|
virtual void fatal(const char *fmt, ...) = 0;
|
|
|
|
virtual void levelColor(LogLevel lvl, const LogColor &c) = 0;
|
|
virtual LogColor levelColor(LogLevel lvl) const = 0;
|
|
virtual void colors(bool on) = 0;
|
|
virtual bool colors() const = 0;
|
|
|
|
ServiceInfo info() const override {
|
|
ServiceInfo i;
|
|
i.name = "Logger";
|
|
i.priority = ServicePriority::Core;
|
|
return i;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief 控制台日志服务
|
|
*/
|
|
class ConsoleLogger : public ILogger {
|
|
public:
|
|
ConsoleLogger();
|
|
~ConsoleLogger() override;
|
|
|
|
bool init() override;
|
|
void shutdown() override;
|
|
|
|
void level(LogLevel lvl) override;
|
|
LogLevel level() const override;
|
|
bool enabled(LogLevel lvl) const override;
|
|
|
|
void log(LogLevel lvl, const char *fmt, ...) override;
|
|
void log(LogLevel lvl, const std::string &msg) override;
|
|
|
|
void trace(const char *fmt, ...) override;
|
|
void debug(const char *fmt, ...) override;
|
|
void info(const char *fmt, ...) override;
|
|
void warn(const char *fmt, ...) override;
|
|
void error(const char *fmt, ...) override;
|
|
void fatal(const char *fmt, ...) override;
|
|
|
|
void levelColor(LogLevel lvl, const LogColor &c) override;
|
|
LogColor levelColor(LogLevel lvl) const override;
|
|
void colors(bool on) override;
|
|
bool colors() const override;
|
|
|
|
const char *levelString(LogLevel lvl);
|
|
std::string ansiColor(LogLevel lvl);
|
|
|
|
private:
|
|
void output(LogLevel lvl, const char *msg);
|
|
|
|
LogLevel level_ = LogLevel::Info;
|
|
bool colors_ = true;
|
|
LogColor levelColors_[7];
|
|
class Impl;
|
|
Unique<Impl> impl_;
|
|
|
|
E2D_AUTO_REGISTER_SERVICE(ILogger, ConsoleLogger);
|
|
};
|
|
|
|
} // namespace extra2d
|
|
|
|
// 格式化辅助
|
|
namespace extra2d {
|
|
namespace detail {
|
|
template <typename T> std::string to_string(T &&value) {
|
|
using D = std::decay_t<T>;
|
|
using Raw = std::remove_reference_t<T>;
|
|
if constexpr (std::is_same_v<D, std::string>)
|
|
return value;
|
|
else if constexpr (std::is_array_v<Raw>)
|
|
return std::string(value);
|
|
else if constexpr (std::is_same_v<D, const char *>)
|
|
return value ? value : "(null)";
|
|
else if constexpr (std::is_same_v<D, bool>)
|
|
return value ? "true" : "false";
|
|
else if constexpr (std::is_arithmetic_v<D>)
|
|
return std::to_string(value);
|
|
else
|
|
return "<?>";
|
|
}
|
|
|
|
inline void format_impl(std::string &result, const char *fmt) { result += fmt; }
|
|
|
|
template <typename T, typename... Args>
|
|
void format_impl(std::string &result, const char *fmt, T &&value,
|
|
Args &&...args) {
|
|
while (*fmt) {
|
|
if (*fmt == '{' && *(fmt + 1) == '}') {
|
|
result += to_string(std::forward<T>(value));
|
|
return format_impl(result, fmt + 2, std::forward<Args>(args)...);
|
|
}
|
|
result += *fmt++;
|
|
}
|
|
result += " " + to_string(std::forward<T>(value));
|
|
format_impl(result, fmt, std::forward<Args>(args)...);
|
|
}
|
|
} // namespace detail
|
|
|
|
template <typename... Args>
|
|
std::string format_str(const char *fmt, Args &&...args) {
|
|
std::string result;
|
|
detail::format_impl(result, fmt, std::forward<Args>(args)...);
|
|
return result;
|
|
}
|
|
} // namespace extra2d
|
|
|
|
// 日志宏
|
|
#define E2D_LOG(lvl, ...) \
|
|
do { \
|
|
if (auto log = ::extra2d::ServiceLocator::instance() \
|
|
.tryGet<::extra2d::ILogger>()) \
|
|
if (log->enabled(lvl)) \
|
|
log->log(lvl, ::extra2d::format_str(__VA_ARGS__)); \
|
|
} while (0)
|
|
|
|
#define E2D_LOG_CAT(lvl, cat, ...) \
|
|
do { \
|
|
if (auto log = ::extra2d::ServiceLocator::instance() \
|
|
.tryGet<::extra2d::ILogger>()) \
|
|
if (log->enabled(lvl)) \
|
|
log->log(lvl, ::extra2d::format_str("[{}] {}", cat, __VA_ARGS__)); \
|
|
} while (0)
|
|
|
|
// 带类别的日志宏
|
|
#define E2D_TRACE(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Trace, cat, __VA_ARGS__)
|
|
#define E2D_DEBUG(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Debug, cat, __VA_ARGS__)
|
|
#define E2D_INFO(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Info, cat, __VA_ARGS__)
|
|
#define E2D_WARN(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Warn, cat, __VA_ARGS__)
|
|
#define E2D_ERROR(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Error, cat, __VA_ARGS__)
|
|
#define E2D_FATAL(cat, ...) \
|
|
E2D_LOG_CAT(::extra2d::LogLevel::Fatal, cat, __VA_ARGS__)
|
|
|
|
// 常用日志类别
|
|
#define CAT_APP "应用"
|
|
#define CAT_WINDOWS "窗口"
|
|
#define CAT_RENDER "渲染"
|
|
#define CAT_SCENE "场景"
|
|
#define CAT_INPUT "输入"
|
|
#define CAT_AUDIO "音频"
|
|
#define CAT_ASSET "资源"
|
|
#define CAT_SYSTEM "系统"
|
|
#define CAT_DATA "存档"
|
|
#define CAT_MODULES "模块系统"
|
|
#define CAT_SERVICES "服务系统" |