AI 助理
备案 控制台
开发者社区 开发与运维 文章 正文

万字详解logback日志框架,再没这么全的了!

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 万字详解logback日志框架,再没这么全的了!

老项目中日志使用混乱,某些项目使用log4j,某些项目使用logback,统一是必须的。既然Spring Boot已经将logback做为默认集成的日志框架,全面了解学习是必然了。


曾经log4j是流行的日志框架,现在已被它的继任者logback替代,logback更快,更小,更灵活。当然,如果你的项目中还在用System.out.println()来输出内容,那更是得行动起来,要么“逃”吧,要么改造吧。


logback简介

先来看看logback何许人也,最直接的就是看看它的官网 http://logback.qos.ch


image.pngimage.pnglogback-core为基础核心,另外两个均依赖它。其中logback-classic实现了简单日志门面SLF4J;logback-access主要作为一个与Servlet容器交互的模块,提供与HTTP访问相关的一些功能。


通常使用时直接引入logback-classic的依赖,便可自动引入logback-core,当然为保险起见也可以显式的引入两者。


SpringBoot对logback的支持

上面已经提到SpringBoot默认集成了logback,因此无需专门引入便可进行直接使用。后面的示例我们也基于SpringBoot来进行演示和讲解,毕竟方便嘛。


在SpringBoot的web项目中logback的依赖关系如下:


我们可以看到一旦引入spring-boot-starter-web依赖,对应的不仅引入了logback框架,还同时引入了slf4j相关框架。所以,项目中直接使用即可。


SpringBoot的集成

首先创建一个SpringBoot项目,核心依赖文件便是spring-boot-starter-web。


<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-web</artifactId>

</dependency>

1

2

3

4

如此便集成完成,其实嘛,等于根本不用集成。我们在项目中创建一个Controller类,其中打印不同级别的日志信息。


@RestController
public class HelloWorldController {
  private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class);
  @RequestMapping("/hello")
  public void hello() {
    log.debug("Hello world 测试debug日志");
    log.info("Hello world 测试info日志");
    log.warn("Hello world 测试warn日志");
    log.error("Hello world 测试error日志");
  }
}

上面代码中分别使用debug,info,warn,error方法输出日志。日志的所有配置,都是基于SpringBoot集成logback时的默认配置来的。


此时如果访问对应的url,便可打印出对应日志。


2020-10-18 21:22:59.800  INFO 45952 --- [nio-8080-exec-2] c.s.controller.HelloWorldController      : Hello world 测试info日志

2020-10-18 21:22:59.800  WARN 45952 --- [nio-8080-exec-2] c.s.controller.HelloWorldController      : Hello world 测试warn日志

2020-10-18 21:22:59.800 ERROR 45952 --- [nio-8080-exec-2] c.s.controller.HelloWorldController      : Hello world 测试error日志

1

2

3

为什么只打印了三行?因为SpringBoot默认日志输出级别为info级别。在application.properties文件中添加如下配置便可打印出debug级别的日志。


logging.level.com.secbro2=debug

1

其中com.secbro2为项目的基础package路径。更多配置使用下节专门进行讲解。


SpringBoot对logback的基础配置

SpringBoot对logback内置了一些默认配置,这与SpringBoot集成其他框架异曲同工。默认情况下SpringBoot将日志输出到控制台,不会写到日志文件。如果输出到日志文件,则需在application.properties中设置logging.file或logging.path属性。


# 注:二者不能同时使用。否则只有logging.file生效

logging.file=文件名

logging.path=日志文件路径

logging.level.包名=指定包下的日志级别

logging.pattern.console=日志打印规则

1

2

3

4

5

6

logging.file设置日志文件,可以是绝对路径或相对路径。如:logging.file=my.log。


logging.path设置日志目录,会在指定目录下创建spring.log文件,并写入日志内容,如:logging.path=/var/log。


二者不能同时使用,否则只有logging.file生效。


我们使用一下IDEA的提示功能可以看到,基于SpringBoot的默认配置还有以下选项。


image.png

image.png关于日志级别的配置,在上面已经有具体的示例了。设置格式为logging.leve.* =LEVEL,其中*为包名或logger名,LEVEL有:TRACE,DEBUG,INFO,WARN,ERROR,FATAL,OFF。


其他的就是日志文件的大小(默认10MB)、格式,以及控制台和日志文件内日志的格式配置了。根据提示我们可以很轻易搞定。


