1. 简介

1.1 认识日志框架

在项目开发中,使用日志非常重要,不管是记录运行情况还是定位线上问题,都离不开对日志的分析。在 Java 领域里存在着多种日志框架,如 JCL、SLF4J、Jboss-logging、jUL、log4j、log4j2、logback 等等。

日志分类 描述 举例
日志门面(日志抽象层) 为 Java 日志访问提供一套标准和规范的 API 框架,其主要意义在于提供接口。 JCL(Jakarta Commons Logging)、SLF4j(Simple Logging Facade for Java)、jboss-logging
日志实现 日志门面的具体的实现 Log4j、JUL(java.util.logging)、Log4j2、Logback

通常情况下,日志由一个日志门面日志实现组合搭建而成,SpringBoot 选用的是 SLF4j + logback。

SLF4J 是目前市面上最流行的日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有 log4j,logback,java.util.logging 等,它们才实现了具体的日志系统的功能。

Logback 是 Log4j 的改进版本,而且原生支持 SLF4J(因为是同一作者开发的),因此 Logback+SLF4J 的组合是日志框架的最佳选择,而且 Logback 的配置可以是 XML 或 Groovy 代码。

1.2 日志级别

常见的日志级别如下(优先级依次升高)。

序号 日志级别 说明
1 trace 追踪,指明程序运行轨迹。
2 debug 调试,实际应用中一般将其作为最低级别,而 trace 则很少使用。
3 info 输出重要的信息,使用较多。
4 warn 警告,使用较多。
5 error 错误信息,使用较多。

1.3 日志输出格式

序号 输出格式 说明
1 %d{yyyy-MM-dd HH:mm:ss, SSS} 日志生产时间,输出到毫秒的时间
2 %-5level 输出日志级别,-5 表示左对齐并且固定输出 5 个字符,如果不足在右边补 0
3 %logger 或 %c logger 的名称
4 %thread 或 %t 输出当前线程名称
5 %p 日志输出格式
6 %message 或 %msg 或 %m 日志内容,即 logger.info(“message”)
7 %n 换行符
8 %class 或 %C 输出 Java 类名
9 %file 或 %F 输出文件名
10 %L 输出错误行号
11 %method 或 %M 输出方法名
12 %l 输出语句所在的行数, 包括类名、方法名、文件名、行数
13 hostName 本地机器名
14 hostAddress 本地 ip 地址

1.4 yaml中配置日志级别

可以在 yaml 配置文件中设置日志级别,但一般我们会在 logback.xml 中进行配置。

  1. logging: # 设置日志级别
  2. level:
  3. com:
  4. xuwei:
  5. platformserver:
  6. trace

2. Slf4j+Logback使用

2.1 引入所需依赖

Spring Boot 的核心启动器 spring-boot-starter 引入了 spring-boot-starter-logging,spring-boot-starter-logging 的 Maven 依赖不但引入了 logback-classic (包含了日志框架 SLF4J 的实现),还引入了 log4j-to-slf4j(log4j 的替换包)jul-to-slf4j (JUL 的替换包)。

  1. <!-- 日志框架 -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-logging</artifactId>
  5. </dependency>

2.2 排除第三方框架依赖日志框架

当我们引入了依赖了其他日志框架的第三方框架(例如 Hibernate)时,只需要把这个框架所依赖的日志框架排除,即可实现日志框架的统一:

  1. <dependency>
  2. <groupId>org.apache.activemq</groupId>
  3. <artifactId>activemq-console</artifactId>
  4. <version>${activemq.version}</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>commons-logging</groupId>
  8. <artifactId>commons-logging</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>

2.3 slf4j 简单使用。

  1. @SpringBootTest
  2. @Slf4j
  3. class PlatformServerApplicationTests {
  4. private static final Logger logger = LoggerFactory.getLogger(PlatformServerApplicationTests.class);
  5. @Test
  6. void contextLoads() {
  7. //日志级别 由低到高
  8. logger.trace("trace 级别日志");
  9. logger.debug("debug 级别日志");
  10. logger.info("info 级别日志");
  11. logger.warn("warn 级别日志");
  12. logger.error("error 级别日志");
  13. }
  14. // 和上面功能一样,需引入lombok依赖
  15. @Test
  16. void slf4jTest() {
  17. log.trace("trace 级别日志");
  18. log.debug("debug 级别日志");
  19. log.info("info 级别日志");
  20. log.warn("warn 级别日志");
  21. log.error("error 级别日志");
  22. }
  23. }

2.4 设计 logback.xml 文件。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration scan="true" scanPeriod="60 seconds" debug="false">
  3. <!-- 日志存放路径 -->
  4. <property name="log.path" value="logs/platform-server" />
  5. <!-- 日志输出格式 -->
  6. <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
  7. <!-- 控制台输出 -->
  8. <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
  9. <encoder>
  10. <pattern>${log.pattern}</pattern>
  11. </encoder>
  12. </appender>
  13. <!-- 系统日志输出 -->
  14. <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
  15. <file>${log.path}/info.log</file>
  16. <!-- 循环政策:基于时间创建日志文件 -->
  17. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  18. <!-- 日志文件名格式 -->
  19. <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
  20. <!-- 日志最大的历史 60天 -->
  21. <maxHistory>60</maxHistory>
  22. </rollingPolicy>
  23. <encoder>
  24. <pattern>${log.pattern}</pattern>
  25. </encoder>
  26. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  27. <!-- 过滤的级别 -->
  28. <level>INFO</level>
  29. <!-- 匹配时的操作:接收(记录) -->
  30. <onMatch>ACCEPT</onMatch>
  31. <!-- 不匹配时的操作:拒绝(不记录) -->
  32. <onMismatch>DENY</onMismatch>
  33. </filter>
  34. </appender>
  35. <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
  36. <file>${log.path}/error.log</file>
  37. <!-- 循环政策:基于时间创建日志文件 -->
  38. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  39. <!-- 日志文件名格式 -->
  40. <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
  41. <!-- 日志最大的历史 60天 -->
  42. <maxHistory>60</maxHistory>
  43. </rollingPolicy>
  44. <encoder>
  45. <pattern>${log.pattern}</pattern>
  46. </encoder>
  47. <filter class="ch.qos.logback.classic.filter.LevelFilter">
  48. <!-- 过滤的级别 -->
  49. <level>ERROR</level>
  50. <!-- 匹配时的操作:接收(记录) -->
  51. <onMatch>ACCEPT</onMatch>
  52. <!-- 不匹配时的操作:拒绝(不记录) -->
  53. <onMismatch>DENY</onMismatch>
  54. </filter>
  55. </appender>
  56. <!-- 系统模块日志级别控制 -->
  57. <logger name="com.xuwei.platformserver" level="info" />
  58. <!-- Spring日志级别控制 -->
  59. <logger name="org.springframework" level="warn" />
  60. <root level="info">
  61. <appender-ref ref="console" />
  62. </root>
  63. <!--系统操作日志-->
  64. <root level="info">
  65. <appender-ref ref="file_info" />
  66. <appender-ref ref="file_error" />
  67. </root>
  68. </configuration>