自学内容网 自学内容网

Spring Boot 日志

1. 日志概述

为什么要学习⽇志

⽇志对我们来说并不陌⽣,从JavaSE部分,我们就在使⽤ System.out.print 来打印⽇志了.

通过打 印⽇志来发现和定位问题,或者根据⽇志来分析程序的运⾏过程.在Spring的学习中,也经常根据控制台 的⽇志来分析和定位问题.

随着项⽬的复杂度提升,我们对⽇志的打印也有了更⾼的需求,⽽不仅仅是定位排查问题.

⽐如需要记录⼀些⽤⼾的操作记录(⼀些审计公司会要求),也可能需要使⽤⽇志来记录⽤⼾的⼀些喜好, 把⽇志持久化,后续进⾏数据分析等.但是 System.out.print 不能很好的满⾜我们的需求,我们就 需要使⽤⼀些专⻔⽇志框架(专业的事情交给专业的⼈去做).

⽇志的⽤途

通过前⾯的学习,我们知道⽇志主要是为了发现问题,分析问题,定位问题的,但除此之外,⽇志还有很多⽤途

  1. 系统监控 监控现在⼏乎是⼀个成熟系统的标配,我们可以通过⽇志记录这个系统的运⾏状态,每⼀个⽅法的响应 时间,响应状态等,对数据进⾏分析,设置不同的规则,超过阈值时进⾏报警.⽐如统计⽇志中关键字的数 量,并在关键字数量达到⼀定条件时报警,这也是⽇志的常⻅需求之⼀
  2. 数据采集 数据采集是⼀个⽐较⼤的范围,采集的数据可以作⽤在很多⽅⾯,⽐如数据统计,推荐排序等.
    • 数据统计:统计⻚⾯的浏览量(PV),访客量(UV),点击量等,根据这些数据进⾏数据分析,优化公司运营 策略
    • 推荐排序:⽬前推荐排序应⽤在各个领域,我们经常接触的各⾏各业很多也都涉及推荐排序,⽐如购 物,⼴告,新闻等领域.数据采集是推荐排序⼯作中必须做的⼀环,系统通过⽇志记录⽤⼾的浏览历 史,停留时⻓等,算法⼈员通过分析这些数据,训练模型,给⽤⼾做推荐.

下图中的数据源,其中⼀部分就来⾃于⽇志记录的数据.

  1. 日志审计
    随着互联⽹的发展,众多企业的关键业务越来越多的运⾏于⽹络之上.⽹络安全越来越受到⼤家的关 注,系统安全也成为了项⽬中的⼀个重要环节,安全审计也是系统中⾮常重要的部分.国家的政策法规、 ⾏业标准等都明确对⽇志审计提出了要求.通过系统⽇志分析,可以判断⼀些⾮法攻击,⾮法调⽤,以 及系统处理过程中的安全隐患.
  • ⽐如,⼤家平时都在做运营系统,其中运营⼈员在通过界⾯处理⼀些数据的时候,如果没有清楚的⽇志 操作记录,⼀条数据被删除或者修改,你是⽆法找到是谁操作的,但是如果你做了相应的记录,该数 据被谁删除或者修改就会⼀⽬了然.
  • 还有⼀些内部的违规和信息泄漏(⽐如客⼾信息被卖掉)现象出现后,如果未记录留存⽇志,为事后调查 提供依据,则事后很难追查(⼀些公司查看客⼾的信息都会被记录⽇志,如果频繁查询也会报警).

2. 日志使用

SpringBoot项⽬在启动的时候默认就有⽇志输出,如下图所⽰:

它打印的⽇志System.out.print 有什么不同呢

@RestController
public class LoggerController {
    @RequestMapping("/logger")
    public String logger(){
    System.out.println("打印⽇志");
    return "打印⽇志";
    }
}

观察⽇志输出

可以看到,我们通过 System.out.print 打印的⽇志,⽐ SpringBoot 打印的⽇志缺少了很多信息.

SpringBoot内置了⽇志框架 Slf4j ,我们可以直接在程序中调⽤ Slf4j 来输出⽇志

2.1 打印日志