但是,你可能也发现了在application.properties中支持的配置有些简单。对的,如果需要配置复杂的日志内容,则需要基于xml配置文件来进行操作。


自定义logback配置

在application.properties中配置日志,通常在小型系统或对日志没有严格要求的系统中使用。如果运用在生产环境,通常建议通过基于xml文件来对logback进行自定义配置。


在SpringBoot中,默认支持四种命名的日志文件。


image.png也就是说如果在src/main/resources目录下放置其中任一类型的配置文件,SpringBoot便会自动进行使用。


而Spring Boot官方推荐优先使用带有-spring的文件名配置(如有logback-spring.xml,则不会使用logback.xml)。


若需要对配置文件名进行修改,或者希望把放到其它目录下,可以在application中通过logging.config属性来指定,如logging.config=classpath:config/my-log-config.xml。


logback-spring.xml详解

对于xml日志文件的配置,大多数人第一次接触时有一种望而生畏的感觉,其实如果仔细分析,会发现核心的部分只有三个元素:appender、logger、root。


image.png通过上图我们可以清理的了解整个xml文件的元素及功能。


其中configuration是根元素,必须的;logger和root可视为同一类,都是日志组件;logger定义日志从哪里(包)获取以及级别;appender配置日志格式、如何过滤、文件处理等。property和contextName元素,分别用来定义变量和应用上下文名称,非必须。


先通过一个简单的日志模板,从视觉上感受一下:


<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>
  <logger name="chapters.configuration" level="INFO"/>
  <root level="DEBUG">          
    <appender-ref ref="STDOUT" />
  </root>  
</configuration>

上述实例定义了控制台输出debug级别日志的配置。下面对相关的元素进行逐一讲解。


configuration元素

logback.xml配置文件的基本结构可以描述为configuration元素,包含零个或多个appender元素,后跟零个或多个logger元素,后跟最多一个root元素(也可以没有)。


根元素configuration有三个属性:


debug:默认为false,若设置为true,则打印出logback内部日志信息。

scan:默认值为true,若设置为true,配置文件如果发生改变,将会被重新加载。

scanPeriod:与scan配合使用,当scan为true时,此属性生效,默认的时间间隔为1分钟,设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。如可以设置为scanPeriod="30 seconds"每30秒检测一次。

定义上下文名称

contextName元素,每一个日志组件(logger)都会关联到日志上下文,默认上下文名称是’default’,用于标识应用,如果多个应用输出到同一个地方,就有必要使用%contextName来区别。


上线文的配置直接在configuration元素下:


<configuration>

   <contextName>HelloWorld-log</contextName>

</configuration>

1

2

3

经过定义之后,在其他property属性或appender中便可通过“%contextName”来获取和使用该上下文名称了。


定义变量

通过property元素可定义变量。它有name和value两个属性。变量可以使“${name}”来使用变量。作用类似于代码中的常量字符串,定义之后公共地方便可以统一使用。如日志文件名称前缀、日志路径、日志输出格式等。


<configuration>

   <property name="log.path" value="./log" />

</configuration>

1

2

3

上面便是定义了日志的根路径的变量。


如果是在Spring或SpringBoot项目当中,想让value值是通过配置文件获取,可使用springProperty来定义。


<springProperty scope="context" name="log.path" source="catalina.base"/>

1

其中source指定的catalina.base便是在application.properties当中配置变量。此配置还是比较常用的,可以做到灵活区分环境。


appender组件

appender组件用来定义日志输出格式,日志如何过滤以及日志文件的处理。appender的结构如下:


image.pngappender的属性有name和class。name指定appender名称,后面使用该appender是也是通过名称来指定。


class属性指定要实例化的appender类的完全限定名称。appender类默认有以下几种:


ConsoleAppender:日志输出到控制台,类名ch.qos.logback.core.ConsoleAppender。

FileAppender:日志输入到文件,类名ch.qos.logback.core.FileAppender。

RollingFileAppender:滚动记录文件,FileAppender的子类,当符合条件(大小、时间),日志进行切分处理。类名:ch.qos.logback.core.rolling.RollingFileAppender。

appender元素可以包含零个或一个layout元素,零个或多个encoder元素以及零个或多个filter元素。


实战中ConsoleAppender及RollingFileAppender使用较多,若需要自定义如把日志输出到消息队列,可以自定义实现AppenderBase接口。


