springboot应用系列5--springboot2整合logback

光焱      2022-04-12     216

关键词:

上一篇我们梳理了Spring Boot 2 整合log4j2的配置过程,其中讲到了Spring Boot 2原装适配logback,并且在非异步环境下logback和log4j2的性能差别不大,所以对于那些日志量不算太高的项目来说,选择logback更简单方便。

1. pom.xml

pom.xml不需要添加任何依赖。

2. logback的配置文件

系统启动时,logback按照下列顺序加载第一个找到的配置文件:

(1) classpath: logback-test.xml

(2) classpath: logback.groovy

(3) classpath: logback.xml

(4) 查询com.qos.logback.classic.spi.Configurator接口的实现

(5) 如果以上均未找到,则加载默认配置。

但是与Spring Boot集成时,上面的配置文件加载较早,Spring Boot为logback提供了很多扩展(比如<springProfile>节点),这些扩展的加载要晚于上面的配置文件,所以Spring Boot建议使用logback-spring.xml作为配置文件。

3. 配置目标

类似上一篇整合log4j2时的情况,我们希望达成以下目标:

(1) 所有级别的日志均可以通过控制台打印;

(2) 日志的存储目录格式为“/yyyy-MM/dd/”(“年-月/日/”),日志文件名称包含小时;

(3) error级别的日志存储在“/yyyy-MM/dd/app-error-{HH}.log”中,其中HH是日志发生的小时;

(4) 其他级别的日志存储在“/yyyy-MM/dd/app-other-{HH}.log”中;

(5) 所有级别的日志同时以html格式存储备份;

(6) 所有日志文件按照小时归档,一个小时一套文件(三个具体文件error,other);

(7) 设置日志文件的size上限,如果某一小时出现的日志特别多,超过size limit之后自动生成带数字后缀的文件。

4. logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <property name="Log_Home" value="logs" />
    <property name="Log_Pattern" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger - %msg%n" />

    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>${Log_Pattern}</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <appender name="RollingFile_Error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>true</prudent>
        <encoder>
            <pattern>${Log_Pattern}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${Log_Home}/%d{yyyy-MM}/%d{dd}/app-error-%d{HH-mm}.%i.log</FileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>10080</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="RollingFile_Other" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>true</prudent>
        <encoder>
            <pattern>${Log_Pattern}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>NEUTRAL</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${Log_Home}/%d{yyyy-MM}/%d{dd}/app-other-%d{HH-mm}.%i.log</FileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>10080</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="RollingFile_HTML" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <prudent>true</prudent>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%relative%thread%mdc%level%logger%msg</pattern>
            </layout>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <FileNamePattern>${Log_Home}/%d{yyyy-MM}/%d{dd}/app-%d{HH-mm}.%i.html</FileNamePattern>
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>10080</maxHistory>
        </rollingPolicy>
    </appender>

    <root level="info">
        <appender-ref ref="Console" />
        <appender-ref ref="RollingFile_Error" />
        <appender-ref ref="RollingFile_Other" />
        <appender-ref ref="RollingFile_HTML" />
    </root>
</configuration>

(1) logback的日志等级跟slf4j保持一致包括TRACE, DEBUG, INFO, WARN 和 ERROR;

(2) <configuration>节点设置debug="true"属性会在系统启动时打印logback加载的状态信息,如果logback加载过程中出现错误也会被打印出来,另外一种起同样作用的配置为在<configuration>节点中配置:

<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

(3) <property>节点属于xml级别的全局配置变量;

(4) <appender>节点中的<encoder>节点是日志事件的输出格式化配置,其中<Pattern>属性存储格式化规则,其中的符号含义分别为:

[%d{yyyy-MM-dd HH:mm:ss.SSS}]: 时间格式;

[%thread]: 输出日志的线程;

%-5level: 日志级别;

%logger: 日志调用者;

%msg: 日志内容;

%n: 换行符。

(5) <prudent>节点默认值为false,如果设置为true可确保在多线程下对同一日志文件的操作的线程安全性,但是打开之后写日志的性能会下降大约三倍。参考官网描述:

In prudent mode, FileAppender will safely write to the specified file, even in the presence of other FileAppender instances running in different JVMs, potentially running on different hosts. The default value for prudent mode is false.
Prudent mode can be used in conjunction with RollingFileAppender although some restrictions apply.

Prudent mode implies that append property is automatically set to true.

Prudent more relies on exclusive file locks. Experiments show that file locks approximately triple (x3) the cost of writing a logging event. On an "average" PC writing to a file located on a local hard disk, when prudent mode is off, it takes about 10 microseconds to write a single logging event. When prudent mode is on, it takes approximately 30 microseconds to output a single logging event. This translates to logging throughput of 100'000 events per second when prudent mode is off and approximately 33'000 events per second in prudent mode.

此外,prudent功能还有两个限制:

a. 日志文件不能被压缩;

b. 不能在<FileAppender>节点上设置file属性。

(6) <filter>节点用来配置过滤器,本例针对两个appender分别配置了两个<filter>,第一个filter只打印ERROR级别的日志,第二个filter只打印非ERROR级别的日志。此外logback还提供多种过滤器详见logback官网