打印⽇志的步骤:

  • 在程序中得到⽇志对象.
  • 使⽤⽇志对象输出要打印的内容.

2.1.1 在程序中得到⽇志对象

在程序中获取⽇志对象需要使⽤⽇志⼯⼚LoggerFactory,如下代码所⽰:

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

LoggerFactory.getLogger需要传递⼀个参数,标识这个⽇志的名称.这样可以更清晰的知道是哪个类 输出的⽇志.当有问题时,可以更⽅便直观的定位到问题类

注意:Logger对象是属于org.slf4j包下的,不要导⼊错包.


2.1.2 使⽤⽇志对象打印⽇志

⽇志对象的打印⽅法有很多种,我们可以先使⽤info()⽅法来输出⽇志,如下代码所⽰:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoggerController {
    private static Logger logger = LoggerFactory.getLogger(LoggerController.clas
    @RequestMapping("/logger")
    public String logger(){
        logger.info("--------------要输出⽇志的内容----------------");
        return "打印⽇志";
    }
}

打印⽇志效果展⽰:

2.2 日志框架介绍 (了解)


SLF4J不同于其他⽇志框架,它不是⼀个真正的⽇志实现,⽽是⼀个抽象层,对⽇志框架制定的⼀种规范, 标准,接⼝.所有SLF4J并不能独⽴使⽤,需要和具体的⽇志框架配合使⽤.

2.2.1 ⻔⾯模式(外观模式)

SLF4J是⻔⾯模式的典型应⽤(但不仅仅使⽤了⻔⾯模式).

⻔⾯模式定义

⻔⾯模式(FacadePattern)⼜称为外观模式,提供了⼀个统⼀的接⼝,⽤来访问⼦系统中的⼀群接⼝.

其主要特征是定义了⼀个⾼层接⼝,让⼦系统更容易使⽤.

原⽂:Provideaunifiedinterfacetoasetofinterfacesinasubsystem.Facadedefinesahigherlevel interfacethatmakesthesubsystemeasiertouse.

解释:要求⼀个⼦系统的外部与其内部的通信必须通过⼀个统⼀的对象进⾏.⻔⾯模式提供⼀个⾼层 次的接⼝,使得⼦系统更易于使⽤.

⻔⾯模式主要包含2种⻆⾊:

  1. 外观⻆⾊(Facade):也称⻔⾯⻆⾊,系统对外的统⼀接⼝.

  2. ⼦系统⻆⾊(SubSystem):可以同时有⼀个或多个SubSystem.每个SubSytem都不是⼀个单独的类, ⽽是⼀个类的集合.SubSystem并不知道Facade的存在,对于SubSystem⽽⾔,Facade只是另⼀个 客⼾端⽽已(即Facade对SubSystem透明)

⽐如去医院看病,可能要去挂号,⻔诊,化验,取药,让患者或患者家属觉得很复杂,如果有提供接待⼈ 员,只让接待⼈员来处理,就很⽅便.

⻔⾯模式的实现

场景:回家,我们会开各个屋的灯.离开家时,会关闭各个屋的灯

如果家⾥设置⼀个总开关,来控制整个屋的灯就会很⽅便.

我们使⽤⻔⾯模式的实现

public class FacadePatternDemo {
    public static void main(String[] args) {
        LightFacade lightFacade = new LightFacade();
        lightFacade.lightOn();
    }
}

/**
 * 灯的⻔⾯ 
 */
class LightFacade{
    private Light livingRoomLight = new LivingRoomLight();
    private Light hallLight = new HallLight();
    private Light diningLight = new DiningLight();
    
    public void lightOn(){
        livingRoomLight.on();
        hallLight.on();
        diningLight.on();
    }
    
    public void lightOff(){
        livingRoomLight.off();
        hallLight.off();
        diningLight.off();
    }
}

interface Light {
    void on();
    void off();
}

/**
 * 客厅灯 
 */
class LivingRoomLight implements Light{
    @Override
    public void on() {
    System.out.println("打开客厅灯");
    }
    @Override
    public void off() {
    System.out.println("关闭客厅灯");
    }
}
/**
 * ⾛廊灯 
 */
class HallLight implements Light{
    @Override
    public void on() {
    System.out.println("打开⾛廊灯");
    }
    @Override
    public void off() {
    System.out.println("关闭⾛廊灯");
    }
}

/**
 * 餐厅灯 
 */
class DiningLight implements Light{
    @Override
    public void on() {
    System.out.println("打开餐厅灯");
    }
    @Override
    public void off() {
    System.out.println("关闭餐厅灯");
    }
}

⻔⾯模式的优点

  • 减少了系统的相互依赖.实现了客⼾端与⼦系统的耦合关系,这使得⼦系统的变化不会影响到调⽤它 的客⼾端;
  • 提⾼了灵活性,简化了客⼾端对⼦系统的使⽤难度,客⼾端⽆需关⼼⼦系统的具体实现⽅式,⽽只需 要和⻔⾯对象交互即可.
  • 提⾼了安全性.可以灵活设定访问权限,不在⻔⾯对象中开通⽅法,就⽆法访问

2.2.2 SLF4J框架介绍

SLF4J就是其他⽇志框架的⻔⾯.SLF4J可以理解为是提供⽇志服务的统⼀API接⼝,并不涉及到具体的 ⽇志逻辑实现.

不引⼊⽇志⻔⾯

常⻅的⽇志框架有log4J,logback等.如果⼀个项⽬已经使⽤了log4j,⽽你依赖的另⼀个类库,假如是 ApacheActiveMQ,它依赖于另外⼀个⽇志框架logback,那么你就需要把logback也加载进去.


存在问题:

  1. 不同⽇志框架的API接⼝和配置⽂件不同,如果多个⽇志框架共存,那么不得不维护多套配置⽂件(这 个配置⽂件是指⽤⼾⾃定义的配置⽂件).
  2. 如果要更换⽇志框架,应⽤程序将不得不修改代码,并且修改过程中可能会存在⼀些代码冲突.
  3. 如果引⼊的第三⽅框架,使⽤了多套,那就不得不维护多套配置.

引⼊⽇志⻔⾯

引⼊⻔⾯⽇志框架之后,应⽤程序和⽇志框架(框架的具体实现)之间有了统⼀的API接⼝(⻔⾯⽇志框架 实现),此时应⽤程序只需要维护⼀套⽇志⽂件配置,且当底层实现框架改变时,也不需要更改应⽤程序代码.

SLF4J就是这个⽇志⻔⾯.

总的来说,SLF4J使你的代码独⽴于任意⼀个特定的⽇志API,这是⼀个对于开发API的开发者很好的思想.

2.3 日志格式的说明

打印的日志格式, 如下图:

从上图可以看到, ⽇志输出内容元素具体如下:

  1. 时间⽇期:精确到毫秒
  2. ⽇志级别:ERROR,WARN,INFO,DEBUG或TRACE
  3. 进程ID
  4. 线程名
  5. Logger名(通常使⽤源代码的类名)
  6. ⽇志内容

2.4 日志级别

⽇志级别代表着⽇志信息对应问题的严重性,为了更快的筛选符合⽬标的⽇志信息.

试想⼀下这样的场景,假设你是⼀家2万⼈公司的⽼板,如果每个员⼯的⽇常⼯作和琐碎的信息都要反馈给你,那你⼀定⽆暇顾及.于是就有了组织架构,⽽组织架构就会分级,有很多的级别设置,

如下图所⽰:

有了组织架构之后,就可以逐级别汇报消息了,例如:组员汇报给组⻓,组⻓汇报给研发⼀组,研发⼀组 汇报给Java研发,等等依次进⾏汇报.

⽇志级别⼤概是同样的道理,有了⽇志级别之后就可以过滤⾃⼰想看到的信息了,⽐如只关注error级别 的,就可以根据级别过滤出来error级别的⽇志信息,节约开发者的信息筛选时间.

2.4.1 日志级别的分类

⽇志的级别从⾼到低依次为:FATAL、ERROR、WARN、INFO、DEBUG、TRACE

  • FATAL:致命信息,表⽰需要⽴即被处理的系统级错误.
  • ERROR:错误信息,级别较⾼的错误⽇志信息,但仍然不影响系统的继续运⾏.
  • WARN:警告信息,不影响使⽤,但需要注意的问题
  • INFO:普通信息,⽤于记录应⽤程序正常运⾏时的⼀些信息,例如系统启动完成、请求处理完成等.
  • DEBUG:调试信息,需要调试时候的关键信息打印.
  • TRACE:追踪信息,⽐DEBUG更细粒度的信息事
  • 件(除⾮有特殊⽤意,否则请使⽤DEBUG级别替代)

⽇志级别通常和测试⼈员的Bug级别没有关系.

⽇志级别是开发⼈员设置的,⽤来给开发⼈员看的.⽇志级别的正确设置,也与开发⼈员的⼯作经验有 关.如果开发⼈员把error级别的⽇志设置成了info,就很有可能会影响开发⼈员对项⽬运⾏情况的判 断.出现error级别的⽇志信息较多时,可能也没有任何问题.测试的bug级别更多是依据现象和影响范围来判断

⽇志级别的顺序:


级别越⾼,收到的消息越少

2.4.2 ⽇志级别的使⽤

⽇志级别是开发⼈员⾃⼰设置的.开发⼈员根据⾃⼰的理解来判断该信息的重要程度

类似公司管理,通常由领导来判断什么样的事情需要汇报,什么样的事情不需要汇报.

针对这些级别,Logger对象分别提供了对应的⽅法,来输出⽇志.

/**
 * 打印不同级别的⽇志 
 * @return
 */
@RequestMapping("/printLog")
public String printLog() {
    logger.trace("================= trace ===============");
    logger.debug("================= debug ===============");
    logger.info("================= info ===============");
    logger.warn("================= warn ===============");
    logger.error("================= error ===============");
    return "打印不同级别的⽇志" ;
}

SpringBoot默认的⽇志框架是Logback,Logback没有 FATAL 级别,它被映射到 ERROR .

出现fatal⽇志,表⽰服务已经出现了某种程度的不可⽤,需要需要系统管理员紧急介⼊处理.通常情 况下,⼀个进程⽣命周期中应该最多只有⼀次FATAL记录.

观察打印的⽇志结果:

结果发现,只打印了info,warn和error级别的⽇志

这与⽇志级别的配置有关,⽇志的输出级别默认是info级别,所以只会打印⼤于等于此级别的⽇志,也就 是info,warn和error.

2.5 日志配置

上述是⽇志的使⽤,⽇志框架⽀持我们更灵活的输出⽇志,包括内容,格式等.

2.5.1 配置日志级别

⽇志级别配置只需要在配置⽂件中设置"logging.level"配置项即可,如下所⽰:

⼆者转换⽅式:Properties⽂件的点( . )对应yml⽂件中的换⾏

以下两个配置,根据项⽬使⽤其中之⼀.

Properties配置

logging.level.root: debug

yml配置

logging:
 level:
 root: debug

重新运⾏上述代码,观察结果:

2.5.2 日志持久化

以上的⽇志都是输出在控制台上的,然⽽在线上环境中,我们需要把⽇志保存下来,以便出现问题之后追 溯问题.把⽇志保存下来就叫持久化.

⽇志持久化有两种⽅式

  1. 配置⽇志⽂件名
  2. 配置⽇志的存储⽬录

配置⽇志⽂件的路径和⽂件名

Properties配置

logging.file.name: logger/springboot.log

yml配置

# 设置⽇志⽂件的⽂件名 
logging:
 file:
 name: logger/springboot.log

后⾯可以跟绝对路径或者相对路径

运⾏结果显⽰,⽇志内容保存在了对应的⽬录下

配置⽇志⽂件的保存路径

Properties配置

logging.file.path: D:/temp

yml配置

# 设置⽇志⽂件的⽬录 
logging:
 file:
 path: D:/temp

这种⽅式只能设置⽇志的路径,⽂件名为固定的spring.log

运⾏程序,该路径下多出⼀个⽇志⽂件:spring.log

注意:

logging.file.name 和logging.file.path 两个都配置的情况下,只⽣效其⼀,以 logging.file.name 为准.

2.5.3 配置⽇志⽂件分割

如果我们的⽇志都放在⼀个⽂件中,随着项⽬的运⾏,⽇志⽂件会越来越⼤,需要对⽇志⽂件进⾏分割.

当然,⽇志框架也帮我们考虑到了这⼀点,所以如果不进⾏配置,就⾛⾃动配置

默认⽇志⽂件超过10M就进⾏分割


配置⽇志⽂件分割:

Properties配置

logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB

yml配置

logging:
 logback:
 rollingpolicy:
 max-file-size: 1KB
 file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i
  1. ⽇志⽂件超过1KB就分割(设置1KB是为了更好展⽰.企业开发通常设置为200M,500M等,此处没 有明确标准)
  2. 分割后的⽇志⽂件名为:⽇志名.⽇期.索引

项⽬运⾏,多打印⼀些⽇志,⽇志分割结果:

2.5.4 配置日志格式

⽬前⽇志打印的格式是默认的

配置项说明:

  1. %clr(表达式){颜⾊}设置输⼊⽇志的颜⾊

    ⽀持颜⾊有以下⼏种:

    • blue
    • cyan
    • faint
    • green
    • magenta
    • red
    • yellow
  2. %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd’T’HH:mm:ss.SSSXXX}}⽇期和时间–精确到毫 秒

    %d{}⽇期

    ${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd’T’HH:mm:ss.SSSXXX} ⾮空表达式,获取 系统属性 LOG_DATEFORMAT_PATTERN ,若属性LOG_DATEFORMAT_PATTERN 不存在,则使 ⽤-yyyy-MM-dd HH:mm:ss.SSSXXX 格式,系统属性可以 System.getProperty(“LOG_DATEFORMAT_PATTERN”) 获取

  3. %5p 显⽰⽇志级别ERROR,MARN,INFO,DEBUG,TRACE.

  4. %t 线程名.%c 类的全限定名.%M method.%L 为⾏号.%thread 线程名称.%m 或者 %msg 显⽰输出消息.%n 换⾏符

  5. %5 若字符⻓度⼩于5,则右边⽤空格填充.%-5 若字符⻓度⼩于5,则左边⽤空格填充.%.15 若 字符⻓度超过15,截去多余字符.%15.15 若字符⻓度⼩于15,则右边⽤空格填充.若字符⻓度超 过15,截去多余字符

