我们的应用程序使用 log4j 来控制日志记录行为。它通过 log4 配置 xml 文件(下面的完整配置)的
Field
部分中的 Configuration.Appenders.RollingFile.StructuredLayout
元素指定日志行的格式。
问题:日志格式仅在我们的某些环境中使用,而在其他环境中不使用。
我们像这样将 log4j xml 配置传递给应用程序,每个环境都相同
# command in stage
java -Dlog4j.configurationFile=/opt/ais/config/log4j2.xml -jar myApp.jar
# command in production
java -Dlog4j.configurationFile=/opt/ais/config/log4j2.xml -jar myApp.jar
阶段的日志没有格式。生产中的日志具有我们期望的格式(在 xml 中指定)。
# in stage (no format, not working)
> cat /opt/ais/logs/splunk/myApp/host-0-443.log
test log message
# in prod (format, working as expected)
> cat /opt/ais/logs/splunk/myApp/host-0-443.log
timestamp="2023-05-03 07:13:15,461",level="INFO",thread="pool-2-thread-1",message="test log message",logger="MessageProcessor",appName="myApp",instanceNum="300",dataCenter="MR",partition="MR",buildVersion="1.0.0"
每台主机上都有xml文件,文件路径匹配。那么是什么导致一个环境支持日志格式,而另一个环境不支持?
完整的 log4j 配置 xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="com.apple.jvm.commons.logging.structured">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<StructuredLayout/>
</Console>
<RollingFile name="RollingFile"
fileName="/opt/ais/logs/splunk/${sys:ISApplicationName}/${sys:ISHostId}-${sys:ISInstanceId}-${sys:WOPort}.log"
filePattern="/opt/ais/logs/${sys:ISApplicationName}/${sys:ISHostId}-${sys:ISInstanceId}-${sys:WOPort}.%i.log">
<StructuredLayout serializer="com.mycompany.jvm.commons.logging.structured.kv.KeyValueSerializer" fieldSeparator="," timeZoneId="America/Los_Angeles">
<Field name="timestamp" pattern="%date{yyyy-MM-dd HH:mm:ss,SSS}{America/Los_Angeles}"/>
<Basic exclude="timestamp"/>
<Throwable name="exception"/>
<Field name="appName" value="${sys:ISApplicationName}"/>
<Field name="instanceNum" value="${sys:ISInstanceId}"/>
<Field name="dataCenter" value="${sys:ISDataCenter}"/>
<Field name="partition" value="${sys:partition}"/>
<Field name="buildVersion" value="${sys:build.version}"/>
</StructuredLayout>
<Policies>
<SizeBasedTriggeringPolicy size="500 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="RollingFile"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
问题是 StructuredLayout
com.mycompany.jvm.commons.logging.structured.kv.KeyValueSerializer
中的序列化程序在依赖图中不可用。我们的生产构建正在运行,但在最后一个生产构建和当前构建的暂存之间的某个时间,该依赖性被删除了。谁知道为什么,但这可能是因为我们“幸运”并通过传递依赖获得了依赖,但这不再是真的。
修复是向 gradle 添加运行时依赖项,以包含缺少的
KeyValueSerializer
类型。
runtimeOnly("com.mycompany.jvm.commons.commons-logging:structured-layout-log4j2:1.11.1")
注意这个依赖是我们自己的内部神器,YMMV