ConsoleAppender上面已经有示例,主要作用就是将日志输出到控制台,并通过pattern元素指定了输出的格式。下面重点看一下RollingFileAppender的配置。


RollingFileAppender配置

RollingFileAppender是FileAppender的子类,扩展了FileAppender,具有翻转日志文件的功能。


例如,RollingFileAppender可以记录到名为log.txt文件的文件,并且一旦满足某个条件,就将其日志记录目标更改为另一个文件。


RollingFileAppender通常包括File、filter,rollingPolicy,encoder和layout元素。


encoder用来指定日志的输出格式及编码等:


<!-- 文件输出日志格式 -->
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n" />
<appender>
    <!--日志文件输出格式-->
    <encoder>
        <pattern>${FILE_LOG_PATTERN}</pattern>
        <charset class="java.nio.charset.Charset">UTF-8</charset>
    </encoder>
</appender>

file元素用来配置日志的路径和名称,一般把路径和文件名前缀定义到变量(property中)。


<encoder>

   <!-- 正在记录的日志文件的路径及文件名 -->

   <file>${log.path}/log_error.log</file>

</appender>

1

2

3

4

${log.path}获取的便是前面属性中定义的变量。


appender中可以有多个filter元素,比如用ThresholdFilter来过滤低于指定临界值的日志;用LevelFilter来过滤日志级别。以LevelFilter为例:


<!-- 过滤器,只记录debug级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>DEBUG</level>
    <OnMismatch>DENY</OnMismatch>
    <OnMatch>ACCEPT</OnMatch>
</filter>

其中level指定日志级别,onMath指定符合过滤条件的操作接收(ACCEPT),onMismatch指定不符合条件的拒绝(DENY)。


如果需要将不同级别的日志输出到不同的日志文件,那么就需要配置多个filter,每个filter像上面一样指定level级别:DEBUG,INFO,WARN和ERROR。


通常情况下,日志输出会配置三个,一个控制台输出用于开发阶段;一个INFO及以上级别的日志输出,可追踪相应的生产日志;一个单独ERROR级别的日志输出,方便快速检查出异常日志。


rollingPolicy用于配置滚动策略,支持TimeBasedRollingPolicy、SizeAndTimeBasedRollingPolicy、FixedWindowRollingPolicy、SizeBasedTriggeringPolicy。


分别是基于时间滚动、基于大小和时间滚动、固定窗口滚动和大小触发。其中FixedWindowRollingPolicy一般和SizeBasedTriggeringPolicy同时使用。下面以TimeBasedRollingPolicy为例,以天为单位输出日志,每天一个日志。


<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <!-- 日志输出格式 -->
    <fileNamePattern>${log.path}/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
    <!-- 日志保留天数 -->
    <maxHistory>30</maxHistory>
</rollingPolicy>

fileNamePattern指定日志的路径及名称,此处是按日期输出,即%d{yyyy-MM-dd}格式。maxHistory表示日志最多保留天数,存活超过30天的日志会被删除。


logger配置

logger用来设置某一个类或者某个包的日志输出级别、以及关联的appender。


logger包含三个属性:


name:要输出日志的包名或者类名,比如com.secbro2。必选项。

level:设置日志级别,允许一个不区分大小写的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。如果未设置,则logger会向上继承最近一个非空级别。可选项。

additivity:是否将日志向上级传递,默认为 true。可选项。

logger通过1个或多个子节点appender-ref来控制日志的输出。


<logger name="org.springframework" level="WARN"/>

<logger name="com" level="debug" />

1

2

上面示例表示org.springframework包下的日志以warn级别输出,com包下的日志以debug级别输出。


<logger name="com.secbro2" level="info" additivity="true">

   <appender-ref ref="CONSOLE" />

</logger>

1

2

3

上面的示例对指定包指定appender进行日志控制,由于设置了info级别,additivity为true,而且关联CONSOLE的appender,因此info以上级别的日志会输出到控制台。


同时会把日志上传到父级,即root。若root也有配置CONSOLE的输出的话,会在控制台输出两次。additivity为false,则不会。


root配置

root元素配置根记录器。它是一个特殊的logger,是所有logger的根节点,只有一个属性level,默认为DEBUG 。