更多说明,参考:https://logback.qos.ch/manual/layouts.html#conversionWord

设置了颜⾊,却没有⽣效?

需要配置,让idea⽀持控制台颜⾊显⽰

  1. 打开启动配置,添加 VM options
  2. 添加VM options -Dspring.output.ansi.enabled=ALWAYS
  3. 重新启动程序,就发现控制台⽀持颜⾊了

Properties配置

logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

yml配置

logging:
 pattern:
 console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
 file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

项⽬运⾏,观察⽇志变化:

通常情况下,咱们就使⽤默认的⽇志格式打印即可.

3. 更简单的日志输出

每次都使⽤LoggerFactory.getLogger(xxx.class)很繁琐,且每个类都添加⼀遍,lombok给我们提供了 ⼀种更简单的⽅式.

  1. 添加lombok框架⽀持
  2. 使⽤ @slf4j 注解输出⽇志。

3.1 添加lombok依赖

<dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <optional>true</optional>
</dependency>

3.2 输出日志

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class LogController {
    public void log(){
    log.info("--------------要输出⽇志的内容----------------");
    }
}

lombok提供的 @Slf4j 会帮我们提供⼀个⽇志对象log,我们直接使⽤就可以.

4. 总结

  1. ⽇志是程序中的重要组成部分,使⽤⽇志可以快速的发现和定位问题,SpringBoot内容了⽇志框 架,默认情况下使⽤的是info⽇志级别将⽇志输出到控制台的,我们可以通过 lombok提供的 @Slf4j 注解和log 对象快速的打印⾃定义⽇志.
  2. ⽇志包含6个级别,⽇志级别越⾼,收到的⽇志信息也就越少,我们可以通过配置⽇志的保存名称 或 保存⽬录来将⽇志持久化.

原文地址:https://blog.csdn.net/qq_67549203/article/details/144993343

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!