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.

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

相关推荐
先做个垃圾出来………几秒前
Linux/Unix系统下的基础文本处理命令
java·linux·unix
风若飞几秒前
Linux 环境下解决 Tomcat8 与 JDK8 配置问题
java·linux·运维·服务器·tomcat
ONExiaobaijs2 分钟前
Java jdk运行库合集
java·开发语言·python
Coder_Boy_13 分钟前
基于SpringAI的在线考试系统-教学管理与用户管理模块联合回归测试文档
java·前端·数据库·人工智能·spring boot
Knight_AL14 分钟前
一文讲透 Java 中transient的用处(结合 Flink 理解)
java·python·flink
xqqxqxxq20 分钟前
《智能仿真无人机平台(多线程V1.0)技术笔记》(初识线程,带你理解程序运行的基本流程)
java·笔记
进阶小白猿22 分钟前
Java技术八股学习Day23
java·网络·学习
砚边数影25 分钟前
DL4J框架入门(三):基础配置,计算后端(CPU/GPU)选型与优化
java·数据库·人工智能·ai·金仓数据库
名字无法显示34128 分钟前
Arthas 实战指南:结合 IDEA 的 Java 线上排查完整流程
java·intellij-idea
小阿鑫30 分钟前
32岁程序员猝死背后,我的一些真实感受
前端·后端·程序员·代码人生