Logback

发布于 2022-11-12  2.28k 次阅读


1. Logbac简介

Logback是由log4j创始人设计的一个开源日志组件,在log4j的原基础上做了优化,功能更加强大

logback具有优势:

  • 内核重写、测试充分、初始化内存加载更小,这一切让logback性能和log4j相比有诸多倍的提升
  • logback非常自然地直接实现了slf4j,这个严格来说算不上优点,只是这样,再理解slf4j的前提下会很容易理解logback,也同时很容易用其他日志框架替换logbac
  • logback有比较齐全的200多页的文档
  • logback当配置文件修改了,支持自动重新加载配置文件,扫描过程快且安全,它并不需要另外创建一个扫描线程
  • 支持自动去除旧的日志文件,可以控制已经产生日志文件的最大数量

1)logback当前分为三个模块:

  1. logback-core其他两个模块的基础模块
  2. logback-classic:是log4j的一个改良版本,此外logback-classic完整实现了Slf4j API,可以很方便地更换成其他日志系统如log4j或JDK14 Logging
  3. logback-access:访问模块与Servlet容器集成提供通过HTTP来访问日志的功能

2)logback的组件:和log4j一样(名称和功能都没有变,当内部实现做了优化)

  • Logger:日志的记录器,主要用于存放日志对象,也可以定义日志类型和级别等
  • Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、数据库等等
  • Layout:负责把事件转换成字符串,格式化的日志信息的输出

注:在Logback中Layout对象被封装在encoder中,也就是说之后的配置Layout需要先配置encoder对象

3)logback日志级别:五种日志级别

  • trace:跟踪信息,等级也非常低,一般情况下不使用
  • debug(默认):指出细粒度信息事件对调试应用程序是非常有帮助的,主要配合开发,在开发过程中打印一些重要信息
  • info:消息的粗粒度级别运行信息
  • warn:警告信息,程序在运行过程中会出现的有可能发生的隐形的错误
  • error:系统的错误信息,如果不想要输出过多的日志设置该级别即可

4)Logback提供三种配置文件:

  1. logback.groovy:
  2. logback-test.xml:
  3. logback.xml

注:如果都不存在则采用默认的配置,一般使用最多的配置文件是logback.xml

2. Logback入门案例

导入maven依赖:

<!--slf4j日志门面-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

<!--logback日志实现 logback-classic涵盖了logback-core依赖,不需要重复导入-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

测试代码:

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

    logger.trace("trace日志");
    logger.debug("debug日志");
    logger.info("info日志");
    logger.warn("warn日志");
    logger.error("error日志");
}

输出:

09:35:33.081 [main] DEBUG com.kxjslf4j.slf4jCase - debug日志
09:35:33.083 [main] INFO com.kxjslf4j.slf4jCase - info日志
09:35:33.083 [main] WARN com.kxjslf4j.slf4jCase - warn日志
09:35:33.083 [main] ERROR com.kxjslf4j.slf4jCase - error日志

3. Logback配置文件说明

1)property通用属性配置

    所谓的配置文件通用属性是为了让接下来的配置更加方便引用,通过${}的形式,方便的获得value值,通过value的值可以做其他配置而使用

<property name="pattern" value="通用配置属性"></property>
#可以通过${pattern}进行获取

2)appender属性配置

常用的appender:

  • ConsolAppender:日志控制台输出
  • FileAppender:日志文件输出
  • RollingFileAppender:按文件大小进行切分
  • …………

配置项:

① target:表示对于日志输出目标配置

  • 默认:System.out 表示以黑色字体输出日志
  • 设置:System.err 表示以红色字体输出日志

② encode:配置日志输出格式,手动配置格式的方式

  • pattern:指定格式
<appender name="console" class="ch.qos.logback.core.ConsoleAppender" >
    <target>System.out</target>
    
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
    </encoder>
