Java日志框架的使用(slf4j、Logback)

2,013 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

引言

SpringBoot为Logback提供了默认的配置文件base.xml,base.xml文件里定义了默认的日记输出级别为INFO。

    ERROR(40, "ERROR"),
    WARN(30, "WARN"),
    INFO(20, "INFO"),
    DEBUG(10, "DEBUG"),
    TRACE(0, "TRACE");

在这里插入图片描述

I Logback的使用

在这里插入图片描述

Slf4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。 Slf4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。

SLF4J更像是将这些日志框架重新封装,提供了共通的接口供使用者调用,无论底层框架如何改变,只需要替换依赖即可,不需要再逐一更改排查项目何处调用了原日志系统的方法。

Logback是SpringBoot内置的日志处理框架,你会发现spring-boot-starter其中包含了spring-boot-starter-logging,该依赖内容就是 Spring Boot 默认的日志框架 logback。官方文档:logback.qos.ch/manual/

1.1 门面模式

slf4j是门面模式的典型应用,门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。 在这里插入图片描述

slf4j的用法就是常年不变的一句"Logger logger = LoggerFactory.getLogger(Object.class);",可见这里就是通过LoggerFactory去拿slf4j提供的一个Logger接口的具体实现而已。

我们可以使用mvn 引入lombok,使用注解来更简便的使用slf4j。

  1. POJO的getter/setter/toString;异常处理;I/O流的关闭操作等等,这些样板代码既没有技术含量,又影响着代码的美观,Lombok应运而生。

  2. IDEA 2020最后一个版本发布了,已经内置了Lombok插件,SpringBoot 2.1.x之后的版本也在Starter中内置了Lombok依赖

1.2 slf4j的应用举例

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

//1、新版spring-boot-starter-test不再集成junit,而是junit-jupiter,不再使用@RunWith()注解。
//@RunWIth(SpringRunner.class)
@SpringBootTest
public class LoggerTest {
private final Logger logger = LoggerFactory.getLogger(LoggerTest.class);

@Test
    public void test1() {

    logger.debug("debug...");

    logger.info("info..."); //系统的默认日记级别
    logger.error("error...");



}




}

1.3 application.properties

配置文件所在目录不同优先级也不同,如下图1~4优先级从高到低

在这里插入图片描述

  1. 当前项目根目录的config下
  2. 当前项目根目录下
  3. resource目录的config目录下
  4. resource目录下
  5. 在使用 spring.config.location 指定外部配置文件时,需要此份配置文件需全量满足当前工程运行时所需,因为它不会去与 resources 目录下的配置文件去做 merge 操作。

application.properties和application.yml作用是一致的,spring boot项目中同时存在application.properties和application.yml文件时,两个文件都有效,但是application.properties的优先级会比application.yml高。

要么用application.properties 要么用 application.yml,不要都用使自己混乱

yaml不同于 properties 文件的无序,yaml 配置有序。

可设置spring.config.name环境变量指定配置文件名称。

1.4 启用“调试”模式

方式一: 在application.properties中配置debug=true,该属性置为true的时候,核心Logger(包含嵌入式容器、hibernate、spring)会输出更多内容,但是你自己应用的日志并不会输出为DEBUG级别。

方式二:在编译设置中开启 在这里插入图片描述

默认情况下,Spring Boot将日志输出到控制台,不会写到日志文件。我们可以在application.properties或application.yml配置,但是只能配置简单的场景,保存路径、日志格式等,复杂的场景(区分 info 和 error 的日志、每天产生一个日志文件等)满足不了,只能自定义配置。

1.5 自定义logback的配置文件

按如下规则组织配置文件名,就能被正确加载: 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

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <property name = "ENCODER_PATTERN" value = "%d{MM-dd  HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n"/>
    <!-- 控制台日志:输出全部日志到控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 控制输出流对象,默认System.out 改为System.err-->
        <target>System.err</target>
        <!-- 日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${ENCODER_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- root Logger 配置-->
    <root level="info">
        <appender-ref ref="console"/>
    </root>
</configuration>

fileInfoLog和fileErrorLog

    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>/Users/mac/Desktop/log/tomcat/test/info.%d.log</fileNamePattern>
        </rollingPolicy>
    </appender>


    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>
                %msg%n
            </pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>/Users/mac/Desktop/log/tomcat/test/error.%d.log</fileNamePattern>
        </rollingPolicy>
    </appender>


    <!-- root Logger 配置-->
    <root level="info">
        <appender-ref ref="fileInfoLog"/>
        <appender-ref ref="fileErrorLog"/>

    </root>

查阅正在改变的日志文件: tail -f error.2022-04-09.log

II SpringBoot内置插件的使用(jackson和lombok)

idea2021.2.2 已经捆绑安装jackson和lombok插件

在这里插入图片描述

2.1 lombok

Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。

projectlombok.org/features/al…

  1. 添加maven,如果不指定版本号,会提示找不到最新版本1.18.22,我们可以指定版本之后,再重新加载。
<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

如果不想每次都写private final Logger logger = LoggerFactory.getLogger(当前类名.class); 可以用注解@Slf4j

@Slf4j
    public void test1() {

    log.debug("debug...");

    log.info("info..."); //系统的默认日记级别
    log.error("error...");



}

注解@Data作用在类上,会为类的所有属性自动生成setter/getter、equals、hasCode、toString方法。

@Builder在创建对象时具有链式赋值的特点。

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Student {

2.2 jackson

SpringBoot内置了jackson来实现JSON的序列化和反序列化。

jackson使用ObjectMapper类将POJO对象序列化为JSON字符串,也能将JSON字符串反序列化为POJO对象。 在这里插入图片描述

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

        String str = mapper.writeValueAsString(stu);
        Student stu = mapper.readValue(str,Student.class);

jackson包含很多注解,用于个性化序列化和反序列化操作。

  1. @JsonProperty(alias),作用在属性上,为属性指定别名。
  2. @JsonIgnore,作用在属性上,用此注解来忽略属性。
  3. @JsonIgnoreProperties({propertyName1,propertyName2}),作用在类上,表示忽略一组属性。
  4. @JsonFormat(pattern=""),用于格式化日期。

比如@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss"),将时间格式化为“年-月-日 时:分:秒”。

    @JsonIgnore
    private String gender;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonProperty("bd")
    private Date birthday;

see also

shell 脚本完成对日志文件的提取

idea,快速搜索的快捷键:command+o