(日志框架之Logback的使用与详细配置)

Logback

概述

Logback是一个Java日志框架,是log4j项目的继承者,也是log4j创始人设计的另一个开源日志组件,性能比log4j要好。它旨在解决log4j存在的一些问题,并提供了更高效和更灵活的日志框架。

Logback特点:

高性能:采用异步日志机制,可以将日志操作和业务逻辑分离,从而大幅度提升系统的性能。

灵活的配置:支持多种不同的配置方式,包括基于XML、Groovy、JSON等格式的配置文件,同时还支持通过代码进行配置。

多种日志级别:支持6种不同的日志级别,包括TRACE、DEBUG、INFO、WARN、ERROR和FATAL,用户可以根据需要选择合适的日志级别。

多种输出方式:支持多种不同的输出方式,包括控制台输出、文件输出、邮件发送等。用户可以根据需要选择合适的输出方式。

插件丰富:提供许多有用的插件,例如logstash-logback-encoder,可以将日志输出到ELK(Elasticsearch、Logstash、Kibana)平台上进行分析和可视化。

易于集成:Logback与Spring、Hibernate、JUnit等框架都有很好的集成,可以方便地进行应用程序的日志输出管理。

Logback三个主要模块:

1.logback-core

它是 Logback 的核心模块,提供了基本的日志功能。它支持多种输出格式和输出目标,包括控制台输出、文件输出和 Socket 输出。logback-core 可以与其他日志框架集成,例如 log4j 和 JDK Logging。

2.logback-classic

它是 Logback 的经典模块,是 log4j 的改进版。它提供了更强大的日志功能,并且向下兼容 log4j。它还支持 SLF4J,可以在不修改代码的情况下将应用程序从一个日志框架切换到另一个日志框架。

3.logback-access

它是 Logback 的访问模块,提供了基于 HTTP 请求的访问日志记录功能。使用 logback-access,可以记录每个请求的详细信息,包括请求方法、URL、响应状态码等。

配置文件结构

配置文件结构层次如下:

configuration : 配置文件的根元素,它包含了多个子元素:appender、logger 和 root

	appender : 定义了输出端,可以是控制台、文件、网络等,每一个appender都需要有一个唯一的名称和一个类定义
	
	logger : 定义了日志记录器,用于记录指定类的日志信息。logger元素需要指定一个名称和一个级别,以及一个可选的appender-ref子元素,用于将日志记录器连接到一个appender
	
	root : 定义了根日志记录器,它会接收所有未被其他logger接收的日志事件

Logback 的配置文件通常是 XML 格式,文件名为 logback.xml。它的结构如下:

<!--
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!--
     定义变量值的标签,property标签有两个属性,name和value;过property定义的值会被插入到logger上下文中。定义变量后,可以使${name}来使用变量
     -->
    <property name="AppName" value="demo"/>
    <!--
    每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用contextName标签设置成其他名字,用于区分不同应用程序的记录
    -->
    <contextName>${AppName}</contextName>
    <!--负责写日志的组件-->
    <appender>
        <filter></filter>
    </appender>
    <!--用来设置某一个包或者具体的某一个类的日志打印级别以及指定appender。-->
    <logger>
        <appender-ref ref=""/>
    </logger>
    <!---根logger,也是一种logger,且只有一个level属性-->
    <root>
    </root>
</configuration>

日志级别

ALL < TRACE < DEBUG < INFO < WARN < ERROR <FATAL <OFF
ALL:最低等级的,用于打开所有日志记录

TRACE:是最详细的日志信息,通常用于诊断问题和追踪代码执行流程。在生产环境中,应该关闭TRACE级别的日志输出,以避免影响系统性能

DEBUG:是调试信息,用于调试应用程序。在生产环境中,建议将DEBUG级别的日志输出关闭

INFO:是普通的信息记录,通常用于向用户展示可读的操作结果或执行状态。例如,当用户成功登录时,可以记录一条 INFO 级别的日志

WARN:表示警告信息,通常用于记录一些不严重但需要注意的问题。例如,当系统资源紧张时,可以记录一条WARN级别的日志

ERROR:表示错误信息,通常用于记录系统运行时发生的错误。例如,当数据库连接失败时,可以记录一条ERROR级别的日志

FATAL:表示致命错误,通常用于记录系统崩溃或无法恢复的错误。例如,当出现内存泄漏或硬盘损坏时,可以记录一条FATAL级别的日志

OFF:最高等级的,用于关闭所有日志记录。

Logback基本使用

与Maven项目集成

