如何使用LoggingEventCompositeJsonEncoder仅输出JSON日志?
你现在同时输出普通日志和JSON日志,核心原因是引入的org/springframework/boot/logging/logback/base.xml已经默认配置了一个输出普通文本的控制台Appender(名为CONSOLE),而你自己又添加了JSON格式的jsonConsoleAppender,两个Appender都被关联到root logger,所以会重复输出。
解决方法有两种,选一种就行:
方法1:移除base.xml的引入,自行配置基础日志规则
直接删掉<include resource="org.springframework.boot.logging.logback.base.xml"/>这一行,保留自己的Logger级别配置和JSON Appender即可。修改后的完整配置如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <logger name="org.springframework.web" level="INFO"/> <logger name="org.apache" level="INFO"/> <!-- SECURITY --> <logger name="httpclient" level="INFO"/> <appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp/> <version/> <message/> <loggerName/> <threadName/> <logLevel/> <mdc/> <arguments/> <pattern> <pattern> { "myField": { "mySubField": "%mdc{abc}" }, "myField2": "%mdc{abc}" } </pattern> <omitEmptyFields>true</omitEmptyFields> </pattern> <logstashMarkers/> </providers> </encoder> </appender> <root level="INFO"> <appender-ref ref="jsonConsoleAppender" /> </root> </configuration>
方法2:保留base.xml,但禁用默认的普通文本控制台Appender
如果不想丢掉base.xml里的其他默认配置(比如文件日志、日志级别默认值),可以在引入base.xml后,给默认的CONSOLE Appender添加过滤规则,让它拒绝所有日志:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org.springframework.boot.logging.logback.base.xml"/> <!-- 禁用默认的普通文本控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator> <expression>false</expression> </evaluator> <onMismatch>ACCEPT</onMismatch> <onMatch>DENY</onMatch> </filter> </appender> <logger name="org.springframework.web" level="INFO"/> <logger name="org.apache" level="INFO"/> <!-- SECURITY --> <logger name="httpclient" level="INFO"/> <appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp/> <version/> <message/> <loggerName/> <threadName/> <logLevel/> <mdc/> <arguments/> <pattern> <pattern> { "myField": { "mySubField": "%mdc{abc}" }, "myField2": "%mdc{abc}" } </pattern> <omitEmptyFields>true</omitEmptyFields> </pattern> <logstashMarkers/> </providers> </encoder> </appender> <root level="INFO"> <appender-ref ref="jsonConsoleAppender" /> </root> </configuration>
是否推荐用LogManager.getLogger("CONSOLE_JSON_APPENDER")这种方式?
完全不推荐。这种做法违背了日志框架的设计初衷:
- 常规通过类获取Logger(比如
LoggerFactory.getLogger(YourClass.class)),日志里的loggerName字段会显示类的全限定名,能直接定位到日志的产生位置,对排查问题至关重要; - 用自定义名称获取Logger,会丢失类的归属信息,日志里的
loggerName变成你指定的字符串,后续排查问题时根本不知道这条日志来自哪个类、哪个模块。
如果想要定向让某些日志输出到JSON Appender,正确的做法是给特定包/类的Logger配置专属Appender,而不是通过自定义Logger名称来绑定。
常规创建Logger时的类信息去哪了?
当你用LoggerFactory.getLogger(YourClass.class)时,框架会把该类的全限定名作为Logger的名称,后续输出日志时,这个名称会被写入loggerName字段(也就是你配置里的<loggerName/>对应的JSON字段)。而用自定义名称时,这个类信息就被替换成了你指定的字符串,自然不会出现在日志里。
内容的提问来源于stack exchange,提问作者Baradè

