Jeffrey · Chiang

日志管理

spring boot 中的日志配置、使用及管理

为什么用

日志分操作日志系统日志

  • 操作日志:用户在操作软件时记录的操作步骤,使用用户自查,针对用户
  • 系统日志:记录系统中软硬件和系统问题,同时还可以监视系统中发生的事件.可用来检查错误发生的原因,寻找受到攻击时由攻击者留下的痕迹.系统日志包括系统日志、应用程序日志和安全日志.针对软件开发人员(测试维护人员)

日志作用:

实时反映系统的运行状态

全球后期运维和开发人员迅速定位线上问题,回忆止损速度,减少系统故障带来的损失

无缝与监控系统结合,进行日志采集,拿到系统运行的相关性能指标,有利于分析系统的性能瓶颈,提前规避风险

全球统计与业务相 的指标数据,进行相关业务分析和功能优化

日志级别

  • ALL:最低等级,用于打开所有日志记录
  • TRACE:很低级别,一般不用
  • DEBUG:小粒度的信息事件,主要用于开发过程中的运行信息.
  • INFO:大粒度上突出强调程序的运行过程.打印有用的信息,可用于生产里的输入输出,避免滥用.
  • WARN:突出潜在的问题,但不是错误,仅给程序提醒.
  • ERROR:表示发生了错误,但不影响系统的继续运行.打印错误和异常信息,但又不想有输出太多的日志内容,可使用这个级别.
  • FATAL:指出每个将会导致应用程序退出的严重错误事件,级别较高的重大错误,这种级别可直接停止程序.
  • OFF:最高等级,用于关闭所有日志记录.

何时何地用

哪些地方需要打印日志

  1. 调用第三方接口时打印日志,如具体的 Request / Response
  2. 状态变化
  3. 重要方法的输入输出
  4. 业务异常
  5. 非预期执行
  6. 很少出现的else
  7. 程序运行时间
  8. 大批量的数据的执行速度

日志打印内容

打印内容,要从实际出发,包含必要内容,首要目标是便于定位问题:

  1. 用户
  2. 模块
  3. 参数
  4. 动作

日志级别

ERROR

影响到程序正常运行、请求正常运行的异常情况:

  1. 打开配置文件失败
  2. 第三方对接异常(包括第三方返回错误码)
  3. 所有影响功能使用的异常(不要在抛异常的时候打印日志,要在捕获异常的位置打印日志)

WARN

不应该出现但不影响程序、请求正常运行的异常情况:

  1. 有容错机制的错误情况
  2. 找不到配置但系统能自动创建的情况
  3. 即将接近临界值的情况(如,缓存池占用达到警告线,业务异常的记录等)

INFO

系统运行和第三方接口调用信息

  1. Service方法中对系统/业务状态的变更
  2. 主要逻辑中的分步骤
  3. 客户端请求参数REST/WS
  4. 调用第三方时的参数和结果

DEBUG

  1. 所有想知道的相关信息
  2. 生产环境需要关闭该级别
  3. 生产环境如要开启,可配置开关,不能一直开启

Java框架体系

java中日志框架分日志规范和日志实现

  • 日志规范: 定义一组日志的接口规范,并不提供底层具体实现逻辑,如 Apache Commons Logging 和 Slf4j.
  • 日志实现:日志的具体实现,包括级别控制、打印格式、输出形式(数据库、文件、控制台等).如 Log4j、Log4j2、Logback及 JavaUtil Logging.

使用时,一个规范搭配一个实现层. 如 Slf4j + Log4j 或 Slf4j + Logback

导入

spring boot 日志框架默认使用slf4j+logback, 默认随web依赖自动添加到项目中

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-btto-starter-web</artifactId>
</dependency>

使用

在需要的位置通过下面方式打印日志

private static final Logger log = LoggerFactory.getLogger(UserController.class);

log.info("测试信息级别日志输出");

统一配置

application.yml

日志级别