</appender>
  • %p:输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
  • %r:输出自应用启动到输出该日志讯息所耗费的毫秒数
  • %t:输出产生该日志事件的线程名
  • %f:输出日志讯息所属的类别的类别名
  • %c:输出日志讯息所属的类的全名
  • %d:输出日志时间点的日期或时间,指定格式的方式: %d{yyyy-MM-dd HH:mm:ss}
  • %l:输出日志事件的发生位置,即输出日志讯息的语句在他所在类别的第几行。
  • %m:输出代码中指定的讯息,如log(message)中的message
  • %n:输出一个换行符号

3)rootlogger根节点的配置

  • level:指定等级
  • appender-ref:引入appender
<root level="info">
    <appender-ref ref="console"/>
</root>

例:一个简单的logback配置文件

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

    <!--通用配置项,可以在其他地方通过${}方式引用-->
    <property name="pattern" value="通用配置属性"></property>

    <!--设置appender为控制台输出-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender" >
        <!--输出目标样式-->
        <target>System.out</target>
        <!--配置格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--配置layout格式-->
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>
    </appender>
    <!--配置root根节点-->
    <root level="info">
        <!--引入appender-->
        <appender-ref ref="console"/>
    </root>
</configuration>

4. Logback日志输出

4.1 日志输出到文件

logback通过FileAppender对象进行文件输出

配置项:

  • file:指定文件输出位置
  • append:是否追加,默认为true
  • encode:指定格式

例:

① 配置文件

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

    <!--通用配置项,文件地址-->
    <property name="file" value="D://logback"></property>

    <!--配置fileappender文件输出-->
    <appender name="fileappender" class="ch.qos.logback.core.FileAppender">
        <!--指定文件输出地址-->
        <file>${file}/logback.log</file>
        <!--是否进行追加 默认为true-->
        <append>true</append>
        <!--配置格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--配置layout格式-->
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>
    </appender>

    <!--配置root根节点-->
    <root level="info">
        <!--引入appender-->
        <appender-ref ref="fileappender"/>
    </root>

</configuration>

② 测试代码

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

    logger.trace("trace日志");
    logger.debug("debug日志");
    logger.info("info日志");
    logger.warn("warn日志");
    logger.error("error日志");
}
③ 输出

4.2 日志HTML格式输出

将日志输出成一个Html文件,这个html文件是由logback来控制样式,内容和格式由于开发者自定义

使用的appender依然是FileAppender,但是encoder输出格式为LayoutWrappingEncode

例:

① 配置文件

<!--通用配置项,文件地址-->
<property name="htmlfile" value="D://logback"></property>

<!--配置fileappender文件输出-->
<appender name="htmlfileappender" class="ch.qos.logback.core.FileAppender">
    <!--指定文件输出地址-->
    <file>${htmlfile}/logback.html</file>
    <!--是否进行追加 默认为true-->
    <append>true</append>
    <!--配置格式-->
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <!--配置HTMLlayout格式-->
        <layout class="ch.qos.logback.classic.html.HTMLLayout">
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </layout>
    </encoder>
</appender>

<!--配置root根节点-->
<root level="info">
    <!--引入appender-->
    <appender-ref ref="htmlfileappender"/>
</root>

② 测试代码

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

    logger.trace("trace日志");
    logger.debug("debug日志");
    logger.info("info日志");
    logger.warn("warn日志");
    logger.error("error日志");
}

③ 输出

4.3 日志拆分

Logback提供了RollingFileAppender对象对日志文件进行拆分存储

RollingFileAppender的两个重要属性:

  • RollingPolicy:指定拆分规则,提供日志目标文件自动切换的功能
  • TriggeringPolicy:Policy触发器

Logback文件拆分和Log4j的区别:

  • Logback通过RollingPolicy集成了多种拆分规则(大小拆分和时间拆分等等),而log4j需要单独指定规则
  • Logback功能更加强大,它提供的拆分不久支持日志大小和日志时间还有日志窗口日志滚动策略等

