目录
日志接口
commons-loggin
slf4j
日志实现
log4j
logback
关系
Log4j 2与Log4j 1都是Apache旗下的日志框架,Log4j 2与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。
Commons Logging和Slf4j是日志门面(门面模式是软件工程中常用的一种软件设计模式,也被称为正面模式、外观模式。它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)。Log4j和Logback则是具体的日志实现方案。可以简单的理解为接口与接口的实现,调用者只需要关注接口而无需关注具体的实现,做到解耦。
比较常用的组合使用方式是Slf4j与Logback组合使用,Commons Logging与Log4j组合使用。
Logback必须配合Slf4j使用。由于Logback和Slf4j是同一个作者,其兼容性不言而喻。
Commons Logging实现机制
Commons Logging是通过动态查找机制,在程序运行时,使用自己的ClassLoader寻找和载入本地具体的实现。详细策略可以查看commons-logging-*.jar包中的org.apache.commons.logging.impl.LogFactoryImpl.java文件。由于Osgi不同的插件使用独立的ClassLoader,Osgi的这种机制保证了插件互相独立, 其机制限制了Commons Logging在Osgi中的正常使用。
Slf4j实现机制
Slf4j在编译期间,静态绑定本地的Log库,因此可以在Osgi中正常使用。它是通过查找类路径下org.slf4j.impl.StaticLoggerBinder,然后在StaticLoggerBinder中进行绑定。
日志实现框架
-
Jul:Java Util Logging,自Java1.4以来的官方日志实现。
-
Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。
-
Apache Log4j 2是apache开发的一款Log4j的升级产品,并且不兼容Log4j。
-
Logback是一个日志框架,Log4j是同一作者,都出自Ceki Gülcü之手。
Java 日志框架的选择
-
成本考虑:Logback文档免费。Logback的所有文档是全面免费提供的,不象Log4J那样只提供部分免费文档而需要用户去购买付费文档。
-
资源开销:Commons Logging相比较与SLF4J开销更高.
-
性能:Logback相比Log4j、Log4j2拥有更好的性能。Logback声称:某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在Logback中需要3纳秒,而在Log4J中则需要30纳秒。LogBack创建记录器(logger)的速度也更快:13毫秒,而在Log4J中需要23毫秒。更重要的是,它获取已存在的记录器只需94纳秒,而Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的。
log4j配置文件
### 注:log4j.properties配置文件要放在resources目录下
# 指定日志的输出级别与输出端(输出级别,自定义输出端名称,自定义输出端名称....)
log4j.rootLogger = trace,console,myFile,rollingFile,dailyFile,dbFile###### 控制台输出配置
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 使用PatternLayout来声明日志用自定义格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 针对PatternLayout来用conversionPattern设置格式
log4j.appender.console.layout.conversionPattern = %d [%t] %-5p [%c] - %m%n###### 文件输出配置
log4j.appender.myFile = org.apache.log4j.FileAppender
log4j.appender.myFile.layout = org.apache.log4j.PatternLayout
log4j.appender.myFile.layout.conversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
# 是否以追加日志的形式添加(默认就是true)
log4j.appender.myFile.append = true
# 指定日志的输出路径
log4j.appender.myFile.file = ./fileLog.log
# 指定日志的文件编码
log4j.appender.myFile.encoding = utf-8###### 文件自动按大小拆分配置
log4j.appender.rollingFile = org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.conversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
log4j.appender.rollingFile.append = true
log4j.appender.rollingFile.file = ./fileRollingFileLog.log
log4j.appender.rollingFile.encoding = UTF-8
# 文件内容超过2KB则进行拆分,拆分的最多文件由maxBackupIndex定义
log4j.appender.rollingFile.maxFileSize = 2KB
# 文件拆分的数量(这里是3),当文件拆分的数量超限时则最新拆分出的文件覆盖最老的日志文件
log4j.appender.rollingFile.maxBackupIndex = 3###### 文件自动按日期拆分配置
log4j.appender.dailyFile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.layout = org.apache.log4j.PatternLayout
log4j.appender.dailyFile.layout.conversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%t:%r] - [%p] %m%n
log4j.appender.dailyFile.append = true
log4j.appender.dailyFile.file = ./dailyRollingFile.log
log4j.appender.dailyFile.encoding = UTF-8
# 文件拆分的日期 正常按照 '.'yyyy-MM-dd 以天为拆分,这里我以每秒拆分一次
log4j.appender.dailyFile.datePattern = '.'yyyy-MM-dd HH-mm-ss# MySQL输出配置
log4j.appender.dbFile = org.apache.log4j.jdbc.JDBCAppender
log4j.appender.dbFile.layout = org.apache.log4j.PatternLayout
log4j.appender.dbFile.layout.conversionPattern = %p %r %c %t %d{yyyy/MM/dd HH:mm:ss:SSS} %m %l %F %L %% %n
log4j.appender.dbFile.URL = jdbc:mysql://localhost:3306/log4j?serverTimezone=GMT%2B8&useAffectedRows=true&useSSL=false
log4j.appender.dbFile.User = root
log4j.appender.dbFile.Password = 123
log4j.appender.dbFile.Sql=INSERT INTO log(project_name, create_date, level, category, file_name, thread_name, line, all_category, message) \
values('log4j_xiaofeng', '%d{yyyy-MM-dd HH:mm:ss}', '%p', '%c', '%F', '%t', '%L', '%l', '%m')
logback配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义日志格式参数,后面可以通过${myPattern}使用-->
<property name="myPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread] %-5level %msg%n"/>
<!--定义日志路径参数,后面可以通过${myPattern}使用-->
<property name="file_dir" value="D:/logs"/><!--定义FileAppender 用于在文件上输出日志-->
<appender name="fileAppend" class="ch.qos.logback.core.FileAppender">
<!--日志文件名称-->
<file>${file_dir}/fileLogback.log</file>
<!--配置日志输出格式,并引用 myPattern 自定的日志格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${myPattern}</pattern>
</encoder>
</appender><!--定义FileAppender 用于在文件上输出日志-->
<appender name="fileHtmlAppend" class="ch.qos.logback.core.FileAppender">
<file>${file_dir}/fileLogback.html</file>
<!--因为是要输出HTML格式,所以需要布局包装器一下-->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<!--设置最终的输出样式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%level%d{yyyy-MM-dd HH:mm:ss}%c%M%L%thread%m</pattern>
</layout>
</encoder>
</appender>
<!--配置日志记录器并设置日志记录器的打印级别-->
<root level="ALL">
<!--引入appender....-->
<appender-ref ref="fileAppend"/>
<appender-ref ref="fileHtmlAppend"/>
</root>
</configuration>拆分文档
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义日志格式参数,后面可以通过${myPattern}使用-->
<property name="myPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread] %-5level %msg%n"/>
<!--定义日志路径参数,后面可以通过${myPattern}使用-->
<property name="file_dir" value="D:/logs"/><!--定义RollingFileAppender 用于在文件上输出日志并拆分归档-->
<appender name="rollFileAppend" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--定义日志输出的路径-->
<!--这里的scheduler.manager.server.home 没有在上面的配置中设定,所以会使用java启动时配置的值-->
<!--比如通过 java -Dscheduler.manager.server.home=/path/to XXXX 配置该属性-->
<file>${scheduler.manager.server.home}/fileRollLogback.log</file>
<!--配置日志输出格式,并引用 myPattern 自定的日志格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${myPattern}</pattern>
</encoder>
<!--基于大小和时间滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--按照时间和压缩格式声明文件名 压缩文件为.gz-->
<fileNamePattern>${scheduler.manager.server.home}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
<!--按照文件大小拆分 每个文件达到500MB会自动压缩归档-->
<maxFileSize>500MB</maxFileSize>
</rollingPolicy>
</appender><!--配置日志记录器并设置日志记录器的打印级别-->
<root level="ALL">
<!--引入appender....-->
<appender-ref ref="rollFileAppend"/>
</root>
</configuration>过滤器及异步打印
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义日志格式参数,后面可以通过${myPattern}使用-->
<property name="myPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread] %-5level %msg%n"/><!--定义ConsoleAppender 用于在屏幕上输出日志-->
<appender name="consoleAppend" class="ch.qos.logback.core.ConsoleAppender">
<!--显示控制台日志颜色 System.err【红色】 System.out【默认白色】-->
<target>System.err</target>
<!--配置日志输出格式,并引用 myPattern 自定的日志格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${myPattern}</pattern>
</encoder><!--LevelFilter: 级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,
过滤器会根据onMath 和 onMismatch接收或拒绝日志。-->
<!--例如:将过滤器的日志级别配置为INFO,所有INFO级别的日志交给appender处理,非INFO级别的日志,被过滤掉。-->
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">-->
<!-- <level>INFO</level>-->
<!-- <onMatch>ACCEPT</onMatch>-->
<!-- <onMismatch>DENY</onMismatch>-->
<!-- </filter>-->
<!--ThresholdFilter: 临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,
过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。-->
<!-- 过滤掉所有低于 DEBUG 级别的日志,留下DEBUG及以上级别的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!--配置异步日志-->
<appender name="asyncAppend" class="ch.qos.logback.classic.AsyncAppender">
<!--要使用到异步的Appender-->
<appender-ref ref="consoleAppend"/>
</appender>
<!--配置日志记录器并设置日志记录器的打印级别-->
<root level="ALL">
<!--引入appender....-->
<appender-ref ref="asyncAppend"/>
</root>
</configuration>自定义logger
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义日志格式参数,后面可以通过${myPattern}使用-->
<property name="myPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %c [%thread] %-5level %msg%n"/>
<!--定义ConsoleAppender 用于在屏幕上输出日志-->
<appender name="consoleAppend" class="ch.qos.logback.core.ConsoleAppender">
<!--显示控制台日志颜色 System.err【红色】 System.out【默认白色】-->
<target>System.err</target>
<!--配置日志输出格式,并引用 myPattern 自定的日志格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${myPattern}</pattern>
</encoder>
</appender><!--additvity="false" 不继承父元素-->
<logger name="cn.xw" level="INFO" additvity="false">
<!--自定义logger中配置appender-->
<appender-ref ref="consoleAppend"/>
</logger>
</configuration>加载顺序
logback在启动的时候,会按照下面的顺序加载配置文 ①:如果java程序启动时指定了logback.configurationFile属性,就用该属性指定的配置文件。 如java -Dlogback.configurationFile=/path/to/mylogback.xml Test , 这样执行Test类的时候就会加载/path/to/mylogback.xml配置 ②:在classpath中查找 logback.groovy 文件 ③:在classpath中查找 logback-test.xml 文件 ④:在classpath中查找 logback.xml 文件 ⑤:如果是jdk6+,那么会调用ServiceLoader 查找com.qos.logback.classic.spi.Configurator接口的第一个实现类 ⑥:自动使用ch.qos.logback.classic.BasicConfigurator,在控制台输出日志 注:上面的顺序表示优先级,使用java -D配置的优先级最高,只要获取到配置后就不会再执行下面的流程。 相关代码可以看ContextInitializer#autoConfig()方法。