关于onMatch和onMismatch,请看logback源码:

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.filter;
15  
16  import ch.qos.logback.core.spi.FilterReply;
17  
18  public abstract class AbstractMatcherFilter<E> extends Filter<E> {
19  
20      protected FilterReply onMatch = FilterReply.NEUTRAL;
21      protected FilterReply onMismatch = FilterReply.NEUTRAL;
22  
23      final public void setOnMatch(FilterReply reply) {
24          this.onMatch = reply;
25      }
26  
27      final public void setOnMismatch(FilterReply reply) {
28          this.onMismatch = reply;
29      }
30  
31      final public FilterReply getOnMatch() {
32          return onMatch;
33      }
34  
35      final public FilterReply getOnMismatch() {
36          return onMismatch;
37      }
38  }
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.spi;
15  
16  /**
17   *
18   * This enum represents the possible replies that a filtering component
19   * in logback can return. It is used by implementations of both 
20   * {@link ch.qos.logback.core.filter.Filter Filter} and
21   * ch.qos.logback.classic.turbo.TurboFilter abstract classes.
22   * 
23   * Based on the order that the FilterReply values are declared,
24   * FilterReply.ACCEPT.compareTo(FilterReply.DENY) will return 
25   * a positive value.
26   *
27   * @author S&eacute;bastien Pennec
28   */
29  public enum FilterReply {
30      DENY, NEUTRAL, ACCEPT;
31  }

简单来讲onMatch和onMismatch的取值都有三个分别是DENY(拒绝),NEUTRAL(进入下一个filter),ACCEPT(接受,跳过所有剩下的filter)。

(7) rollingPolicy节点配置日志文件的存档策略,本例后三个appender都是每分钟(不超过10MB)存储一个文件;

注意如果存档日志文件数量超过maxHistory值,最老的日子文件会被删除。

(8) 最后说一下<encoder>里面的<layout>,它是logback中的一个组件负责将日志事件转成字符串,先看一下它的接口定义:

public interface Layout<E> extends ContextAware, LifeCycle {
  String doLayout(E event);
  String getFileHeader();
  String getPresentationHeader();
  String getFileFooter();
  String getPresentationFooter();
  String getContentType();
}

继承该接口你就可以自定义自己的layout:

