Java的日志体系

Java的日志有很多框架,框架里又有很多概念,初次接触的时候很容易让人摸不着北,这里简单整理一下。

框架

日志框架主要分为两种,一种是具体实现,一种是抽象层。

前者包括Log4jLogback以及Java自带的java.util.logging等,都是拿来就可以直接调用的库。

后者如SLF4j,是一个抽象层,本质上是一组利用了外观模式的API,它不提供日志的具体实现,而是将具体实现交给上一类框架,你的代码调用的是SLF4J的API而不是某一个特定的日志框架,这样做的好处是将代码和具体的日志框架解耦,你可以在不做任何代码更改的情况下更换日志框架。

举个例子,比如一开始使用的框架是Log4j:

1
2
3
4
5
6
7
8
9
10
import org.apache.log4j.Logger;

class Scratch {

private static Logger logger = Logger.getLogger(Scratch.class);

public static void main(String[] args) {
logger.info("test");
}
}

后来要把框架换成java.util.logging,虽然方法名一样,但是支持的参数不同,所以代码就需要改成:

1
2
3
4
5
6
7
8
9
10
import java.util.logging.Logger;

class Scratch {

private static Logger logger = Logger.getLogger(Scratch.class.getName());

public static void main(String[] args) {
logger.info("test");
}
}

但是如果使用的是SLF4J,代码就变成了:

1
2
3
4
5
6
7
8
9
10
11
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class Scratch {

private static Logger logger = LoggerFactory.getLogger(Scratch.class.getName());

public static void main(String[] args) {
logger.info("test");
}
}

因为依赖的是SLF4J,所以无论具体的实现框架怎么换,都不用修改代码,只需引入不同的依赖和配置文件就行了。

概念

总的来说Java的日志体系里的经常涉及概念一共有三种,在不同的框架里名称可能有所区别但是做的事情都差不多。

Logger是用来触发日志的对象,比如上面示例代码里的logger,在需要生成日志的地方调用它,然后它会将日志传递给AppenderAppender负责将日志输出到指定的地方,比如控制台、文件等,在输出之前,Appender还会用Layout来将日志格式化成指定的格式。

Logger

Logger在代码里实例化,获取的方式根据框架不同而有所区别,比如Log4j是用静态类来获取:

1
private static Logger logger = Logger.getLogger(Scratch.class);

SLF4j是利用工厂类来获取:

1
private static Logger logger = LoggerFactory.getLogger(Scratch.class.getName());

它们接受的参数会被用来作为logger的标识符,一般是String类型(Log4j提供了一个接受class的便捷方法),如果同名的logger已经存在则会直接返回。

最佳实践是传入当前类的类名来作为标识符。

Appender

Appender通常在配置文件里来定义,它用来将日志输出到指定的地方,同一条日志可以被多个Appender处理,比如同时输出到控制台和文件,输出之前会用Layout来格式化。

Layout

Layout通常也在配置文件里定义,可以用来指定输出的日志的格式,比如java.util.logging中的XMLFormatter可以将日志格式化成XML(此框架中的LayoutFormatter)。

常用的Layout还有PatternLayout,可以自己写占位符来指定格式,部分占位符如下:

Field Placeholder
message %m
level %p
exception %e
thread %t
logger %c
method %m

比如,如果指定的PatternLayout[%p] %t: %m, 那么日志输出就会是:

1
2
3
4
[INFO] main: initializing worker threads
[DEBUG] worker: listening on port 12222
[INFO] worker: received request from 192.168.1.200
[ERROR] worker: unknown request ID from 192.168.1.200

配置

Log4j

Log4j会在项目目录下搜索一个名叫log4j.propertie的文件并将此作为配置文件,在Log4j 1中格式还可以是XML,所以文件也可以是log4j.xml

Log4j 2中格式可以是XML, JSON, 和YAML

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Root logger option
log4j.rootLogger=DEBUG, stdout, file

# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\log4j-application.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

Logback

Logback也会在项目目录下搜索名为logback.xml的文件来作为配置文件,它还支持Groovy,所以也可以是logback.groovy

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>

<logger name="com.mkyong" level="debug" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>

<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

SLF4J

SLF4J没有自己的配置,只需引入依赖并提供对应框架的配置文件就可以了,比如要把SLF4J结合Log4j一起用的话,可以引入如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.7</version>
</dependency>

然后再提供Log4j的配置文件就可以了。

用Demo验证ArrayList的线程不安全

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×