RollingPolicy拆分规则:

  • TimeBasedRollingPolicy:也许是最受欢迎的日志滚动策略。它的滚动策略是基于时间的,例如根据天数,月份
  • SizeAndTimeBasedRollingPolicy:有时候需要不仅想通过时间来规定滚动策略,还希望同时限制每个日志文件的大小。在TimeBasedRoolingPolicy中已经提供限制总日志文件的大小的功能,而SizeAndTimeBasedRollingPolicy提供了更为强大的,针对单个日志文件的大小限制能力
  • SizeBasedTriggeringPolicy:检测当前活动日志文件的大小,当到达一定容量,就开启日志滚动
  • FixedWindowRollingPolicy:固定窗口的日志滚动策略

例:使用SizeAndTimeBasedRollingPolicy进行拆分

① 配置文件

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

    <!--通用配置项,文件地址-->
    <property name="rollfile" value="D://logback"></property>

    <!--配置文件的append 可拆分归档的文件-->
    <appender name="roll" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!--输入格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>
        <!--文件输出位置-->
        <file>${rollfile}/roll_logback.log</file>
        <!--指定拆分规则-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--按照时间和压缩格式声明文件名 压缩格式为gz-->
            <fileNamePattern>${rollfile}/roll.%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>

            <!--按照文件大小进行拆分-->
            <maxFileSize>1KB</maxFileSize>
        </rollingPolicy>
    </appender>

    <!--配置root根节点-->
    <root level="info">
        <!--引入appender-->
        <appender-ref ref="roll"/>
    </root>
</configuration>

② 测试代码

@Test
    public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);
    for (int a=0;a<1000;a++){
        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warn日志");
        logger.error("error日志");
    }
}

③ 输出

5. logback异步日志

Logback默认日志记录输出是同步的,日志记录和业务代码存在逻辑先后关系

如:

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

    //日志记录代码
    for (int a=0;a<100;a++) {
        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warn日志");
        logger.error("error日志");
    }

    //假设为业务逻辑代码
    System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
    System.out.println("-=-=-=-=-----=-=-=-=-=-=-=-=-=-=-=-----=-=-");
    System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
}

输出:

  • 只要执行完日志记录代码,才执行逻辑代码
  • 假如日志记录量大,那么对应的业务逻辑会被推迟执行

由此出现问题:只要是记录日志,那么系统本身的功能就处于等待状态,当日志记录完毕后,才会执行其他代码,如果日志记录量非常庞大的话,那么我们对于系统本身业务代码的执行效率会降低

解决办法:使用异步线程解决,加一个日志记录线程,多线程操作,logback本身已提供,配置即可

配置步骤:

  1. 配置异步日志(AspncAppender),在异步日志中引入我们真正需要输出的appender
  2. 在rootlogger下引入异步日志

例:

① 配置文件

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

    <!--设置appender为控制台输出-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender" >
        <!--输出目标样式-->
        <target>System.out</target>
        <!--配置格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--配置layout格式-->
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>
    </appender>


    <!--配置异步日志-->
    <appender name="asyncAppender" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="console"/>
    </appender>


    <!--配置root根节点-->
    <root level="info">
        <!--引入appender-->
        <appender-ref ref="asyncAppender"/>
    </root>
</configuration>

② 测试

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

    //日志记录代码
    for (int a=0;a<100;a++) {
        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warn日志");
        logger.error("error日志");
    }


    //假设为业务逻辑代码
    System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
    System.out.println("-=-=-=-=-----=-=-=-=-=-=-=-=-=-=-=-----=-=-");
    System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
}

③ 输出

6. Logback日志过滤

logback在Appender中增加了filter日志过滤,支持对任何事件过滤输出,如:日志记录的内容、MDC内容、日期时间等等

logback-classic的2个常规过滤器:

  • LevelFilter:级别过滤器
  • ThresholdFilter:临界值过滤器

Filter三个过滤事件的值:它们都是FilterReply的枚举

  • DENY:记录事件立即被抛弃,不经过剩余过滤器
  • NEUTRAL:下一个处理器会处理记录事件
  • ACCEPT:记录事件被立即处理,不再经过剩余过滤器