1.添加依赖

在Maven项目的pom.xml 文件中添加Logback的依赖,以便能够在代码中使用它

       <!--slf4j日志门面-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <!--logback日志实现-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

2.配置 Logback

创建一个 Logback 的配置文件(通常是 logback.xml),并为其定义 appender、logger 和 root 等元素。也可以不用配置。

3.使用 Logback记录日志

public class Logback {

    public static final Logger LOGGER = LoggerFactory.getLogger(Logback.class);

    @Test
    public void test() {
            LOGGER.error("error");
            LOGGER.warn("wring");
            LOGGER.info("info");
            LOGGER.debug("debug");
            LOGGER.trace("trace");
    }
}
18:05:38.202 [main] ERROR cn.ybzy.Logback - error
18:05:38.206 [main] WARN cn.ybzy.Logback - wring
18:05:38.207 [main] INFO cn.ybzy.Logback - info
18:05:38.207 [main] DEBUG cn.ybzy.Logback - debug

与Spring Boot集成

springboot集成了logback日志系统,默认读取名叫logback-spring.xml的配置文件,如果想自定义配置文件的名称,需要在spring boot配置文件中配置指定

logging:
	config: classpath:logback.xml

用法

public class MyTest {
    private static final Logger logger = LoggerFactory.getLogger(MyTest.class);

    public static void main(String[] args) {
        logger.info("info.....");
        logger.warn("warn" + ".....");
        logger.error("error,msg={}", "error....");
    }
}

与lombok集成

logback和lombok集成,使用@Slf4j注解标注类,直接使用log对象,需添加lombok依赖

    <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
@Slf4j
public class MyTest {

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

Logback配置

logback组件之间的关系

1. Logger:日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。

2. Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、数据库等等。

3. Layout:负责把事件转换成字符串,格式化的日志信息的输出。在logback中Layout对象被封装在encoder中。

Logger配置

logger就是在程序需要使用的Logger对象

    <!--
        name:指定受此logger约束的某一个包或者具体的某一个类。或者用于自定义日志名称
        level:设置打印级别(TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF)
        addtivity:描述是否向上级logger传递打印信息。默认是true。
    -->
    <logger name="com.chongba.schedule.service.VisiableThreadPool" additivity="false">
        <!--appender-ref则是用来指定具体appender-->
        <appender-ref ref="file.thread"/>
    </logger>

自定义日志名称的使用

    <!--自定义日志名称-->
    <logger name="web" additivity="false">
        <appender-ref ref="console"/>
    </logger>
private static final Logger threadLogger = LoggerFactory.getLogger("web");

Appender配置

ConsoleAppender配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!--属性配置管理,供引用使用-->

    <!--定义日志输出内容的格式-->
    <!--日志输出格式:
       %-5level
       %d{yyyy-MM-dd HH:mm:ss.SSS}日期
       %c类的全限定名称
       %M为method
       %L为行号
       %thread线程名称
       %m或者%msg为信息
       %n换行
     -->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>

    <!--控制台日志输出的appender-->
    
    <!--name属性指定appener的名称,class指定appender的类型-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--控制输出流对象 默认 System.out(黑色) 改为 System.err(红色)-->
        <target>System.err</target>
        
        <!--日志消息格式配置-->
        
        <!-- 对记录事件进行格式化。1.把日志信息转换成字节数组 2.把字节数组写入到输出流 -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--引用属性配置管理中定义的某个属性-->
            <pattern>${pattern}</pattern>
            <charset>utf-8</charset>
        </encoder>
        
    </appender>

    <!--root logger 配置-->
    <root level="ALL">
        <appender-ref ref="console"/>
    </root>

</configuration>
[ERROR] 2021-03-21 18:16:14.273 cn.ybzy.Logback test 13 [main] error
[WARN ] 2021-03-21 18:16:14.277 cn.ybzy.Logback test 14 [main] wring
[INFO ] 2021-03-21 18:16:14.278 cn.ybzy.Logback test 15 [main] info
[DEBUG] 2021-03-21 18:16:14.278 cn.ybzy.Logback test 16 [main] debug
[TRACE] 2021-03-21 18:16:14.279 cn.ybzy.Logback test 17 [main] trace

FileAppender配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!--属性配置管理,供引用使用-->

    <!--定义日志输出内容的格式-->
    <!--日志输出格式:
       %-5level
       %d{yyyy-MM-dd HH:mm:ss.SSS}日期
       %c类的全限定名称
       %M为method
       %L为行号
       %thread线程名称
       %m或者%msg为信息
       %n换行
     -->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>

