Java的日志系统经过了漫长的发展,最后确认为slf4j加logback的结构。充分证明了logback的生命力。

java日志的发展

1 起步阶段
在Java发展的初期是没有真正的日志框架的,当时为了排查问题都是使用System.out或者System.err来进行关键信息的记录。然后利用系统的重定向功能将这些关键信息,记录到特定的文件之中。起到记录日志排查问题的作用。这样做有一个很大的缺陷:不灵活不可配置。代码已发布到生产环境便不可更改,除非重新发布代码。

2 日志框架出现
有需求就会有人提供服务,面对Java的这种日志问题。出现了第一个试图解决Java日志问题的框架–Log4j。log4j确实是一个开创性的产品,里面提出的很多理念都深深地影响着现在的日志系统。最重要的是他几乎解决了当时Java日志系统的所有问题。包括后面的几个日志框架都没有替代它,直到现在他还有很强的生命力。

3 SUN公司重视日志框架
在Log4j出现之后,SUN公司意识到了日志系统的重要性。于是在JDK1.4之中也加入了logging日志模块。他没有直接将log4j收入囊中,而是参照log4j自己写了一套。但是写的并没有log4j好。最后自己就放弃了。

4 Apache公司试图解决日志问题
common-logging是apache提供的一个通用的日志接口。用户可以自由选择第三方的日志组件作为具体实现,像log4j,或者jdk自带的logging, common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库。这样做的好处是避免了日志方案的直接耦合。接口是commons-logging实现确可以随时更改而不用更改代码。但是他也有很大的缺陷:由于它使用了ClassLoader寻找和载入底层的日志库, 导致了象OSGI这样的框架无法正常工作,因为OSGI的不同的插件使用自己的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging无法工作。所以几乎没有人使用这个日志框架

5 日志框架的确定
直到SLF4J加Logback的出现,Java的日志系统终于天下归一统了。slf4j类似commons-logging,向应用层提供API接口,所有用户的编程都是面向slf4j的,而底层的实现可以是任何日志框架,现在最好的是logback。他们的优点我就不说了,网上一大堆。

logback配置详解

下面的配置文件可以认为是一个最全的logback的配置文件。在日常的开发中,我们只需要摘取其中的子集就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="5000">
<contextName>logback_context</contextName>
<property name="log.dir" value="/home/chenglai.guo/log" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class:%line - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.dir}/%d{yyyy-MM-dd}.error.log</FileNamePattern>
<MaxHistory>10</MaxHistory>
</rollingPolicy>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.dir}/%d{yyyy-MM-dd}.error.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>1000MB</MaxFileSize>
</triggeringPolicy>
</appender>
<appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.dir}/dbaccess.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %class:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="org.springframework" level="ERROR"/>
<logger name="org.apache.ibatis" level="ERROR"/>
<logger name="java.sql.Connection" level="ERROR"/>
<logger name="java.sql.Statement" level="ERROR"/>
<logger name="java.sql.PreparedStatement" level="ERROR"/>
<logger name="com.qunar.des.common.dao" additivity="false" level="INFO">
<appender-ref ref="SQL_FILE"/>
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>