【发布时间】:2014-05-23 09:18:19
【问题描述】:
我正在使用 Log4j 2 中的 Routing 功能在运行时动态创建附加程序。当我知道这些附加程序完成时,我想告诉 Log4j 以便它可以整理相关资源(刷新和关闭文件,释放与这些附加程序相关的内部对象等)。如果不这样做,Log4j 仍然有打开的文件句柄,我无法操作它写入的文件(来自对日志进行后处理和存档的外部进程)。
我如何告诉 Log4j 不会再次使用附加程序?
为了完整起见,我包含了我的 Log4j 配置。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %level{ERROR=!, WARN=?, INFO=-, DEBUG=., TRACE=.} %msg%n"/>
</Console>
<Routing name="MatchLogs">
<Routes pattern="$${ctx:matchID}">
<Route>
<RandomAccessFile name="MatchLog-${ctx:matchID}" fileName="logs/${ctx:matchID}.log">
<PatternLayout pattern="%d{ISO8601} %-5level %-30.30logger{1} %msg%n"/>
</RandomAccessFile>
</Route>
</Routes>
</Routing>
<Async name="AsyncWrapper">
<AppenderRef ref="MatchLogs" level="debug"/>
<AppenderRef ref="Console" level = "info"/>
</Async>
<Routing name="MatchStatsLogs">
<Routes pattern="$${ctx:matchID}">
<Route>
<RandomAccessFile name="MatchStatsLog-${ctx:matchID}" fileName="logs/${ctx:matchID}_stats.log">
<PatternLayout pattern="%msg"/>
</RandomAccessFile>
</Route>
</Routes>
</Routing>
<Async name="AsyncStatsWrapper">
<AppenderRef ref="MatchStatsLogs" level="debug"/>
</Async>
</Appenders>
<Loggers>
<Logger name="stats" level="trace" additivity="false">
<AppenderRef ref="AsyncStatsWrapper"/>
</Logger>
<Root level="debug">
<AppenderRef ref="AsyncWrapper"/>
</Root>
</Loggers>
</Configuration>
当一场比赛开始时,我从参与该比赛的每个线程调用ThreadContext.put("matchID", theMatchID);。比赛结束后,我清除ThreadContext。显然,这还不足以让 Log4j 知道我不会重复使用该匹配 ID,因此它保留了 Appender。但是,我知道我不会重复使用匹配 ID,那么我该如何告诉 Log4j 进行整理呢?
【问题讨论】:
-
很好的问题。出于这个原因,我不得不转向以编程方式创建附加程序,以便在完成后关闭它们。像超时或上下文过期函数这样的东西会很好。