1.spdlog源码解读(三)
2.easylogging源码学习笔记(6)
3.Gin源码分析 - 中间件(3)- Logger
4.常见log日志的源码使用方法详细解析
spdlog源码解读(三)
重构代码以提升效率与可维护性是软件开发中的重要实践。针对日志记录功能,源码原代码存在重复实现与参数传递问题,源码本文将对日志记录功能进行优化,源码通过创建Logger类与Registry类实现日志管理的源码单例模式,以及引入sink机制来封装输出目的源码源码分享zxhost地,实现多输出日志打印。源码
首先,源码引入单例模式通过Registry类管理日志记录器实例,源码确保全局只有一个实例,源码简化代码结构并提升管理效率。源码其次,源码针对同步与异步需求,源码myibatis源码解析创建Logger类与继承于它的源码AsyncLogger类,分别满足不同场景下的源码日志记录需求。
为实现灵活的日志输出,本文提出创建基类base_sink,并定义两个子类,分别用于将日志文本写入文件与进行彩色输出。通过此设计,spdlog能够通过多态特性实现不同输出端的日志打印,简化日志配置与实现。
在完成上述优化后,代码将更加简洁、易于维护,底部共振源码并支持多种日志输出方式。具体实现细节已在GitHub仓库中详细展示,供读者参考与深入理解。
easylogging源码学习笔记(6)
`LOG` 是默认日志、CLOG自定义日志、LOG_IF条件日志
特殊日志
LOG_EVERY_N、LOG_AFTER_N、LOG_N_TIMES
for (int i = 1; i <= ; ++i) {
LOG_EVERY_N(2, INFO) << "Logged every second iter";
}// 5 logs written; 2, 4, 6, 7,
for (int i = 1; i <= ; ++i) {
LOG_AFTER_N(2, INFO) << "Log after 2 hits; " << i;
}// 8 logs written; 3, 4, 5, 6, 7, 8, 9,
for (int i = 1; i <= ; ++i) {
LOG_N_TIMES(3, INFO) << "Log only 3 times; " << i;
}// 3 logs writter; 1, 2, 3
条件日志和特殊日志可以搭配使用
* `VLOG_IF(condition, verbose-level)`
* `CVLOG_IF(condition, verbose-level, loggerID)`
* `VLOG_EVERY_N(n, verbose-level)`
* `CVLOG_EVERY_N(n, verbose-level, loggerID)`
* `VLOG_AFTER_N(n, verbose-level)`
* `CVLOG_AFTER_N(n, verbose-level, loggerID)`
* `VLOG_N_TIMES(n, verbose-level)`
* `CVLOG_N_TIMES(n, verbose-level, loggerID)`
日志详细等级判定
if (VLOG_IS_ON(2)) {
// Verbosity level 2 is on for this file
}
性能追踪
* `TIMED_FUNC(obj-name)`
* `TIMED_SCOPE(obj-name, block-name)`
* `TIMED_BLOCK(obj-name, block-name)`
这些宏实际上都是关于el::base::type::PerformanceTrackerPtr,一个指向el::base::PerformanceTracker的指针
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
PerformanceTracker::PerformanceTracker(const std::string& blockName,
base::TimestampUnit timestampUnit,
const std::string& loggerId,
bool scopedLog, Level level) :
m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
// We store it locally so that if user happen to change configuration by the end of scope
// or before calling checkpoint, we still depend on state of configuration at time of construction
el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
if (m_enabled) {
base::utils::DateTime::gettimeofday(&m_startTime);
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
}
在构造函数中获取一个时间,
PerformanceTracker::~PerformanceTracker(void) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
if (m_enabled) {
base::threading::ScopedLock scopedLock(lock());
if (m_scopedLog) {
base::utils::DateTime::gettimeofday(&m_endTime);
base::type::string_t formattedTime = getFormattedTimeTaken();
PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
data.init(this);
data.m_formattedTimeTaken = formattedTime;
PerformanceTrackingCallback* callback = nullptr;
for (const std::pair& h
: ELPP->m_performanceTrackingCallbacks) {
callback = h.second.get();
if (callback != nullptr && callback->enabled()) {
callback->handle(&data);
}
}
}
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
}
在析构函数中获取一个时间,处理时间data,使用PerformanceTrackingCallback类型指针callback,嗨家教源码并在callback->handle(&data)中处理输出。
由于定义了ELPP_FEATURE_PERFORMANCE_TRACKING,因此在初始化(INITIALIZE_EASYLOGGINGPP)中实际上是安装了一个base::DefaultPerformanceTrackingCallback。
在PerformanceTracker类的handle函数中,callback是一个PerformanceTrackingCallback类型指针,由于安装的是DefaultPerformanceTrackingCallback对象,因此是一个基类指针指向了派生类对象。处理输出的逻辑在DefaultPerformanceTrackingCallback类的handle函数中。
DefaultPerformanceTrackingCallback类的handle函数首先会将数据成员m_data的指针赋值给函数参数,并创建一个base::type::stringstream_t类型的对象ss用于构建输出内容。根据m_data的dataType,输出不同的读dubbo源码信息。在输出时,会使用el::base::Writer类构造并输出内容。
Gin源码分析 - 中间件(3)- Logger
本文深入剖析Gin框架内置中间件Logger,详细阐述其四种创建形式。基本形式以默认配置输出日志至标准输出。自定义格式器形式允许用户调整日志输出格式。指定输出流形式则灵活地将日志输出至特定写入器,同时可忽略指定路径的日志。复杂配置形式提供高度定制化,是创建中间件的高级手段。深入探讨LoggerConfig结构体,解析其三个关键属性:日志格式、输出器和忽略路径。LogFormatter方法实现日志的格式化,包含辅助函数进行颜色调整,如根据HTTP响应码和请求类型设置显示颜色。defaultLogFormatter方法提供默认的日志格式化操作。详细解析LoggerWithConfig方法,该方法获取配置参数并判断输出环境,随后将忽略路径保存为映射,记录过滤的路径。计算处理时间和构建日志字符串,输出至指定写入器。
常见log日志的使用方法详细解析
日志在程序开发中起着至关重要的作用,它能帮助我们调试错误并记录关键信息。常见的日志框架包括Java自带的原生日志、log4j以及Slf4j等。
日志级别是控制输出信息的关键,通常分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE和ALL,级别越高,信息越详细。Java.util.Logger,如在源代码中使用`Logger`,可以通过设置级别来调整输出,例如,`logger.setLevel(Level.ALL)`会显示所有级别的信息,而`logger.setLevel(Level.WARNING)`则只会显示严重和警告级别的信息。
log4j则通常在XML配置文件中配置,比如导入依赖和配置``元素。通过这种方式,可以精细地控制每个日志条目的格式和输出位置。log4j2的配置文件如`log4j2.xml`,提供了丰富的自定义选项。
Slf4j作为当前主流的日志框架,支持参数化输出,只需在类头引入`import org.slf4j.Logger`和`LoggerFactory.getLogger`,并在代码中调用相关方法。在引入依赖时,可能出现`SLF4J: Failed to load class`的问题,解决方法通常是检查类路径和slf4j的绑定。Slf4j的输出信息中包含类路径信息,便于追踪问题来源。
总结来说,log日志的使用方法因框架而异,但核心在于控制输出级别和配置细节,以满足不同开发阶段的需求。通过灵活运用这些工具,可以提高程序的可维护性和可读性。