日志模块

在实际的生产应用中,养成良好的埋点打日志的习惯,是一个优秀软件开发工程师必不可缺的技能。丰富的日志有助于我们排查线上出现的问题。

本文介绍了Java中的日志,并给出了在实际应用中配置的日志模块的实例。

日志的级别

  • 日志信息的优先级从高到底有ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程序

日志信息的优先级

  • org.apache.log4j.Level类提供以下级别,但也可以通过Level类的子类自定义级别
Level 描述
ALL 各级包括自定义级别
DEBUG 指定细粒度信息事件是最有用的应用程序调试
ERROR 错误事件可能仍然允许应用程序继续运行
FATAL 非常严重的错误事件,这可能导致应用程序的终止
INFO 指定能够突出在粗粒度级别的应用程序运行情况的信息
OFF 这是最高等级,是为了关闭日志记录
TRACE 指定细粒度比DEBUG更低的信息事件
WARN 指定具有潜在危害的情况

日志级别是如何工作的

  • 级别p的级别使用q,在记录日志请求时,如果p>=q启用
  • 这条规则是log4j的核心,它假设级别是有序的
  • 标准级别的关系如下:

    ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF

在实际开发中使用日志功能

slf4j+logback

项目依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>

配置文件

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
<?xml version="1.0" encoding="UTF-8" ?>
<!--
scan:
当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:
设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:
当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<jmxConfigurator/>
<!--定义变量-->
<property name="log_dir" value="/opt/logs"/>

<!-- 将日志添加到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
[%-5level] [%thread] [%logger{36}] [%d{yyyy-MM-dd HH:mm:ss.SSS}] %msg%n
</pattern>
</layout>
</appender>

<!--将日志添加到文件-->
<!--
<file>:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
<append>:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
<encoder>:对记录事件进行格式化。(具体参数稍后讲解 )
<prudent>:如果是 true,日志会被安全的写入文件,即使其他的FileAppender也在向此文件做写入操作,效率低,默认是 false。
<rollingPolicy>:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。
<triggeringPolicy >: 告知 RollingFileAppender 合适激活滚动。
-->
<appender name="logger" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log_dir}/demo.log</File>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_dir}/demo.log.%d{yyyy-MM-dd}</fileNamePattern>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] [%thread] [%logger{36}] [%d{yyyy-MM-dd HH:mm:ss.SSS}] %msg%n</pattern>
<charset class="java.nio.charset.Charset">UTF-8</charset>
</encoder>
</appender>


<!--日志级别-->
<!--
ERROR > WARN > INFO > DEBUG
只有大于等于当前级别的日志消息才会被打印
-->

<!--这种logger向上级root传递日志-->
<logger name="com.winsky.logs"/>

<!--没有设置addtivity,默认为true,将此logger的打印信息向上级传递;-->
<logger name="logger_demo" additivity="false">
<level value="INFO"/>
<appender-ref ref="logger"/>
<appender-ref ref="STDOUT"/>
</logger>

<root level="ERROR">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

java使用demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class LogFactory {
private static final Logger log = LoggerFactory.getLogger("logger_demo");

public static Logger getLog() {
return log;
}
}

public class LogDemo {
private static Logger log = LogFactory.getLog();

public static void main(String[] args) {
log.trace("======trace");
log.debug("======debug");
log.info("======info");
log.warn("======warn");
log.error("======error");
}
}

log4j

项目依赖

  • slf4j-api.jar
  • slf4j-log4j.jar

配置文件

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
# 优先级从高到低分别是 ERROR、WARN、INFO、DEBUG
# 设置日志目录
log=/data/logs
log4j.rootLogger=ERROR,rootDailyFile
#设置日志模块是否向上冒泡到根模块
log4j.additivity.sysLogger=true
log4j.additivity.synLogger=true
log4j.additivity.httpLogger=true
#
#
#输出到控制台
log4j.appender.systemOut=org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout=org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern=[%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l] %m%n
log4j.appender.systemOut.Threshold=DEBUG
log4j.appender.systemOut.ImmediateFlush=TRUE
log4j.appender.systemOut.Target=System.out
#
#输出到文件
# 系统日志数据库存储模块
log4j.appender.rootDailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.rootDailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.rootDailyFile.layout.ConversionPattern=[%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l] %m%n
log4j.appender.rootDailyFile.Threshold=DEBUG
log4j.appender.rootDailyFile.ImmediateFlush=TRUE
log4j.appender.rootDailyFile.Append=TRUE
log4j.appender.rootDailyFile.File=${log}/root.log
log4j.appender.rootDailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.rootDailyFile.Encoding=UTF-8
#
#
# 系统日志数据库存储模块
log4j.logger.sysLogger=ERROR,sysDailyFile
log4j.appender.sysDailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.sysDailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.sysDailyFile.layout.ConversionPattern=[%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l] %m%n
log4j.appender.sysDailyFile.Threshold=DEBUG
log4j.appender.sysDailyFile.ImmediateFlush=TRUE
log4j.appender.sysDailyFile.Append=TRUE
log4j.appender.sysDailyFile.File=${log}/sysLog.log
log4j.appender.sysDailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.sysDailyFile.Encoding=UTF-8
#
#
# http模块
log4j.logger.httpLogger=INFO,httpDailyFile
log4j.appender.httpDailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.httpDailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.httpDailyFile.layout.ConversionPattern=[%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l] %m%n
log4j.appender.httpDailyFile.Threshold=DEBUG
log4j.appender.httpDailyFile.ImmediateFlush=TRUE
log4j.appender.httpDailyFile.Append=TRUE
log4j.appender.httpDailyFile.File=${log}/http.log
log4j.appender.httpDailyFile.DatePattern='.'yyyy-MM-dd
log4j.appender.httpDailyFile.Encoding=UTF-8

Java使用demo

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
public class LogFactory {
private static final Log sysLogger;
private static final Log httpLogger;

static {
sysLogger = LogFactory.getLog("sysLogger");
httpLogger = LogFactory.getLog("httpLogger");
}

public static Log getSysLogger() {
return sysLogger;
}

public static Log getHttpLogger() {
return httpLogger;
}
}

public class LoggerDemo {
private static final Log sysLogger = LogFactory.getSysLogger();

public static void main(String[] args) {
sysLogger.info("log4j日志模块测试");
}
}