如何为Log4j2 JsonTemplateLayout仅在错误日志中添加支持动态赋值与默认值的自定义字段
没问题,我来帮你实现这个需求!咱们一步步来,用Log4j的JsonTemplateLayout结合自定义模板和上下文参数就能搞定。
1. 自定义JSON日志模板
首先,我们需要创建一个自定义的JSON模板文件,用来实现仅在ERROR级别显示额外字段的逻辑,同时支持默认值。在src/main/resources下新建CustomLogstashJsonEventLayoutV1.json,内容如下:
{ "@version": 1, "source_host": "${hostName}", "message": "$${message}", "thread_name": "$${threadName}", "@timestamp": "$${date:format=yyyy-MM-dd'T'HH:mm:ss.SSSXXX}", "level": "$${level}", "logger_name": "$${loggerName}", "aNumber": 1, {{#if level == "ERROR"}} "severity": "${json:map=contextMap:key=severity:default=DEFAULT_SEVERITY}", "err_code": "${json:map=contextMap:key=err_code:default=DEFAULT_ERROR_CODE}" {{/if}} }
这里用到了Handlebars语法的{{#if}}条件判断,只有当日志级别为ERROR时才渲染severity和err_code字段;同时通过json:map从日志上下文读取参数,如果没有传入则使用默认值。
2. 修改Log4j2配置文件
更新你的log4j2.properties,把布局的模板路径改成我们刚创建的自定义模板,还可以把默认值提到配置文件里方便修改:
monitorInterval=20 appenders = APP_CONSOLE appender.APP_CONSOLE.type = Console appender.APP_CONSOLE.name = APP_CONSOLE appender.APP_CONSOLE.filter.threshold.type = ThresholdFilter appender.APP_CONSOLE.filter.threshold.level = DEBUG appender.APP_CONSOLE.layout.type = JsonTemplateLayout # 改用自定义模板 appender.APP_CONSOLE.layout.eventTemplateUri = classpath:CustomLogstashJsonEventLayoutV1.json # 配置默认值(可选,也可以直接写在模板里) appender.APP_CONSOLE.layout.defaultSeverity = MEDIUM appender.APP_CONSOLE.layout.defaultErrCode = ERR_DEFAULT appender.APP_CONSOLE.layout.eventTemplateAdditionalField[0].type = EventTemplateAdditionalField appender.APP_CONSOLE.layout.eventTemplateAdditionalField[0].key = aNumber appender.APP_CONSOLE.layout.eventTemplateAdditionalField[0].value = 1 appender.APP_CONSOLE.layout.eventTemplateAdditionalField[0].format = JSON loggers = app logger.app.name = com.vajira.test logger.app.level = DEBUG logger.app.additivity = false logger.app.appenderRef.console.ref = APP_CONSOLE rootLogger.level = ERROR rootLogger.appenderRef.APP_CONSOLE.ref = APP_CONSOLE
如果用了配置文件里的默认值,记得把模板里的DEFAULT_SEVERITY和DEFAULT_ERROR_CODE改成${config:defaultSeverity}和${config:defaultErrCode},这样就能读取配置里的默认值了。
3. 修改应用代码,支持传入自定义字段
现在可以在调用log.error时传入自定义的severity和err_code,如果不传就会用默认值。推荐用传入Map的方式,每个日志事件的参数独立,不会污染线程上下文:
package com.vajira.test; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Map; public class Main { static Logger log = LogManager.getLogger(Main.class); public static void main(String[] args) { System.setProperty("log4j.configurationFile","/home/vajira/test_projects/log4j2_test/src/main/resources/log4j2.properties"); log.info("Helllllooooooooooo this is a sample info message"); log.debug("Helllllooooooooooo this is a sample debug message"); // 1. 传入自定义字段的错误日志 log.error("Helllllooooooooooo this is a custom error message", Map.of("severity", "CRITICAL", "err_code", "E001")); // 2. 不传入字段,使用默认值的错误日志 log.error("Helllllooooooooooo this is a sample error message with defaults"); } }
最终效果
运行后,INFO和DEBUG日志不会显示severity和err_code,而ERROR日志会根据是否传入参数显示对应值或默认值:
- 自定义参数的ERROR日志:
{"@version":1,"source_host":"vajira","message":"Helllllooooooooooo this is a custom error message","thread_name":"main","@timestamp":"2022-01-09T20:30:31.592+0530","level":"ERROR","logger_name":"com.vajira.test.Main","aNumber":1, "severity":"CRITICAL", "err_code":"E001"}
- 默认值的ERROR日志:
{"@version":1,"source_host":"vajira","message":"Helllllooooooooooo this is a sample error message with defaults","thread_name":"main","@timestamp":"2022-01-09T20:30:31.593+0530","level":"ERROR","logger_name":"com.vajira.test.Main","aNumber":1, "severity":"MEDIUM", "err_code":"ERR_DEFAULT"}
内容的提问来源于stack exchange,提问作者Vajira Prabuddhaka
相关产品推荐
相关产品推荐

