背景
公司需要将服务迁移到K8S环境上,由于目前服务输出的格式不符合ES进行采集的日志格式,所有需要将日志输出的格式进行调整为JSON格式,方便ES采集
遇到的坑
之前是直接配置的输出格式的message为"message": %msg"
,但是由于打日志需要打印json内容的日志就没有进行转义导致,整体输出的json格式出错,es采集日志就出问题了
解决方法:调整为"message": %enc{%m}{JSON}"
则支持json内容输出
参考官方文档:https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout
解决方案-正确姿势
log4j log4j2.xml配置示例
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="OFF">
<properties>
<property name="log.pattern">
{"code":"%X{code}", "time":"%d{MM-dd HH:mm:ss.SSS}", "level":"%level", "method":"%X{method}", "header.client-ip":"%X{header.client-ip}", "header.content-length":"%X{header.content-length}", "thread":"%thread", "class":"%logger{35}:%L", "message": %enc{%m}{JSON}", "stack_trace":"%exception{10}"}\n
</property>
</properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${log.pattern}"/>
</Console>
<RollingRandomAccessFile name="fileLog"
fileName="/home/logs/demo.log"
filePattern="/home/logs/demo.%d{yyyyMMddHH}.log.gz">
<PatternLayout pattern="${log.pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1"/>
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="data" maxDepth="1">
<IfFileName glob="*.log.gz"/>
<IfLastModified age="2d"/>
</Delete>
<Delete basePath="log" maxDepth="1">
<IfFileName glob="*.log.gz"/>
<IfLastModified age="2d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="console"/>
<AppenderRef ref="fileLog"/>
</Root>
<Logger name="org.springframework.jdbc.core.JdbcTemplate" level="debug"/>
<Logger name="org.springframework.boot.web.embedded" level="info"/>
</Loggers>
</Configuration>
定义输出格式
<Properties>
<property name="log.pattern">
{"code":"%X{code}", "time":"%d{MM-dd HH:mm:ss.SSS}", "level":"%level", "method":"%X{method}", "header.client-ip":"%X{header.client-ip}", "header.content-length":"%X{header.content-length}", "thread":"%thread", "class":"%logger{35}:%L", "message": %enc{%m}{JSON}", "stack_trace":"%exception{10}"}\n
</property>
</Properties>
输出格式测试
public class Demo {
private static final Logger log = LogManager.getLogger();
public static void main(String[] args) {
String name = "xiaoming";
HashMap<String, Object> infoMap = new HashMap<>(3);
infoMap.put("age", 18);
infoMap.put("sex", 1);
infoMap.put("weight", 60);
log.info("输出信息 name:{}, userInfo:{}", name, JSONObject.toJSONString(infoMap));
}
}
输出效果:
{"code":"","time":"07-06 11:50:29.429","level":"INFO ","thread":"main","class":"com.tushu.bt.push.web.Demo:24","message": 输出信息 name:xiaoming, userInfo:{\"weight\":60,\"age\":18,\"sex\":1}","stack_trace":""}
会将之前的json格式进行转义操作
图示
踩坑
如果不用"message": %enc{%m}{JSON}"
进行处理msg内容直接用"message": %msg"`会出现的问题就是,不会将json内容进行转义导致整体输出的json不是一个正常的json
示例调整输出格式:
<Properties>
<property name="log.pattern">
{"code":"%X{code}", "time":"%d{MM-dd HH:mm:ss.SSS}", "level":"%level", "method":"%X{method}", "header.client-ip":"%X{header.client-ip}", "header.content-length":"%X{header.content-length}", "thread":"%thread", "class":"%logger{35}:%L", "message": %msg", "stack_trace":"%exception{10}"}\n
</property>
</Properties>
还是用上面的Demo.java进行输出日志
效果:
{"code":"", "time":"07-06 12:06:53.483", "level":"INFO", "method":"", "header.client-ip":"", "header.content-length":"", "thread":"main", "class":"com.tushu.bt.push.web.Demo:24", "message": 输出信息 name:xiaoming, userInfo:{"weight":60,"age":18,"sex":1}", "stack_trace":""}
没有进行对message
字段进行特殊字符进行转义操作,导致整体输出的json格式出错!