日志系统4 日志类型的设计
一、核心功能概述
Logger 类主要承担以下职责:
- 管理全局日志级别,控制不同重要程度的日志是否输出
- 提供日志消息的创建接口,对接 LogMessage 类
- 管理日志输出和刷新策略,支持自定义输出目标
- 处理特殊级别日志(如 FATAL)的特殊逻辑
二、关键实现解析
1. 静态成员初始化
// 初始化输出和刷新回调函数为默认实现
wangt::Logger::Outputfunc wangt::Logger::output_ = defaultOutput;
wangt::Logger::Flushfunc wangt::Logger::flush_ = defaultFlush;// 初始化全局日志级别
wangt::LOG_LEVEL wangt::Logger::s_level_ = initLogLevel();
- 静态成员在类外初始化,确保全局唯一实例
- 默认输出到标准输出 (stdout),默认刷新函数为 fflush (stdout)
- 日志级别通过 initLogLevel () 函数初始化
2. 日志级别初始化逻辑
wangt::LOG_LEVEL wangt::initLogLevel()
{if (::getenv("WANGTLOG_TRACE"))return wangt::LOG_LEVEL::TRACE;else if (::getenv("WANGTLOG_DEBUG"))return wangt::LOG_LEVEL::DEBUG;elsereturn wangt::LOG_LEVEL::INFO;
}
- 优先从环境变量获取日志级别配置
- 支持通过环境变量 "WANGTLOG_TRACE" 和 "WANGTLOG_DEBUG" 动态设置
- 默认日志级别为 INFO,平衡信息量和性能
3. 构造函数与析构函数
// 构造函数:初始化日志消息对象
wangt::Logger::Logger(const wangt::LOG_LEVEL &le, const string &filename, const string &funcname, const int line) : impl_(le, filename, funcname, line)
{
}// 析构函数:完成日志输出
wangt::Logger::~Logger()
{impl_ << '\n'; // 为日志添加换行符output_(impl_.toString()); // 输出完整日志flush_(); // 刷新缓冲区// 处理FATAL级别的日志:输出错误信息并终止程序if (impl_.getlevel() == LOG_LEVEL::FATAL){flush_();fprintf(stderr, "Process exit \n");abort(); // 异常终止程序}
}
- 析构函数是日志输出的关键触发点,利用对象生命周期自动完成日志输出
- 为每条日志自动添加换行符,保证格式一致性
- 对 FATAL 级别日志进行特殊处理,输出错误信息并调用 abort () 终止程序
4. 日志输出与刷新控制
// 设置自定义输出函数
void wangt::Logger::setOutput(Outputfunc out)
{output_ = out;
}// 设置自定义刷新函数
void wangt::Logger::setFlush(Flushfunc flush)
{flush_ = flush;
}// 默认输出实现:输出到标准输出
void defaultOutput(const string &msg)
{size_t n = fwrite(msg.c_str(), 1, msg.size(), stdout);
}// 默认刷新实现:刷新标准输出缓冲区
void defaultFlush()
{fflush(stdout);
}
- 通过 setOutput () 和 setFlush () 支持自定义输出策略
- 默认输出到控制台 (stdout),可根据需要改为输出到文件、网络等
- 使用 fwrite 而非 cout,避免 C++ IO 流的性能开销
5. 日志级别控制
// 设置全局日志级别
void wangt::Logger::setLogLevel(LOG_LEVEL level)
{s_level_ = level;
}// 获取当前全局日志级别
wangt::LOG_LEVEL wangt::Logger::GetLogLevel()
{return s_level_;
}
- 提供接口动态调整日志级别,无需重启程序
- 可根据运行环境 (开发 / 测试 / 生产) 灵活设置
6. 日志流接口
wangt::LogMessage &wangt::Logger::stream()
{return impl_;
}
- 返回内部的 LogMessage 对象引用,允许通过 << 运算符添加日志内容
- 实现了类似流操作的接口,使用便捷直观
三、设计亮点
巧用析构函数:利用对象生命周期自动触发日志输出,无需手动调用输出函数,简化使用并避免遗漏
策略模式应用:通过 std::function 定义输出和刷新策略,实现了日志生成与输出的解耦
环境变量配置:支持通过环境变量动态设置日志级别,便于在不同环境中快速切换
分级处理:对 FATAL 级别日志进行特殊处理,确保严重错误能被及时发现
默认实现:提供合理的默认输出和刷新策略,开箱即用,同时支持自定义扩展
四、使用流程
- (可选)通过 setOutput () 和 setFlush () 设置自定义输出和刷新策略
- (可选)通过 setLogLevel () 设置全局日志级别
- 使用日志宏 (通常基于 Logger 类实现) 输出日志信息
- 系统会自动根据日志级别过滤、格式化并输出日志
五、总结
Logger 类通过精心设计的接口和实现,为日志系统提供了灵活、高效的核心控制能力。它既提供了开箱即用的默认行为,又保留了足够的扩展性,允许用户根据实际需求定制日志输出策略。
该实现的核心优势在于:
- 接口简洁易用,通过流操作符添加日志内容
- 职责清晰,专注于日志的控制和调度
- 扩展性好,支持自定义输出目标和格式
- 可靠性高,对严重错误有特殊处理机制
这一设计为构建完整、高效、可靠的日志系统奠定了坚实基础。
源码头文件
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include"LogMessage.hpp"
#include<functional>
namespace wangt{class Logger{public:using Outputfunc=std::function<void(const std::string &msg)>;using Flushfunc=std::function<void()>;static Outputfunc output_;static Flushfunc flush_;private:wangt::LogMessage impl_;//日志消息对象static wangt::LOG_LEVEL s_level_;public:static void setOutput(Outputfunc out);static void setFlush(Flushfunc flush);Logger(const wangt::LOG_LEVEL&le,const string &filename,const string &funcname,const int line);~Logger();wangt::LogMessage&stream();static void setLogLevel(LOG_LEVEL level);static LOG_LEVEL GetLogLevel();};wangt::LOG_LEVEL initLogLevel();
}
#endif
源码cpp文件
#include "Logger.hpp"
#include <iostream>
using namespace std;void wangt::Logger::setOutput(Outputfunc out)
{output_ = out;
}void wangt::Logger::setFlush(Flushfunc flush)
{flush_ = flush;
}wangt::Logger::Logger(const wangt::LOG_LEVEL &le, const string &filename, const string &funcname, const int line) : impl_(le, filename, funcname, line)
{
}wangt::Logger::~Logger()
{impl_ << '\n';output_(impl_.toString());flush_();if (impl_.getlevel() == LOG_LEVEL::FATAL){flush_();fprintf(stderr, "Process exit \n");abort(); //}
}wangt::LogMessage &wangt::Logger::stream()
{return impl_;
}void wangt::Logger::setLogLevel(LOG_LEVEL level)
{s_level_ = level;
}wangt::LOG_LEVEL wangt::Logger::GetLogLevel()
{return s_level_;
}wangt::LOG_LEVEL wangt::initLogLevel()
{if (::getenv("WANGT""LOG_TRACE")){return wangt::LOG_LEVEL::TRACE;}else if (::getenv("WANGT""LOG_DEBUG")){return wangt::LOG_LEVEL::DEBUG;}else{return wangt::LOG_LEVEL::INFO;}
}void defaultOutput(const string &msg)
{size_t n = fwrite(msg.c_str(), 1, msg.size(), stdout);
}void defaultFlush()
{fflush(stdout);
}wangt::Logger::Outputfunc wangt::Logger::output_ = defaultOutput;
wangt::Logger::Flushfunc wangt::Logger::flush_ = defaultFlush;wangt::LOG_LEVEL wangt::Logger::s_level_ = initLogLevel();