<root level="info">

   <appender-ref ref="CONSOLE" />

   <appender-ref ref="LOGSTASH" />

   <appender-ref ref="INFO_FILE" />

   <appender-ref ref="ERROR_FILE" />

</root>

1

2

3

4

5

6

level属性的值可以是不区分大小写的字符串TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。root元素可以包含零个或多个appender-ref元素;被引用的每个appender都被添加到根记录器中。


如果是基于SpringBoot项目,针对不同环境(profile)有不同的日志输出,比如开发(dev)环境只输出CONSOLE的,生产环境(prod)只输入info和error,那则可用到Spring支持的profile机制。对应的元素为springProfile。


profile的值与springboot中配置文件的spring.profiles.active值进行对照。


<!-- 开发环境 -->
<springProfile name="dev">
    <logger name="com" level="debug" />
    <root level="info">
        <appender-ref ref="CONSOLE" />
    </root>
</springProfile>
<!-- 测试环境+生产环境 -->
<springProfile name="test,prod">
    <logger name="com" level="info" />
    <root level="info">
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
</springProfile>

当引入了springProfile,我们可以看到root元素可以出现多次了,但还是保证了一个环境只有一个root元素的要求。springProfile的name对应spring.profiles.active的值,多个值用逗号分隔。


ELK的配置

如果项目中的日志采用的是基于ELK(Elasticsearch,Logstash,Kibana三个开源软件的缩写)来进行日志管理。则可以在pom文件中引入logstash-logback-encoder依赖。


<dependency>

   <groupId>net.logstash.logback</groupId>

   <artifactId>logstash-logback-encoder</artifactId>

   <version>5.1</version>

</dependency>

1

2

3

4

5

然后在logback-spring.xml中配置对应的appender:


<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>debug</level>
    </filter>
    <destination>192.168.0.11:5061</destination>
    <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
        <customFields>{"project": "springboot-logback-elk"}</customFields>
    </encoder>
</appender>

该appender的使用与其他appender的使用无异。主要使用了LogstashTcpSocketAppender类来完成与Logstash的通信。其中destination为Logstash提供的服务地址。customFields为自定义的参数,便于Logstash识别日志是从哪个业务系统传输过来的。


输出logback状态数据

某些时候为了了解logback配置文件加载情况,配置中对应的appender、logger的装载情况等,我们需要启用logback状态数据的输出。这也是logback官网强烈推荐的,可以帮助我们排除诊断一些问题。


启用状态数据输出有两种方式:


在根元素(configuration) 中设置属性debug=“true”。

添加元素(statusListener),class使用OnConsoleStatusListener。如下:

<!-- 输出logback的本身状态数据 -->

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

1

2

两种方式选其一即可。第一种方式的debug与配置文件中的日志级别没有关系,只用于表示输出状态数据。


当采用第一种方式时,访问最开始的实例打印日志如下:


image.png通过日志可以看出打印了日志输出的文件及相关TimeBasedArchiveRemover的操作信息。


异步输出日志

前面讲到的appender,日志输出到文件是同步输出的,即每次输出都会直接写IO到磁盘文件。对于高并发的应用,会产生一定的阻塞,造成不必要的性能损耗。


logback提供了日志异步输出的AsyncAppender。处理方式也很简单,添加一个基于异步写日志的appender,并指向原配置的appender即可:


<!-- 异步输出 -->
<appender name="ASYNCDEBUG" class="ch.qos.logback.classic.AsyncAppender">
    <!-- 默认如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志,若要保留全部日志,设置为0 -->
    <discardingThreshold>0</discardingThreshold>
    <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
    <queueSize>1024</queueSize>
    <!-- 添加附加的appender,最多只能添加一个 -->
    <appender-ref ref="DEBUGFILE"/>
    <includeCallerData>true</includeCallerData>
</appender>
// INFO结构同上
<!-- 异步输出关联到root -->
<root level="DEBUG">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="ASYNCDEBUG" />
    //...
</root>

AsyncAppender的实现原理是通过阻塞队列(BlockingQueue)来避免日志直接输出到文件,先把日志事件输出到BlockingQueue中,然后启动一个新的worker线程,主线程不阻塞,worker线程则从队列中获取需要写的日志,异步输出到对应的位置。


MDC分布式应用追踪请求

上面所讲的日志都是在单个应用系统下记录日志的。一旦进入分布式系统,很可能就会出现日志错乱,对日志追踪和排查造成难题。如果使用像ELK这类框架将日志进行归集统一处理,也需要一个标识,来记录日志的整个请求处理过程。


