123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- #ifndef LOG4CPP_H
- #define LOG4CPP_H
- #include <log4cpp/Category.hh>
- #include <log4cpp/Appender.hh>
- #include <log4cpp/FileAppender.hh>
- #include <log4cpp/RollingFileAppender.hh>
- #include <log4cpp/OstreamAppender.hh>
- #include <log4cpp/Layout.hh>
- #include <log4cpp/PatternLayout.hh>
- #include <log4cpp/Priority.hh>
- #include <string>
- #include <memory>
- #include <unordered_map>
- #include <mutex>
- #include <sstream>
- #include <type_traits>
- #include <cstring>
- #include <vector>
- #include <map>
- #include <chrono>
- #include <iomanip>
- // 前置声明
- class LogInstance;
- // 日志实例管理器(全局唯一,管理所有模块的日志实例)
- class LogManager {
- public:
- static LogManager& getInstance() {
- static LogManager instance;
- return instance;
- }
- // 注册模块日志实例
- void registerInstance(const std::string& module, LogInstance* instance) {
- std::lock_guard<std::mutex> lock(mtx_);
- instances_[module] = instance;
- }
- // 获取模块日志实例
- LogInstance* getInstance(const std::string& module) {
- std::lock_guard<std::mutex> lock(mtx_);
- auto it = instances_.find(module);
- return (it != instances_.end()) ? it->second : nullptr;
- }
- // 移除模块日志实例
- void unregisterInstance(const std::string& module) {
- std::lock_guard<std::mutex> lock(mtx_);
- instances_.erase(module);
- }
- // 获取所有注册的模块名
- std::vector<std::string> getRegisteredModules() {
- std::lock_guard<std::mutex> lock(mtx_);
- std::vector<std::string> modules;
- for (const auto& pair : instances_) {
- modules.push_back(pair.first);
- }
- return modules;
- }
- private:
- LogManager() = default;
- ~LogManager() = default;
- LogManager(const LogManager&) = delete;
- LogManager& operator=(const LogManager&) = delete;
- std::unordered_map<std::string, LogInstance*> instances_;
- std::mutex mtx_;
- };
- // 日志配置结构体
- struct LogConfig {
- std::string root_level = "DEBUG";
- std::string log_dir = "logs";
- std::string history_dir = "logs/history";
- unsigned int max_file_size = 10; // MB
- int max_backups = 5;
- std::string file_pattern = "%d{%Y-%m-%d %H:%M:%S.%l} [%p] - %F::%M@%L %m%n";
- std::string console_pattern = "%d{%H:%M:%S.%l} [%p] - %F::%M@%L %m%n";
- std::string log_file_name; // 自定义日志文件名(为空则使用模块名)
- };
- // 日志实例类(每个动态库一个实例)
- class LogInstance {
- public:
- LogInstance() = default;
- ~LogInstance() { destroyLog(); }
- // 初始化日志(module:模块名,确保唯一;configFile:可为空使用默认配置)
- bool init(const std::string& logHostName,
- const std::string& module,
- const std::string& configFile = "",
- bool toScreen = false);
- // 销毁日志
- void destroyLog();
- // 设置日志级别
- void setPriority(log4cpp::Priority::PriorityLevel consoleLevel,
- log4cpp::Priority::PriorityLevel fileLevel);
- // 日志输出接口(内部使用)
- template <typename... Args>
- void log(log4cpp::Priority::PriorityLevel level, const char* file, int line, const char* function,
- const std::string& format, Args&&... args) {
- if (!isInitialized_) return;
- std::lock_guard<std::mutex> lock(logMtx_);
- // 格式化消息
- std::string formattedMsg = formatMessage(format, std::forward<Args>(args)...);
- // 添加代码位置信息
- std::string location;
- if (file && function) {
- // 提取文件名(不含路径)
- const char* filename = strrchr(file, '/');
- if (!filename) filename = strrchr(file, '\\');
- filename = filename ? filename + 1 : file;
- std::ostringstream oss;
- oss << filename << "::" << function << "@" << line;
- location = oss.str();
- }
- // 输出到文件
- if (logCat) {
- if (!location.empty()) {
- logCat->log(level, "%s - %s", location.c_str(), formattedMsg.c_str());
- }
- else {
- logCat->log(level, "%s", formattedMsg.c_str());
- }
- }
- // 输出到控制台
- if (outToScreen && coutCat) {
- if (!location.empty()) {
- coutCat->log(level, "%s - %s", location.c_str(), formattedMsg.c_str());
- }
- else {
- coutCat->log(level, "%s", formattedMsg.c_str());
- }
- }
- }
- bool isInitialized() const { return isInitialized_; }
- const std::string& getModule() const { return moduleName; }
- const LogConfig& getConfig() const { return config_; }
- const std::string& getLogFileName() const { return actualLogFileName; }
- private:
- // 解析配置文件
- bool parseConfigFile(const std::string& configFile, LogConfig& config);
- // 创建目录
- bool createDirectory(const std::string& dir);
- // 获取当前时间(带毫秒)
- void getCurrentTimeWithMs(std::string& timeStr);
- // 转换日志级别
- log4cpp::Priority::PriorityLevel parseLogLevel(const std::string& levelStr);
- // 移动旧日志到历史目录
- void moveOldLogsToHistory();
- // 格式化消息(替换 {$} 占位符)
- template <typename... Args>
- std::string formatMessage(const std::string& format, Args&&... args) {
- std::string result = format;
- std::vector<std::string> replacements;
- // 收集所有参数
- (replacements.push_back(toString(std::forward<Args>(args))), ...);
- // 替换所有 {$} 占位符
- size_t pos = 0;
- int argIndex = 0;
- while ((pos = result.find("{$}", pos)) != std::string::npos) {
- if (argIndex < replacements.size()) {
- result.replace(pos, 3, replacements[argIndex]);
- pos += replacements[argIndex].length();
- argIndex++;
- }
- else {
- // 参数不足,保留占位符
- pos += 3;
- }
- }
- return result;
- }
- // 类型转换为字符串
- template <typename T>
- std::string toString(T&& value);
- LogConfig config_;
- std::string logHost;
- std::string moduleName;
- std::string actualLogFileName; // 实际使用的日志文件名
- bool outToScreen = false;
- bool isInitialized_ = false;
- // log4cpp组件
- log4cpp::Category* logCat = nullptr;
- log4cpp::Category* coutCat = nullptr;
- log4cpp::RollingFileAppender* rollLogFile = nullptr;
- log4cpp::OstreamAppender* logScreen = nullptr;
- log4cpp::PatternLayout* logLayout = nullptr;
- log4cpp::PatternLayout* screenLayout = nullptr;
- // 线程安全锁
- std::mutex logMtx_;
- };
- // 日志模块初始化函数
- bool initLogModule(const std::string& logHost,
- const std::string& module,
- const std::string& configFile = "",
- bool toScreen = false);
- // 日志模块销毁函数
- void destroyLogModule(const std::string& module);
- // 获取所有已初始化的日志模块
- std::vector<std::string> getInitializedLogModules();
- // 销毁所有日志模块
- void destroyAllLogModules();
- // 类型转换实现
- template <typename T>
- std::string LogInstance::toString(T&& value) {
- using DecayedT = std::decay_t<T>;
- try {
- if constexpr (std::is_same_v<DecayedT, std::string> ||
- std::is_same_v<DecayedT, char*> ||
- std::is_same_v<DecayedT, const char*>) {
- return std::forward<T>(value);
- }
- else if constexpr (std::is_arithmetic_v<DecayedT> || std::is_enum_v<DecayedT>) {
- std::ostringstream oss;
- oss << value;
- return oss.str();
- }
- else {
- std::ostringstream oss;
- oss << std::forward<T>(value);
- return oss.str();
- }
- }
- catch (...) {
- return "[LOG_CONVERT_ERROR]";
- }
- }
- #endif // LOG4CPP_H
|