<filter>标签包含3个子标签:

  • <level>:用于指定过滤的级别
  • <onMatch>:指定级别匹配时响应的值,值为FilterReply枚举
  • <onMismatch>:指定级别不匹配时响应的值,值为FilterReply枚举

例:LevelFilter级别过滤器

① 配置文件

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

    <!--通用配置项,可以在其他地方通过${}方式引用-->
    <property name="pattern" value="通用配置属性"></property>

    <!--设置appender为控制台输出-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender" >
        <!--输出目标样式-->
        <target>System.out</target>
        <!--配置格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--配置layout格式-->
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>

        <!--配置过滤器-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--设置日志的输出级别-->
            <level>ERROR</level>

            <!--高于level中设置的级别,则打印-->
            <onMatch>ACCEPT</onMatch>

            <!--低于level中设置的级别,则屏蔽日志-->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--配置root根节点-->
    <root level="info">
        <!--引入appender-->
        <appender-ref ref="console"/>
    </root>

</configuration>

② 测试

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);
        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warn日志");
        logger.error("error日志");
}

③ 输出

2022-11-10:10:19:22.598 [main] ERROR  error日志

7. Logback自定义logger

Logback的Logger底层结构和Log4j是一模一样的,都是树存储结构,根Logger都是RootLogger,所有的Logger都继承RootLogger

Logger父子关系都是按包结构的关系进行指定的,更具体的包名Logger继承更抽象的包名Logger

自定义Logger的属性:

  • name:路径
  • level:日志级别
  • additivity:表示是否继承rootLogger,flase表示不继承

例:

① 配置文件

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

    <!--设置appender为控制台输出-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender" >
        <!--输出目标样式-->
        <target>System.out</target>
        <!--配置格式-->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--配置layout格式-->
            <pattern>%d{yyyy-MM-dd:HH:mm:ss.SSS} [%thread] %-5level  %msg%n</pattern>
        </encoder>

        <!--配置过滤器-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--设置日志的输出级别-->
            <level>ERROR</level>

            <!--高于level中设置的级别,则打印-->
            <onMatch>ACCEPT</onMatch>

            <!--低于level中设置的级别,则屏蔽日志-->
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name="com.kxjslf4j" level="info" additivity="flase">
        <!--添加appender-->
        <appender-ref ref="console"/>
    </logger>

</configuration>

② 测试代码

@Test
public void test(){

    Logger logger = LoggerFactory.getLogger(slf4jCase.class);

        logger.trace("trace日志");
        logger.debug("debug日志");
        logger.info("info日志");
        logger.warn("warn日志");
        logger.error("error日志");
}

③ 输出

2022-11-10:11:20:58.691 [main] ERROR  error日志

8. logback配置文件的转换

对于不同的日志实现框架使用的配置文件都是不同的,Log4j使用peoperties属性文件,logback使用xml配置文件

如果一个应用程序以前使用了Log4j,但根据业务要求需要使用Logback来替换Log4j,针对这种情况logback提供了log4j.properties转换器

转换地址:https://logback.qos.ch/translator/services/propertiesTranslator.html

注:只有log4j和logback兼容的技术,才会被转换。如果是log4j独立的技术,logback没有或者不兼容,那么这个工具就不能被转化

例:

① log4j配置文件

log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
log4j.appender.myconsole.layout=org.apache.log4j.PatternLayout
log4j.appender.myconsole.layout.conversionPattern=[%p]%r %c %t %d{yyyy-MM-dd HH:mm:ss:SSS} %m%n

log4j.appender.myfile=org.apache.log4j.FileAppender
log4j.appender.myfile.layout=org.apache.log4j.SimpleLayout
log4j.appender.myfile.file=D:\\mylog4j.log
log4j.appender.myfile.encoding=UTF-8
log4j.rootLogger=info,myfile
log4j.logger.com.kxj.log4j.test=trace,myconsole

② 转化


路漫漫其修远兮,吾将上下而求索