logback提供了MDC(Mapped Diagnostic Contexts诊断上下文映射),可以让开发人员在诊断上下文中放置信息。通过ThreadLocal实现了线程与线程之间的数据隔离。在输出时可以通过标识符%X{key}来输出MDC中设置的内容。


分布式应用追踪请求实现思路如下:


image.png下面来看一下具体的实现代码。首先定义个简单工具来生成一个唯一的请求标识,这里采用UUID作为标识。


public class IdUtil {

public static String simpleUuid() {

 return UUID.randomUUID().toString().replaceAll("-", "");

}

}

1

2

3

4

5

然后通过实现接口HandlerInterceptor来自定义一个拦截器。

@Component
public class RequestIdTraceInterceptor implements HandlerInterceptor {
  private static final String REQUEST_ID_KEY = "request-id";
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler) {
    MDC.put(REQUEST_ID_KEY, getRequestId(request));
    return true;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                              Object handler, Exception ex) {
    // 把requestId添加到响应头,以便其它应用使用
    response.addHeader(REQUEST_ID_KEY, MDC.get(REQUEST_ID_KEY));
    // 请求完成,从MDC中移除requestId
    MDC.remove(REQUEST_ID_KEY);
  }
  public static String getRequestId(HttpServletRequest request) {
    String paramRequestId = request.getParameter(REQUEST_ID_KEY);
    String headerRequestId = request.getHeader(REQUEST_ID_KEY);
    // 根据请求参数或请求头判断是否有“request-id”,有则使用,无则创建
    String requestId;
    if (paramRequestId == null && headerRequestId == null) {
      requestId = IdUtil.simpleUuid();
    } else {
      requestId = paramRequestId != null ? paramRequestId : headerRequestId;
    }
    return requestId;
  }
}

代码的思路与上面的图一致,实现接口的preHandle方法用于请求前的处理,调用getRequestId方法从参数和header中获取对应的值,如果都没有获取到,则生成一个新的。否则,取两者中不为空的那个值。


实现接口的afterCompletion方法做了两件事:第一,相应其他系统时返回request-id的值,以便其他系统继续保持同一因为的连续性;第二,清除自身系统中存储的值。


上面只是实例化了自定义的拦截器,并没有对拦截器进行注册使用。在SpringBoot项目中可在实现接口WebMvcConfigurer的addInterceptors方法时,将实例化的拦截件进行添加。


@Configuration
public class WebConfig implements WebMvcConfigurer {
  @Resource
  private RequestIdTraceInterceptor requestIdTraceInterceptor;
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 添加拦截器
    registry.addInterceptor(requestIdTraceInterceptor);
  }
}

这里通过@Resource将RequestIdTraceInterceptor注入,然后通过InterceptorRegistry的addInterceptor方法将其注册。


此时,理论上访问URL请求的过程中已经添加了request-id。但上面我们提到,还需要通过%X{key}才能在logback中获取和输出。


那么就在logback中定义输出格式时在适当的位置进行添加。


<property name="CONSOLE_LOG_PATTERN"

 value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%X{request-id}] %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

1

2

上面的是基于控制台的输出表达式,比较复杂。大家注意看“[%X{request-id}]”部分便是用来输出request-id的值的。


现在启动程序,会发现并没有打印出request-id的值:


2020-10-19 22:02:10.200  INFO [] 76397 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-10-19 22:02:10.204  INFO [] 76397 --- [           main] com.secbro2.ElkApplication               : Started ElkApplication in 2.02 seconds (JVM running for 2.715)
2020-10-19 22:02:24.052  INFO [] 76397 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-10-19 22:02:24.053  INFO [] 76397 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-10-19 22:02:24.060  INFO [] 76397 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms
2020-10-19 22:02:24.078 DEBUG [] 76397 --- [nio-8080-exec-1] c.s.i.RequestIdTraceInterceptor          : no request-id in request parameter or header

只是打印了一个空的中括号,这是因为还没有Http请求,当然就没创建对应的request-id。下面请求一下最初实例的URl,日志打印格式如下:


2020-10-19 22:02:24.085 DEBUG [0097978409374988b7fcaf2debb1a125] 76397 --- [nio-8080-exec-1] c.s.controller.HelloWorldController      : Hello world 测试debug日志