package chapters.layouts;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.LayoutBase;
public class MySampleLayout extends LayoutBase<ILoggingEvent> {
  public String doLayout(ILoggingEvent event) {
    StringBuffer sbuf = new StringBuffer(128);
    sbuf.append(event.getTimeStamp() - event.getLoggingContextVO.getBirthTime());
    sbuf.append(" ");
    sbuf.append(event.getLevel());
    sbuf.append(" [");
    sbuf.append(event.getThreadName());
    sbuf.append("] ");
    sbuf.append(event.getLoggerName();
    sbuf.append(" - ");
    sbuf.append(event.getFormattedMessage());
    sbuf.append(CoreConstants.LINE_SEP);
    return sbuf.toString();
  }
}

然后使用你自定义的layout:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
      <layout class="chapters.layouts.MySampleLayout" />
    </encoder>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

本例使用了logback自带的HTMLLayout。

5. logback不同环境不同配置

有两种实现方式:

(1) 按环境将配置文件拆分为logback-production.xml和logback-dev.xml等,然后在application.properties里面配置:

logging.config: classpath:logback-dev.xml

(2) 第二种是使用<springProfile>标签,在logback-spring.xml中配置:

<!-- develop -->
<springProfile name="dev">
    <root level="DEBUG">
        <appender-ref ref="CONSOLE" />
    </root>
</springProfile>
    
<!-- production -->
<springProfile name="prod">
    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</springProfile>

同时也有两种方式指定使用的环境:

a. 在application.properties里配置:

spring.profiles.active: dev
spring.profiles.active: prod

b. 启动时指定:

java -jar xxx.jar --spring.profiles.active=dev

6. 应用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class BaseController {
    protected static Logger logger = LoggerFactory.getLogger(BaseController.class);
}
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/log")
public class LogController extends BaseController {
    @RequestMapping("/all")
    public String all(String message) {
        logger.trace(message);
        logger.debug(message);
        logger.info(message);
        logger.warn(message);
        logger.error(message);
        System.out.println(message);

        try {
            System.out.println(3 / 0);
        } catch (Exception e) {
            logger.error(null, e);
        }

        return message;
    }
}

springboot系列springboot初级应用及配置文件(代码片段)

二、SpringBoot初级应用2.1SpringBoot项目目录结构src/main/java:文件目录(启动类和java代码编写)src/main/resource:存放静态资源文件的目录、配置文件、mybatis映射文件、属性文件等;src/test/java:测试代码目录... 查看详情

springboot应用系列6--springboot2整合quartz

...bsp;Scheduler(调度器):负责Job的执行。有两种方式可以实现SpringBoot与Quartz的整合:一、使用Spring 查看详情

docker系列-第七篇docker构建springboot应用

1.基于Dockerfile构建SpringBoot镜像1.1准备工作将SpringBoot项目通过maven打成jar包mvncleanpackage#使用maven打包项目1.2使用Dockerfile构建镜像step1在存放jar所在目录下创建Dockerfile文件touchDockerfilestep2编辑Dockerfile增加以下内容FROMjava:8MAINTAINERniuga 查看详情

docker系列-第七篇docker构建springboot应用

1.基于Dockerfile构建SpringBoot镜像1.1准备工作将SpringBoot项目通过maven打成jar包mvncleanpackage#使用maven打包项目1.2使用Dockerfile构建镜像step1在存放jar所在目录下创建Dockerfile文件touchDockerfilestep2编辑Dockerfile增加以下内容FROMjava:8MAINTAINERniuga 查看详情

springboot应用系列5--springboot2整合logback

上一篇我们梳理了SpringBoot2整合log4j2的配置过程,其中讲到了SpringBoot2原装适配logback,并且在非异步环境下logback和log4j2的性能差别不大,所以对于那些日志量不算太高的项目来说,选择logback更简单方便。1.pom.xmlpom.xml不需要添加... 查看详情

补习系列-springboot-restful应用

一、目标了解Restful是什么,基本概念及风格;能使用SpringBoot实现一套基础的Restful风格接口;利用Swagger生成清晰的接口文档。二、Restful入门什么是REST摘自百科的定义:REST即表述性状态转移(英文:RepresentationalStateTransfer,简称RE... 查看详情

springboot系列

https://my.oschina.net/xiedeshou?tab=newest&catalogId=5936801SpringBoot|第零章:前言SpringBoot|第一章:第一个SpringBoot应用SpringBoot|第二章:lombok介绍及简单使用SpringBoot|第三章:springboot配置详解SpringBoot|第四章:日志配置SpringBoot|第 查看详情

springboot系列springboot介绍和基础pom文件

SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Boot致力于在蓬勃发展的快... 查看详情

springboot系列springboot入门(代码片段)

一、SpringBoot入门1.1SpringBoot简介SpringBoot是在Sping(Spring4.0版本)基础上产生的,其中“Boot”的意思就是“引导”,意在简化开发模式,使开发者快速的开发出基于Spring的应用。SpringBoot含有一个内嵌的TomcatWeb服... 查看详情

springboot应用系列4--springboot2整合log4j2

一、背景1.log4j2传承于log4j和logback,它是目前性能最好的日志处理工具,有关它们的性能对比请看:2.除了性能好之外,log4j2有这么几个重要的新features:(1)自动热重载配置文件,而且重新加载期间不会丢失日志请求。logback也可以... 查看详情

springboot系列——配置相关

〇、SpringBoot的全局配置文件  通过上一篇我们可以知道,构建一个SpringBoot项目时,SpringBoot已经对项目进行了默认配置。但在实际应用中,每个项目有其特殊性,不可能仅使用默认的配置,还需自行添加或修改一些配置。  ... 查看详情

重学springboot系列之嵌入式容器的配置与应用(代码片段)

重学SpringBoot系列之嵌入式容器的配置与应用嵌入式容器的运行参数配置调整SpringBoot应用容器的参数两种配置方法配置文件方式常用配置参数tomcat性能优化核心参数自定义配置类方式为Web容器配置HTTPS如何生成自签名证书将SSL应... 查看详情

springboot系列springboot日志框架

注意:本SpringBoot系列文章基于SpringBoot版本v2.1.1.RELEASE进行学习分析,版本不同可能会有细微差别。前言Spring框架选择使用了JCL作为默认日志输出。而SpringBoot默认选择了SLF4J结合LogBack。那我们在项目中该使用哪种日志框架呢?在... 查看详情

springboot学习系列

springboot开发第一个应用程序1、springboot是什么?2、springboot容易上手吗?写这篇文章技术文章,主要是记录日常的学习以及理解。我们重新认识一下spring假设你受命使用spring开发一个简单的helloword的web程序。你该做什么?我能想... 查看详情

springboot系列:springboot使用actuator

Actuator为springboot提供了运行状态监控的功能通过集成它我们可以试试获取到应用程序的运行信息首先,在pom.xml中引入起步依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</arti 查看详情

springboot系列——快速构建项目

  前言  springboot官方参考指南:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/  SpringBoot是由spring家族提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用“约定大于配... 查看详情

springboot系列springboot整合持久层(代码片段)

这里写目录标题四、SpringBoot整合持久层4.1SpringBoot项目工程搭建4.2MyBatis逆向工程生成pojo和mapper文件1先建立包和文件夹,用于存储配置文件和逆向生成pojo和mapper文件2先引入pom依赖文件4.3应用实现增删改查四、SpringBoot整合持... 查看详情

springboot系列教程web篇之404500异常页面配置(代码片段)

...403无权,500服务器异常时,我们可以如何处理原文友链:SpringBoot系列教程web篇之404、500异常页面配置I.环境搭建首先得搭建一个web应用才有可能继续后续的测试,借助SpringBoot搭建一个web应用属于比较简单的活;创建一个maven项目,p... 查看详情