    <!--定义日志文件保存路径属性-->
    <property name="log_dir" value="d:/logs"></property>

    <!--日志文件输出的 appender-->
    <appender name="file" class="ch.qos.logback.core.FileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/logback.log</file>
        <!--日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
        </encoder>
    </appender>

    <!--root logger 配置-->
    <root level="ALL">
        <appender-ref ref="file"/>
    </root>
    
</configuration>

HtmlAppender配置

   <!--html格式日志文件输出appender-->
    <appender name="htmlFile" class="ch.qos.logback.core.FileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/logback.html</file>
        <!--html 消息格式配置-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%-5level%d{yyyy-MM-dd HH:mm:ss.SSS}%c%M%L%thread%m</pattern>
            </layout>
        </encoder>
    </appender>

在这里插入图片描述

RollingFileAppender配置

rollingPolicy子标签:滚动策略。常用的滚动策略如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!--属性配置管理,供引用使用-->
    <!--定义日志输出内容的格式-->
    <property name="pattern" value="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n"></property>

    <!--定义日志文件保存路径属性-->
    <property name="log_dir" value="d:/logs"></property>
    
    <!--日志拆分和归档压缩的appender对象-->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志文件保存路径-->
        <file>${log_dir}/roll_logback.log</file>
        <!--日志消息格式配置-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>${pattern}</pattern>
	        <charset>utf-8</charset>
        </encoder>
        <!--指定拆分规则-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--按照时间和压缩格式声明拆分的文件名-->
            <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}.log%i.zip</fileNamePattern>
            <!-- <fileNamePattern>${log_dir}/rolling.%d{yyyy-MM-dd}.log%i</fileNamePattern>-->
            <!--日志文件保留天数-->
        	<MaxHistory>30</MaxHistory>
            <!--按照文件大小拆分,日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始 -->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>


    <!--root logger 配置-->
    <root level="ALL">
        <appender-ref ref="rollFile"/>
    </root>

</configuration>

在这里插入图片描述

Filter配置

可以为appender 添加一个或多个过滤器,可以用任意条件对日志进行过滤。 appender 有多个过滤器时,按照配置顺序执行

filter的类型

LevelFilter:

根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据 onMath (用于配置符合过滤条件的操作) 和 onMismatch (用于配置不符合过滤条件的操作)接收或拒绝日志

ThresholdFilter:

临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回 NEUTRAL ;当日志级别低于临界值时,日志会被拒绝。

<!--日志拆分和归档压缩的appender对象-->
    <appender name="rollFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <!--日志级别过滤器-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--日志过滤规则-->
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        
    </appender>

异步日志配置

	<!--异步日志-->
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <!--指定某个具体的appender-->
        <appender-ref ref="rollFile"/>
    </appender>

    <!--root logger 配置-->
    <root level="ALL">
        <appender-ref ref="async"/>
    </root>

示例配置

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <property name="LOG_CONTEXT_NAME" value="web-app"/>
    <!--定义日志文件的存储地址 勿在LogBack的配置中使用相对路径-->
    <property name="LOG_HOME" value="logs/${LOG_CONTEXT_NAME}"/>
    <!-- 定义日志上下文的名称 -->
    <contextName>${LOG_CONTEXT_NAME}</contextName>

    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
    </appender>

    <!--info日志统一输出-->
    <appender name="file.info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <Prudent>true</Prudent>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名,按小时生成-->
            <FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/info/info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>
            <!--日志文件输出的文件名,按天生成-->
            <!--<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/error/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern>-->
            <!--日志文件保留天数-->
            <MaxHistory>30</MaxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 除按日志记录之外,还配置了日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始 -->
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %method 方法名  %L 行数 %msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{56}.%method:%L - %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!--错误日志统一输出-->
    <appender name="file.error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--省略,参考file.info appender-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--warn日志统一输出-->
    <appender name="file.warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--省略,参考file.info appender-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--  日志输出级别 -->
    <root level="debug">
        <appender-ref ref="console"/>
        <appender-ref ref="file.error"/>
        <appender-ref ref="file.info"/>
        <appender-ref ref="file.warn"/>
    </root>

    <!-- 某类/包下的所有日志使用file.info appender输出-->
    <logger name="cn.ybzy.demo.controller.TestController" additivity="false">
        <appender-ref ref="file.info"/>
    </logger>

	<logger name="org.hibernate.SQL">
        <level value="DEBUG"/>
    </logger>

</configuration>