2020-10-19 22:02:24.085  INFO [0097978409374988b7fcaf2debb1a125] 76397 --- [nio-8080-exec-1] c.s.controller.HelloWorldController      : Hello world 测试info日志

2020-10-19 22:02:24.085  WARN [0097978409374988b7fcaf2debb1a125] 76397 --- [nio-8080-exec-1] c.s.controller.HelloWorldController      : Hello world 测试warn日志

2020-10-19 22:02:24.085 ERROR [0097978409374988b7fcaf2debb1a125] 76397 --- [nio-8080-exec-1] c.s.controller.HelloWorldController      : Hello world 测试error日志

1

2

3

4

request-id完美打印出来了。读者可以尝试两个系统之间的交互操作,这里就不再用实例演示了。


代码中的日志格式

在日常使用日志时,可以通过最开始的示例定义Logger对象,然后调用其对应级别的日志输出。当然,如果采用Lombok的情况下,可直接类上使用@Slf4j注解来自动注入log属性,不用再声明:


private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class);

1

替换为:


@Slf4j

@RestController

public class HelloWorldController {

}

1

2

3

4

其他内容不变。


而在日志输出格式也有多种,其中最不可取的形式是如下模式的日志输出:


Object entry = new SomeObject();

logger.debug("The entry is " + entry);

1

2

这种模式会导致即使采用info基本输出,debug中的对象toString和字符串拼装依旧会处理。建议采用如下模式输出:


Object entry = new SomeObject();

logger.debug("The entry is {}.", entry);

1

2

此时,如果日志输出级别为info,则不会处理对象的toString和字符串的拼接。


logback作者进行测试得出:第一种和第二种写法输出结果相同。但在禁用日志记录语句的情况下,第二种将比第一种写法优于至少30倍。


小结

到此,关于logback日志框架的讲解告一段落,如果你还想了解更多底层原理和一些表达式,建议看一下官方的手册,虽然是英文的,但还是比较全面的。



相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
longfor5
目录
相关文章
最好zzz
|
7天前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
最好zzz
58 3
丰宝宝
|
27天前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
丰宝宝
34 2
大数据文摘
|
7天前
|
SQL XML 监控
SpringBoot框架日志详解
本文详细介绍了日志系统的重要性及其在不同环境下的配置方法。日志用于记录系统运行时的问题,确保服务的可靠性。文章解释了各种日志级别(如 info、warn、error 等)的作用,并介绍了常用的日志框架如 SLF4J 和 Logback。此外,还说明了如何在 SpringBoot 中配置日志输出路径及日志级别,包括控制台输出与文件输出的具体设置方法。通过这些配置,开发者能够更好地管理和调试应用程序。
大数据文摘
14 0
拉丁解牛说技术
|
1月前
|
Java
日志框架log4j打印异常堆栈信息携带traceId,方便接口异常排查
日常项目运行日志,异常栈打印是不带traceId,导致排查问题查找异常栈很麻烦。
拉丁解牛说技术
114 7
最好zzz
|
1月前
|
运维 NoSQL Java
SpringBoot接入轻量级分布式日志框架GrayLog技术分享
在当今的软件开发环境中,日志管理扮演着至关重要的角色,尤其是在微服务架构下,分布式日志的统一收集、分析和展示成为了开发者和运维人员必须面对的问题。GrayLog作为一个轻量级的分布式日志框架,以其简洁、高效和易部署的特性,逐渐受到广大开发者的青睐。本文将详细介绍如何在SpringBoot项目中接入GrayLog,以实现日志的集中管理和分析。
最好zzz
146 1
萝卜丝丸子
|
2月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
Java应用结构规范问题之配置Logback以仅记录错误级别的日志到一个滚动文件中的问题如何解决
萝卜丝丸子
47 7
萝卜丝丸子
|
2月前
|
Java 应用服务中间件 HSF
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
Java应用结构规范问题之配置Logback以在控制台输出日志的问题如何解决
萝卜丝丸子
35 7
阿里云开发者
|
2月前
|
XML Java API
Java日志通关(四) - Logback 介绍
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第四篇。
阿里云开发者
68 1
阿里云开发者
|
2月前
|
JavaScript Java API
Java日志通关(二) - Slf4j+Logback 整合及排包
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第二篇。
阿里云开发者
226 1
热爱技术的小郑
|
2月前
|
XML Java Maven
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)
这篇文章是Spring5框架的入门到实战教程,介绍了Spring5的新功能——整合日志框架Log4j2,包括Spring5对日志框架的通用封装、如何在项目中引入Log4j2、编写Log4j2的XML配置文件,并通过测试类展示了如何使用Log4j2进行日志记录。
热爱技术的小郑
45 0
Spring5入门到实战------16、Spring5新功能 --整合日志框架(Log4j2)

