Logback输出json格式日志,及异常信息不在Json串内的原因分析

前言

日志什么场景要输出为json格式,以及关于logback的介绍等,不是本文讨论的重点,所以不再说明。

下面的部分假定你已经熟悉logback了,如果你平常也用logback,但是每次都是从网上随便复制一个配置文件直接用,对其中的标签并不了解,那看这篇文章不能保证很轻松。

日志格式

logback的配置文件中,我们可以指定输出日志的格式,如下是一个特别简单的格式:

xml 复制代码
<appender name="SIMPLE-CONSOLE" class="ch.qos.logback.core.ConsoleAppender">  
    <encoder>  
        <pattern>%level %thread %msg \r\n</pattern>  
        <charset>UTF-8</charset>  
    </encoder>  
</appender>

打印日志的级别、线程、日志信息,最后加上了回车换行符。 这是效果:

至于有哪些字段可以输出,可以看ch.qos.logback.classic.PatternLayout 里面设置的转换器。

json格式

现在想把日志输出为json格式,那也很简单,如下定义:

xml 复制代码
<appender name="JSON-CONSOLE" class="ch.qos.logback.core.ConsoleAppender">  
    <encoder>  
        <pattern>{ "level":"%level", "thread": "%thread", "msg":"%msg" }\r\n</pattern>  
        <charset>UTF-8</charset>  
    </encoder>  
</appender>

打印一下效果:

看起来也是比较预期。

如果抛个异常呢,最开始示例的常规文本输出格式,异常也是会正常打印的,如果是Json格式呢,如下:

异常信息和msg信息是分离的,并不在一个json体内,这就很不预期了,实际期望的应该是msg里面包含着异常信息。

字段转换

如上图所示,定义appender的时候,指定了日志格式,及输出哪些字段。

logback就是将pattern里的字段转换为对应的值,然后按照对应的格式输出。所以我们定义为json格式的时候,logback也是将其中的相关变量字段替换为实际值,对于其中的字面值,比如"{ }"等部分,还是原样拼接成一个字符。

encoder标签默认使用的实现类是ch.qos.logback.classic.encoder.PatternLayoutEncoder类

pattern标签默认使用的实现类是ch.qos.logback.classic.PatternLayout类

打个断点看下这个拼接的过程,这是拼了一半的样子:

这部分的源码,一两句话并不能说清楚,简单来说,就是logback使用对应字段的转换器,将字段转换为对应的值。

异常的输出

各个字段会使用对应的转换器替换为实际的值输出,%msg对应的转换器,实际只是输出原始日志,并不包含异常信息:

而我们实际也没并有要输出异常信息,我们只定义了这三个字段:

xml 复制代码
<pattern>%level %thread %msg \r\n</pattern>  

没有指定异常字段,异常字段是下面这几个:

但是打印日志依然输出了异常,究其原因,是因为logback自动帮我们拼接了一个异常的转换器,可以这样理解,我们定义的是:

perl 复制代码
<pattern>{ "level":"%level", "thread": "%thread", "msg":"%msg" }\r\n</pattern>  

实际上是:

perl 复制代码
<pattern>{ "level":"%level", "thread": "%thread", "msg":"%msg" }\r\n %ex</pattern>  

这个过程,是在new PatternLayout()实例的时候发生的。

所以我们虽然输出Json,却在json串后面打印了一个异常信息。这是相关代码注释,大意是检查定义的转换器链是否处理了异常,如果没有就添加一个到链的末尾:

This implementation checks if any of the converters in the chain handles exceptions. If not, then this method adds a ExtendedThrowableProxyConverter instance to the end of the chain.

这就是最后很突兀的打印异常栈的原因,至于解决办法,下一篇文章进行说明。

相关推荐
是小蟹呀^15 分钟前
Spring Security + JWT 面试题整理
java·jwt·springsecurity
spencer_tseng2 小时前
Redis + Nacos.bat
java·windows·dos
霸道流氓气质3 小时前
SpringBoot中通用工具类库(Utils)封装与使用实践
spring boot·后端·python
troyzhxu3 小时前
列表查询的 GraphQL —— 一行代码终结你的 if-else 地狱!
java·springboot·graphql
孫治AllenSun4 小时前
【DataX】生产环境搭建DataX集群案例
java·开发语言·jvm
好好沉淀5 小时前
@NotBlank(message = “{xxx}“) 注解中花括号的含义
java
fīɡЙtīиɡ ℡5 小时前
内存泄漏产生的原因
java·spring·servlet
hkj88085 小时前
Ubuntu 切换java版本
java·linux·ubuntu