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.

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

相关推荐
踏浪无痕6 分钟前
别再只会用 Feign!手写一个 Mini RPC 框架搞懂 Spring Cloud 底层原理
后端·面试·架构
降临-max9 分钟前
JavaWeb企业级开发---Ajax、
java·ajax·maven
NMBG229 分钟前
外卖综合项目
java·前端·spring boot
小徐Chao努力13 分钟前
Spring AI Alibaba A2A 使用指南
java·人工智能·spring boot·spring·spring cloud·agent·a2a
用户6956194403721 分钟前
前后端分离VUE3+Springboot项目集成PageOffice核心代码
后端
rannn_11122 分钟前
【Git教程】概述、常用命令、Git-IDEA集成
java·git·后端·intellij-idea
我家领养了个白胖胖23 分钟前
向量化和向量数据库redisstack使用
java·后端·ai编程
嘻哈baby26 分钟前
NextCloud私有云盘完整部署指南
后端
Ray6628 分钟前
Linux 日志处理三剑客:grep、awk、sed
后端
苹果醋334 分钟前
Java设计模式实战:从面向对象原则到架构设计的最佳实践
java·运维·spring boot·mysql·nginx