logging:
 level:
  root: warn # root表示整个项目
  org:
   springframework:
    web: debug # web 层
   hibernate: error # 持久层
  com:
   test:
    util: debug # 具体包

输出到文件

logging:
 file:
  # name: logs/xxx.log
  name: xxx.log # 输出到根目录下的指定文件中

精细化设置

logging:
 logback:
  rollingpolicy:
   file-name-pattern:xxx.log.gz # 日志文件达到指定大小后自动归档的文件名
   clean- history-on-start:true # 是否在应用启动时归档管理
   max-file-size:20MB # 日志文件到达指定大小后,会自动压缩
   total-size-cap:20MB # 日志文件被删除前,可以容纳的最大大小
   max-history:60 # 日志文件保存的天数

上述配置在Logback配置文件中配置更方便

Logback配置

要实现更加细粒度的日志配置,需要使用日志原生配置,如classpath:logback/log4j.xml等

导入

根据不同的日志系统,按指定规则组织配置文件名,并放于resources目录下,可自动被spring boot加载:

  • Logback: logback-spring.xml/logback-spring.groovy/logback.xml/logback.groovy
  • Log4j: log4j-spring.properties/log4j-spring.xml/log4j.properties/log4j.xml
  • Log4j2: log4j2-spring.xml/log4j2.xml
  • JDK(Java Util Logging): logging.properties

可能在application.yml中通过如下方式自定义日志配置文件名

logging:
 config: classpath:logging-config.xml

配置文件组成

  • root: 必选节点,用来指定最基础的日志输出,仅level一个属性,取值七选一:TRACE,DEBUG,INFO,WARN,ERROR,ALL,OFF.
  • contextName: 设置上下文件名称,默认default,可通过%contextName打印上下文件名称,一般不使用
  • property: 定义变量,有name,value两个属性,定义变量后可能用${}使用.
  • appender: 格式化日志输出的节点,属性name标识appender名字以供引用;class指定输出策略,通常分控制台输出和文件输出.
<?xml version="1.0" encoding="UTF-8" ?>
<!-- configuration 有5个子节点 -->
<configuration debug="false">
  <!-- root节点:必选,只有一个level属性,指定最基础的日志输出级别:TRACE, DEBUG, INFO, WARN, ERROR, ALL, OFF-->
  <root level="debug">
    <appender-ref ref="console"/>
    <appender-ref ref="timeFileOutput"/>
    <!-- other appender-ref 's' -->
  </root>
  <!-- 日志文件存储路径-->
  <property name="LOG_HOME" value="./logs/" />
  <!-- 控制台 appender -->
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
     <!-- 格式化输出:%d日期,%thread线程名,%-5level级别从左显示5个字符宽度(5表示从右显示了个字符宽度),%msg消息,%n换行符
 -->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      <!-- 编码 -->
      <chartset>UTF-8</chartset>
    </encoder>
  </appender>
  <!-- 文件输出,按时间滚动 -->
  <appender name="timeFileOutput" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 日志名,指定最新的文件名,其他文件名使用FileName -->
   <File>${LOG_HOME}/today.log</File>
    <!-- 滚动模式-->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBaseRollingPolicy">
      <!-- 日志文件输出的文件名,gz表示开始文件压缩-->
      <FileNamePatter>${LOG_HOME}/info.%d{yyyy-MM-dd}.%i.log.gz</FileNamePatter>
      <!-- 保留天数 -->
      <MaxHistory>60</MaxHistory>
      <!-- 同一天的大小分割 -->
      <timeBaseFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
       <maxFileSize>20MB</maxFileSize>
      </timeBaseFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <!-- 输出格式 -->

    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
     <!-- 格式化输出:%d日期,%thread线程名,%-5level级别从左显示5个字符宽度(5表示从右显示了个字符宽度),%msg消息,%n换行符
 -->
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      <!-- 编码 -->
      <chartset>UTF-8</chartset>
    </encoder>
  </appender>
</configuration>