我对 log4j2 和路由附加程序有一些问题。
我的应用程序生成不同的线程,并且在每个线程中我都会执行类似的操作
ThreadContext.put("threadName", processName);
和processName会根据不同的信息在线程内生成。但这并不重要,唯一重要的信息是,processName在每个线程中都会不同。
现在我有了这个 log4j2.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
</Console>
<Routing name="RoutingAppender">
<Routes pattern="${ctx:threadName}">
<Route>
<RollingFile name="Rolling-${ctx:threadName}"
fileName="../log/${ctx:threadName}.log"
filePattern="../log/${ctx:threadName}-%d{yyyy-MM-dd}.log"
createOnDemand="true">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Logger name="de.company" level="INFO" additivity="false">
<AppenderRef ref="RoutingAppender"/>
<AppenderRef ref="console"/>
</Logger>
<Logger name="com.company" level="INFO" additivity="false">
<AppenderRef ref="RoutingAppender"/>
<AppenderRef ref="console"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="RoutingAppender"/>
<AppenderRef ref="console"/>
</Root>
</Loggers>
</Configuration>
log4j 为每个线程创建日志文件,没有任何问题。
不幸的是,log4j 将创建一个名为 ${ctx:threadName}.log 的日志文件。在此日志文件中,将显示来自 JSCH 的日志消息。我猜 JSCH 将创建自己的线程,并且由于 JSCH 不会将 ThredName 放入 ThreadContext,log4j 无法替换该变量并使用配置中的变量作为日志文件名称。
我的目标是将 ThreadContext 中没有线程名的所有日志文件写入单个日志文件。
我在 log4j 的文档中找到了这个链接
https://logging.apache.org/log4j/log4j-2.2/faq.html#separate_log_files
但问题是,在该示例中他们知道 threadName 的值是什么。就我而言,我不知道其价值。
ChatGPT 告诉我,我必须更改元素内的 pattern 并使用像这样的双 $
<Routes pattern="$${ctx:threadName}">
我可以像这样添加第二个元素
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route key="$${ctx:threadName}">
<RollingFile name="Rolling-${ctx:threadName}"
fileName="../log/${ctx:threadName}.log"
filePattern="../log/${ctx:threadName}.log-%d{yyyy-MM-dd}"
createOnDemand="true">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
</RollingFile>
</Route>
<Route key="null">
<RollingFile name="Rolling-service"
fileName="../log/default-service.log"
filePattern="../log/default-service.log-%d{yyyy-MM-dd}"
createOnDemand="true">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
但这不起作用 - 我猜 log4j 将 null 解释为字符串。第二种方法是像这样从后备路线中删除关键属性
<Routes pattern="$${ctx:threadName}">
<Route key="$${ctx:threadName}">
<RollingFile name="Rolling-${ctx:threadName}"
fileName="../log/${ctx:threadName}.log"
filePattern="../log/${ctx:threadName}.log-%d{yyyy-MM-dd}"
createOnDemand="true">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
</RollingFile>
</Route>
<Route>
<RollingFile name="Rolling-service"
fileName="../log/default-service.log"
filePattern="../log/default-service.log-%d{yyyy-MM-dd}"
createOnDemand="true">
<PatternLayout pattern="%d{ABSOLUTE} %-5p [%-40.-40c{1}] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
</Policies>
</RollingFile>
</Route>
</Routes>
但在这种情况下,所有日志消息都将存储在default-service.log中。
有人知道在这种情况下该怎么办吗?
非常问候并感谢您的帮助!
路由附加器很棘手,因为除了
<Route>
的内容之外的所有内容都是在编译时插入的,而如果选择该路由,则将评估<Route>
的内容。因此,如果您有:
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route key="$${ctx:threadName}">
<!-- Content 1 -->
</Route>
<Route>
<!-- Content 2 -->
</Route>
</Routes>
</Routing>
它将在配置时进行插值以获得:
<Routing name="RoutingAppender">
<Routes pattern="${ctx:threadName}">
<Route key="${ctx:threadName}">
<!-- Content 1 unchanged -->
</Route>
<Route>
<!-- Content 2 unchanged -->
</Route>
</Routes>
</Routing>
在运行时,模式
${ctx:threadName}
将被插值并与非插值键进行匹配。因此:
ThreadContext.get("threadName")
是 null
,则表达式 ${ctx:threadName}
将计算为自身 ${ctx:threadName}
并匹配 第一个(不是第二个)路线的键,ThreadContext.get("threadName")
是不是null
,则不会匹配任何键,并且将选择第二个(默认)路由。您可以:
${ctx:threadName}
添加默认值并仅使用单个默认路由:<Properties>
<Property name="threadName" value="default-service"/>
</Properties>
<Appenders>
<Routing name="RoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route>
<RollingFile name="Rolling-${ctx:threadName}"
fileName="../log/${ctx:threadName}.log"
filePattern="../log/${ctx:threadName}.log-%d{yyyy-MM-dd}"
createOnDemand="true">
...
</RollingFile>
</Route>
</Routes>
</Routing>
</Appenders>