255 lines
5.6 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.

/**
* @file XNLogger.h
* @author jinchao
* @brief 日志类
* @version 1.0
* @date 2025-01-08
*
* @copyright Copyright (c) 2025 COMAC
*
*/
#pragma once
#include <string>
#include <mutex>
#include <fstream>
#include <chrono>
#include <filesystem>
#include <type_traits>
#include <iostream>
#include <iomanip>
#include <sstream>
/**
* @brief 日志类
*/
class XNLogger
{
public:
/**
* @brief 日志等级
*/
enum LogLevel { Debug, Info, Warning, Error, Time };
/**
* @brief 获取日志类实例
* @return 日志类实例
*/
static XNLogger &instance()
{
static XNLogger instance;
return instance;
}
/**
* @brief 日志输出
* @param level 日志等级
* @param message 日志消息
*/
void log(LogLevel level, const std::string &message);
/**
* @brief 启用控制台输出
* @param level 日志等级
* @param enable 是否启用
*/
void enableConsoleOutput(LogLevel level, bool enable);
/**
* @brief 启用文件输出
* @param level 日志等级
* @param enable 是否启用
*/
void enableFileOutput(LogLevel level, bool enable);
private:
/**
* @brief 构造函数
*/
XNLogger();
/**
* @brief 析构函数
*/
~XNLogger();
/**
* @brief 禁止拷贝构造
*/
XNLogger(const XNLogger &) = delete;
/**
* @brief 禁止赋值
*/
XNLogger &operator=(const XNLogger &) = delete;
/**
* @brief 日志文件路径
*/
std::string logFilePath;
/**
* @brief 控制台输出控制
*/
bool consoleOutputEnabled[5];
/**
* @brief 文件输出控制
*/
bool fileOutputEnabled[5];
/**
* @brief 日志文件
*/
std::ofstream logFile;
/**
* @brief 互斥锁
*/
std::mutex mutex;
/**
* @brief 日志等级转换为字符串
* @param level 日志等级
* @return 日志等级字符串
*/
std::string logLevelToString(LogLevel level) const;
/**
* @brief 获取当前时间字符串
* @return 格式化的时间字符串
*/
std::string getCurrentTimeString() const;
/**
* @brief 控制台输出字体恢复颜色常量
*/
const std::string COLOR_RESET = "\033[0m";
/**
* @brief 调试颜色常量
*/
const std::string COLOR_DEBUG = "\033[34m"; // 蓝色
/**
* @brief 信息颜色常量
*/
const std::string COLOR_INFO = "\033[32m"; // 绿色
/**
* @brief 警告颜色常量
*/
const std::string COLOR_WARNING = "\033[33m"; // 黄色
/**
* @brief 错误颜色常量
*/
const std::string COLOR_ERROR = "\033[31m"; // 红色
};
/**
* @brief 日志辅助类
*/
class XNLoggerHelper
{
public:
/**
* @brief 带参数的日志输出
* @tparam Args 参数类型
* @param level 日志等级
* @param message 日志消息
* @param args 参数
*/
template <typename... Args>
inline static typename std::enable_if<(sizeof...(Args) > 0), void>::type
log(XNLogger::LogLevel level, const std::string &message, Args... args)
{
std::string formattedMessage = formatMessage(message, args...);
XNLogger::instance().log(level, formattedMessage);
}
/**
* @brief 不带参数的日志输出
* @param level 日志等级
* @param message 日志消息
*/
inline static void log(XNLogger::LogLevel level, const std::string &message)
{
XNLogger::instance().log(level, message);
}
private:
/**
* @brief 将参数转换为字符串
* @tparam T 参数类型
* @param arg 要转换的参数
* @return 转换后的字符串
*/
template <typename T>
static std::string convertToString(const T &arg)
{
if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(arg); // 处理数值类型
} else if constexpr (std::is_same_v<T, std::string>) {
return arg;
} else if constexpr (std::is_convertible_v<T, std::string>) {
return std::string(arg);
} else if constexpr (std::is_same_v<T, char *> || std::is_same_v<T, const char *>) {
return std::string(arg);
} else {
static_assert(std::is_arithmetic_v<T> || std::is_same_v<T, std::string>
|| std::is_convertible_v<T, std::string> || std::is_same_v<T, char *>
|| std::is_same_v<T, const char *>,
"错误码010211001不支持的类型转换详见XNLogger.cppline 199");
}
}
/**
* @brief 格式化日志消息,顺序替换%1、%2、%3……
* @tparam Args 参数类型
* @param message 日志消息
* @param args 参数包
* @return 格式化后的消息
*/
template <typename... Args>
static std::string formatMessage(const std::string &message, Args &&...args)
{
static_assert(sizeof...(Args) <= 9,
"错误码010211002单条日志参数数量超过限制详见XNLogger.cppline 216");
std::string result = message;
// 使用初始化列表展开参数包
int index = 1;
// 使用lambda和std::initializer_list展开参数包
(void)std::initializer_list<int>{(
[&result, &index](const auto &value) {
std::string placeholder = "%" + std::to_string(index++);
size_t pos = result.find(placeholder);
if (pos != std::string::npos) {
result.replace(pos, placeholder.length(), convertToString(value));
}
}(args),
0)...};
return result;
}
};
/**
* @brief 宏定义,用于输出调试日志
*/
#define LOG_DEBUG(message, ...) XNLoggerHelper::log(XNLogger::Debug, message, ##__VA_ARGS__)
/**
* @brief 宏定义,用于输出信息日志
*/
#define LOG_INFO(message, ...) XNLoggerHelper::log(XNLogger::Info, message, ##__VA_ARGS__)
/**
* @brief 宏定义,用于输出警告日志
*/
#define LOG_WARNING(message, ...) XNLoggerHelper::log(XNLogger::Warning, message, ##__VA_ARGS__)
/**
* @brief 宏定义,用于输出错误日志
*/
#define LOG_ERROR(message, ...) XNLoggerHelper::log(XNLogger::Error, message, ##__VA_ARGS__)