热门文章

最新文章

  • 1
    Oracle自动清理日志脚本
  • 2
    POCO日志组件Tips
  • 3
    打开haproxy的日志
  • 4
    shell脚本之日志拆分和监听
  • 5
    【阿里巴巴Java编程规范学习 三】Java异常日志规约
  • 6
    A complete log of this run can be found in:npm ERR! C:AppData\Roaming\npm-cache\_logs
  • 7
    年度回顾:阿里云Elasticsearch 在泛日志场景的核心能力建设
  • 8
    SQL Server-聚焦事务对本地变量、临时表、表变量影响以及日志文件存满时如何收缩(三十一)
  • 9
    使用elk+redis搭建nginx日志分析平台(转)
  • 10
    仿酷狗音乐播放器开发日志十一——CTreeNodeUI的bug修复
  • 1
    聊聊日志硬扫描,阿里 Log Scan 的设计与实践
    341
  • 2
    Python中精通异常日志记录
    39
  • 3
    MySQL通过 bin-log 恢复从备份点到灾难点之间数据
    277
  • 4
    Linux ContOS7 日志管理(rsyslog)
    55
  • 5
    Android 截屏 录屏 与获取log
    46
  • 6
    查询提速11倍、资源节省70%,阿里云数据库内核版 Apache Doris 在网易日志和时序场景的实践
    53144
  • 7
    中间件应用日志记录和监控
    177
  • 8
    mongoDB查看数据的插入日志
    369
  • 9
    neo4j如何查看日志信息
    270
  • 10
    Springboot整合与使用log4j2日志框架【详解版】
    537
  • 相关课程

    更多
  • 基于MongoDB构建实时日志分析平台
  • 日志服务SLS实现云产品可观测
  • 日志服务 SLS 可观测数据分析平台介绍
  • 大数据知识图谱系列—基于ELK+Flink日志全观测最佳实践
  • 场景实践-基于阿里云Quick BI 对MOOC网站日志分析
  • 相关电子书

    更多
  • PostgresChina2018_赖思超_PostgreSQL10_hash索引的WAL日志修改版final
  • Kubernetes下日志实时采集、存储与计算实践
  • 日志数据采集与分析对接
  • 相关实验场景

    更多
  • 通过日志服务实现云资源OSS的安全审计
  • 如何将OSS数据导入至SLS中进行分析
  • 日志服务之使用Nginx模式采集日志
  • 日志服务之告警接入与管理
  • 日志服务之数据清洗与入湖
  • 揭秘如何通过日志服务实现个人敏感信息保护
  • 下一篇
    阿里云无影云电脑免费试用,最长可试用3个月

    玻璃钢生产厂家福建开业商场美陈供应玻璃钢雕塑设计报价钟楼商场美陈新余定制玻璃钢雕塑生产厂家甘肃大型玻璃钢雕塑济源学校玻璃钢仿铜雕塑厂家公园摆件玻璃钢人物雕塑厂家现货军人浮雕玻璃钢仿铜雕塑饮料瓶玻璃钢雕塑玻璃钢动物马雕塑制造厂家佛山古代玻璃钢雕塑耒阳玻璃钢十二生肖雕塑陕西玻璃钢浮雕景观雕塑厂家南昌户内玻璃钢雕塑供应商湖南玻璃钢卡通雕塑宜春个性化玻璃钢雕塑玻璃钢橙子雕塑摆件德兴玻璃钢马雕塑平顶山玻璃钢浮雕室外雕塑宁夏景区玻璃钢雕塑设计商场开业美陈文案怀化商场美陈池州环保玻璃钢雕塑多少钱代理玻璃钢动漫雕塑厂南宁抽象玻璃钢雕塑订做价格优质玻璃钢雕塑优选企业河池玻璃钢泡沫雕塑厂家供应通州区商场美陈公司报价河北景观玻璃钢雕塑太原多彩玻璃钢雕塑多少钱香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

    玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化