如何最好地复制已配置的Log4j Appender

时间:2014-03-07 13:09:07

标签: java log4j

我有一个场景,我希望通过会话ID登录到自定义Log4j Appender。换句话说,我想为一个包设置一个记录器(例如com.foo.bar),然后附加自定义Appender。只有当请求带有相同的会话ID时,我才会记录要为与会话ID匹配的Appender编写的消息。当我打开日志记录时,我们必须动态添加Appender并将其名称设置为会话ID。我想要做的是有一个预先配置的Appender,我从log4j.xml文件中获取并复制它,并将名称设置为会话ID,然后将其添加到我的新记录器中。为了从配置文件中提取appender,我发现能够做到这一点的唯一方法是将一个appender附加到一个虚拟记录器(在这种情况下是support_logger)

<appender name="console" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%-5p: %c - %m%n" />
    </layout>
</appender>

<logger name="support_logger">
    <level value="debug" />
    <appender-ref ref="console" />
</logger>

通过这样做,我可以通过编码来获取appender:

Appender appender = Logger.getLogger("support_logger").getAppender("console") );

我现在遇到的问题是我需要创建一个新的记录器,基于我感兴趣的一些包,然后将上面的appender及其所有配置添加到新的记录器中,但是将Appender的名称设置为会话ID。

Logger newLogger = Logger.getLogger("com.foo.bar");
appender.setName(req.getSession().getId()); 
newLogger.addAppender(appender)

这种情况在第一次完美发生,但如果我有同一个包的另一个会话ID,那么“console”appender就不再存在了。当我在Appender上设置名称时,我覆盖了控制台配置,似乎无法将其恢复,因为记录器已经初始化。

所以我的问题是这个。我正在寻找一种简单的方法将“console”appender克隆到另一个appender并使用会话ID设置名称并保持原始的“console”记录器配置,以便我可以在后续请求中访问它。

我编写了一个Appender克隆方法,但我不确定是否有更好的方法可以使用Log4j API。

1 个答案:

答案 0 :(得分:0)

克隆对象或更改引用的对象

是的,你没有克隆appender,你用以下行重命名它:

appender.setName(req.getSession().getId()); 

在执行此操作之前,您需要创建一个深层副本。否则,您只需将现有的appender“console”重命名为“id”。如果您需要知道如何创建深层副本,here is an efficient way

创建appender的深层副本后,可以使用setName重命名它并将其用作appender。

详细信息

您声称,新记录器是您的问题:

  

我现在遇到的问题是我需要创建一个新的记录器,

这不是真的,因为创建新的记录器是......无论如何,你要为每个班级或每个类别做。但通常,现有的log4j配置将根据包或名称决定哪个appender将适用。但是每个会话需要一个文件,因此需要一个新的appender(它自己的Name AND 文件)。

所以你真正需要做的就是这样(伪代码):

Logger newLogger = Logger.getLogger("com.foo.bar");
FileAppender fa = null;
Appender appender = Logger.getLogger("support_logger").getAppender("console") );
try {
    fa = (FileAppender) fa;
} catch (...) {
    // TODO: put sth here
}
FileAppender sessionfileappender = AppenderUtils.deepcopy(fa);
sessionfileappender.setName(req.getSession().getId());
sessionfileappender.setFile("session-" + req.getSession().getId());
newLogger.addAppender(sessionfileappender)

所以实际上,您需要对方法FileAppender AppenderUtils.deepcopy(FileAppender fa)进行编码。

创建新的appender更容易

事实上,创建new FileAppender(Layout layout, String filename)可能更容易,请参阅constructor javadoc。新的Pseudocode将是这样的:

Logger newLogger = Logger.getLogger("com.foo.bar");
FileAppender fa = new FileAppender(
    Logger.getLogger("support_logger").getAppender("console").getLayout(),
    "session-" + req.getSession().getId());
newLogger.addAppender(fa);

更短,嗯?请记住,如果您更改布局(既未克隆,也只是对现有布局的新引用),您将动态更改所有布局。因此,如果您需要新的布局,请创建一个新布局。