云南网官方网站,360建筑网的内容百度可以查到吗,线上营销策略,东莞做网页建站公司前言
随着互联网和大数据的迅猛发展#xff0c;分布式日志系统和日志分析系统已广泛应用#xff0c;几乎所有应用程序都使用各种日志框架记录程序运行信息。因此#xff0c;作为工程师#xff0c;了解主流的日志记录框架非常重要。虽然应用程序的运行结果不受日志的有无影…前言
随着互联网和大数据的迅猛发展分布式日志系统和日志分析系统已广泛应用几乎所有应用程序都使用各种日志框架记录程序运行信息。因此作为工程师了解主流的日志记录框架非常重要。虽然应用程序的运行结果不受日志的有无影响但没有日志的应用程序是不完整的甚至可以说是有缺陷的。优秀的日志系统可以记录操作轨迹、监控系统运行状态和解决系统故障。 Java 日志框架进化史
早期 Java 日志框架没有制定统一的标准使得很多应用程序会同时使用多种日志框架。Java 日志框架的发展历程大致可分为以下几个阶段 1.**Log4j**Apache Log4j是一种基于Java的日志记录工具。该项目由Ceki Gülcü于1999年创建并几乎成为了Java日志框架的实际标准。
2.**JUL**Apache 希望将 Log4j 引入 jdk不过被 sun 公司拒绝了。随后sun 模仿 Log4j在 jdk1.4 中引入了 JULjava.util.logging。
3.**Commons Logging**为了解耦日志接口与实现Apache在2002年推出了JCLJakarta Commons Logging。JCL定义了一套日志接口具体的实现由Log4j或JUL完成。Commons Logging使用动态绑定来实现日志记录编码时只需要使用它定义的接口即可程序运行时会使用ClassLoader来查找和加载底层的日志库因此可以灵活选择Log4j或JUL来实现日志功能。
4.**Slf4jLogback**Ceki Gülcü与Apache基金会在Commons-Logging标准上存在分歧。后来Ceki Gülcü离开了Apache并创建了Slf4j和Logback两个项目。Slf4j是一个日志门面仅提供接口可以支持Logback、JUL、log4j等日志实现。而Logback则提供了具体的实现。相比于log4jLogback具有更快的执行速度和更完善的功能。
5.**Log4j 2**为了保持在Java日志领域的地位防止JCL和Log4j被Slf4j和Logback取代Apache在2014年推出了Log4j 2。Log4j 2与log4j不兼容经过大量深度优化其性能得到显著提升。 日志框架介绍
在上文中已经提及目前常用的日志框架有 Log4jLog4j 2Commons LoggingSlf4jLogbackJUL。这些日志框架可以分为两种类型门面日志和日志系统。
日志门面
**日志门面Logging Facade**是一种设计模式用于在应用程序中实现日志记录的抽象层。它提供了一组统一的接口和方法即相应的 API而不提供具体的接口实现。日志门面在使用时可以动态或者静态地指定具体的日志框架实现解除了接口和实现的耦合使用户可以灵活地选择日志的具体实现框架。
日志系统
**日志系统Logging System**是指用于记录和管理应用程序运行时产生的日志信息的软件工具或框架。与日志门面相对它提供了具体的日志接口实现应用程序通过它执行日志打印的功能如日志级别管理、日志格式化、日志输出目标设置等。常见的日志系统包括Log4j、Logback、Java Util Logging等。 通过使用日志门面我们可以在应用程序中使用统一的API进行日志记录而具体的日志实现可以根据需要选择和配置。这样我们可以根据项目需求和团队喜好来灵活选择、切换和配置日志系统而不会对应用程序代码造成太大影响。
避免环形依赖
Slf4j 的作者 Ceki Gülcü 当年因为觉得 Commons-Logging 的 API 设计的不好性能也不够高因而设计了 Slf4j。而他为了 Slf4j 能够兼容各种类型的日志系统实现还设计了相当多的 adapter 和 bridge 来连接如下图所示 鉴于此在引入日志框架依赖的时候要尽力避免比如以下组合就不能同时出现
•jcl-over-slf4j 和 slf4j-jcl
•log4j-over-slf4j 和 slf4j-log4j12
•jul-to-slf4j 和 slf4j-jdk14
日志框架的使用选择
常用的组合使用方式是 Slf4j Logback 组合使用Commons Logging Log4j 组合使用。
推荐
Slf4j Logback
原因
1. Slf4j 实现机制决定 Slf4j 限制较少使用范围更广。相较于 Commons-LoggingSlf4j 在编译期间便静态绑定本地的 Log 库其通用性要好得多
2. Logback 拥有更好的性能。Logback 声称某些关键操作比如判定是否记录一条日志语句的操作其性能得到了显著的提高这个操作在 Logback 中只需 3 ns而在 Log4j 则需要 30 ns
3. Slf4j 支持参数化使用占位符号代码更为简洁如下例子
// 在使用 Commons-Logging 时通常的做法是
if(log.isDebugEnabled()){ log.debug(User name user.getName() buy goods id good.getId());
} // 在 Slf4j 阵营你只需这么做
log.debug(User name{} ,buy goods id {}, user.getName(),good.getId());4. Logback 的所有文档是免费提供的Log4j 只提供部分免费文档而需要用户去购买付费文档
5. MDC (Mapped Diagnostic Contexts) 用 Filter将当前用户名等业务信息放入 MDC 中在日志 format 定义中即可使用该变量。具体而言在诊断问题时通常需要打出日志。如果使用 Log4j则只能降低日志级别但是这样会打出大量的日志影响应用性能如果使用 Logback保持原定日志级别而过滤某种特殊情况如 Alice 这个用户登录日志将打在 DEBUG 级别而其它用户可以继续打在 WARN 级别。实现这个功能只需加 4 行 XML 配置
6. 自动压缩日志。RollingFileAppender 在产生新文件的时候会自动压缩已经打出来的日志文件。压缩过程是异步的因此在压缩过程中应用几乎不会受影响。 Slf4jLogback入门实践
maven依赖
pom.xml
!--日志框架接口--
dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactId
/dependency
!--日志框架接口实现--
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactId
/dependency
!--日志框架核心组件--
dependencygroupIdch.qos.logback/groupIdartifactIdlogback-core/artifactId
/dependency!--自动化注解工具--
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.16/version
/dependency配置文件
logback.xml
?xml version1.0 encodingUTF-8?
configuration!--默认日志配置--include resourceorg/springframework/boot/logging/logback/defaults.xml/!-- 控制台日志 --appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoder charsetUTF-8pattern${CONSOLE_LOG_PATTERN}/pattern/encoder/appender!-- Info日志 --appender nameFILE-INFO classch.qos.logback.core.rolling.RollingFileAppenderfile${LOG_PATH}/${LOG_FILE}-info.log/fileappendtrue/appendfilter classch.qos.logback.classic.filter.LevelFilterlevelINFO/levelonMatchACCEPT/onMatchonMismatchNEUTRAL/onMismatch/filterrollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${LOG_FILE}-info-%d{yyyy-MM-dd}.%i.log/fileNamePattern !-- 日志文件的路径和名称 --timeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize200MB/maxFileSize !-- 单个日志文件的最大大小 --/timeBasedFileNamingAndTriggeringPolicymaxHistory15/maxHistory !-- 保留的历史日志文件数量 --totalSizeCap2GB/totalSizeCap !-- 所有日志文件的总大小上限 --cleanHistoryOnStarttrue/cleanHistoryOnStart !-- 在启动时清除历史日志文件 --/rollingPolicyencoder charsetUTF-8pattern${FILE_LOG_PATTERN}/pattern/encoder/appender!-- Warn日志 --appender nameFILE-WARN classch.qos.logback.core.rolling.RollingFileAppenderfile${LOG_PATH}/${LOG_FILE}-warn.log/fileappendtrue/appendfilter classch.qos.logback.classic.filter.LevelFilterlevelWARN/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterrollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${LOG_FILE}-warn-%d{yyyy-MM-dd}.%i.log/fileNamePattern !-- 日志文件的路径和名称 --timeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize200MB/maxFileSize !-- 单个日志文件的最大大小 --/timeBasedFileNamingAndTriggeringPolicymaxHistory15/maxHistory !-- 保留的历史日志文件数量 --totalSizeCap2GB/totalSizeCap !-- 所有日志文件的总大小上限 --cleanHistoryOnStarttrue/cleanHistoryOnStart !-- 在启动时清除历史日志文件 --/rollingPolicyencoder charsetUTF-8pattern${FILE_LOG_PATTERN}/pattern/encoder/appender!-- Error日志 --appender nameFILE-ERROR classch.qos.logback.core.rolling.RollingFileAppenderfile${LOG_PATH}/${LOG_FILE}-error.log/fileappendtrue/appendfilter classch.qos.logback.classic.filter.LevelFilterlevelERROR/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filterrollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_PATH}/${LOG_FILE}-error-%d{yyyy-MM-dd}.%i.log/fileNamePatterntimeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATPmaxFileSize200MB/maxFileSize/timeBasedFileNamingAndTriggeringPolicymaxHistory15/maxHistorytotalSizeCap2GB/totalSizeCapcleanHistoryOnStarttrue/cleanHistoryOnStart/rollingPolicyencoder charsetUTF-8pattern${FILE_LOG_PATTERN}/pattern/encoder/appender!-- 异步输出 --appender nameinfo-asyn classch.qos.logback.classic.AsyncAppenderappender-ref refFILE-INFO/queueSize512/queueSize !-- 异步队列的大小 --/appenderappender namewarn-asyn classch.qos.logback.classic.AsyncAppenderappender-ref refFILE-WARN/queueSize512/queueSize !-- 异步队列的大小 --/appenderappender nameerror-asyn classch.qos.logback.classic.AsyncAppenderappender-ref refFILE-ERROR/queueSize512/queueSize/appender!-- 应用日志 --logger namecom.improve.fuqige.bronze additivityfalseappender-ref refCONSOLE/appender-ref refFILE-INFO/appender-ref refFILE-WARN/appender-ref refFILE-ERROR//logger!-- 总日志出口 --root level${logging.level.root}appender-ref refCONSOLE/appender-ref refinfo-asyn/appender-ref refwarn-asyn/appender-ref referror-asyn//root
/configurationapplicantion.properties
logging.filefuqige-bronze
logging.pathXXXXXX/Logs/XXXXXX
logging.level.rootinfo
logging.level.com.improve.fuqige.bronzeinfo
logging.pattern.console%cyan(%d{yyyy-MM-dd HH:mm:ss.SSS}) %yellow([%thread]) %highlight(%-5level) %boldGreen(%logger{80}[LineNumber:%L]): %highlight(%msg%n)
logging.pattern.file%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{requestId}] %-5level --- [%thread] %logger{80}[LineNumber:%L]: %msg%n测试用例
Slf4j
RestController
RequestMapping(/test)
public class TestController {GetMapping(/hello)public String hello() {log.info(进来了!);log.warn(进来了!);log.error(进来了!);return hello, world! requestId MDC.get(requestId);}
}参考资料
Java 日志框架 https://zhuanlan.zhihu.com/p/365154773
SLF4J框架常见的用法和最佳实践 https://juejin.cn/post/7215569601161166906
作者京东零售 张洪
来源京东云开发者社区 转载请注明来源