【问题标题】:Log4j - Changing logger level for a particular logger instanceLog4j - 更改特定记录器实例的记录器级别
【发布时间】:2014-09-22 10:13:20
【问题描述】:

我使用 apache log4j 进行应用程序日志记录。当我的应用程序服务器启动时,我使用 log4j.xml 来初始化记录器。对于每个类,我调用 Loggers.getLogger("loggername") 来获取日志实例以记录该类的详细信息。

例如: 在 log4j.xml 中

<appender name="default" class="org.apache.log4j.RollingFileAppender">
                <param name="File" value="${log.dir}/logs/serverout.txt" />
                <param name ="Append" value="TRUE"/>
                <layout class="org.apache.log4j.PatternLayout">
                        <param name="ConversionPattern" value="%d{[HH:mm:ss:SSS]|[MM-dd-yyyy]}|[%c]|[%p]|[%L]: %m|%n"/>
                </layout>
                <param name="MaxFileSize" value="10MB"/>
                <param name="MaxBackupIndex" value="100"/>
</appender>
<logger name="com.mypackage" additivity="false">
                <level value="INFO"/>
                <appender-ref ref="default"/>
</logger>

以及我如何在每个类中调用

private static Logger logger = Logger.getLogger(MPMyclass.class.getName());

我的要求: 基本上,当有很多用户会话时,我会运行一个应用程序服务器。每个会话都有一个唯一的 sessionId。每个会话都是几个类的实例。每个类都有自己的 Logger 实例。如果我想为特定类(MPMyclass)启用日志级别。我可以获取记录器名称(com.mypackage)并设置其级别,以便它更改整体级别。但我希望它以某种方式设置,以便我只能设置到特定会话而不是整体。 如果我有一个类名 MPMyclass ,有很多 MPMyclass 实例,我的要求是更改该类实例的记录器级别,而不是所有实例。

可能的解决方案: 1. 每个会话/实例都有一个唯一的 sessionId。所以我可以获取/设置级别。但这太复杂了,因为有很多类很难设置/获取。 2.我可以有一个Hashtable来存储每个类的实例及其unqiue sessionid,但也不建议这样做,因为类和类的实例太多,这不是一个好的解决方案。

我正在努力在 log4j 的帮助下或通过 Java 设计通过简单的解决方案来解决这个问题。如果有什么我可以做的,请建议我。

谢谢

【问题讨论】:

    标签: java logging log4j


    【解决方案1】:

    我建议你编写一个自定义的 RollingFileAppender(或任何其他 Appender)来控制这个东西,并将它与 MDC 和 JMX 结合起来。

    它应该看起来像这样:

    public class MyRollingFileAppender extends RollingFileAppender implements MyRollingFileAppenderMBean {
    
        private final Set<String> enabledSessions = new HashSet<>();
    
        @Override
        public synchronized void doAppend(LoggingEvent event) {
            if (enabledSessions.contains(event.getMDC("sessionId"))) {
                super.doAppend(event);
            }
        }
    
        @Override
        public synchronized void enable(String... sessionIds) throws JMException {
            for (String sessionId : sessionIds) {
                enabledSessions.add(sessionId);
            }
        }
    
        @Override
        public synchronized void disable(String... sessionIds) throws JMException {
            // do the opposite here...
        }
    
    }
    

    点击此链接了解 MDC:https://blog.oio.de/2010/11/09/logging-additional-information-like-sessionid-in-every-log4j-message/

    【讨论】:

    • 您可以使用装饰器模式将此行为添加到任何附加程序,而不是扩展特定的附加程序。另请注意,这个简单的示例不允许更改日志级别,而只能打开/关闭日志记录。
    • @Pino 您可以设置 Appender 的 Threshold 属性,而不是更改 logger 级别。在这里会产生同样的效果。是的,在这里创建一个装饰器将是一个更通用的解决方案。
    • @shlomi333 是的,我知道阈值属性,但您没有在示例中使用它。但是,即使更改此属性,您也无法根据要求控制每个类的日志记录(尽管它可能足以满足实际需求)。
    • @Pino 我同意它不能满足“逐字”的需要,但我希望答案足以满足 OP 的目的
    • 感谢您的建议。因此,正如您所建议的,我为每个记录器实例添加了一个条目,并且在设置级别时我需要检查 MDC 值(在我的情况下为 sessionid)并相应地设置级别?除了最终它似乎是一个内部(在 log4j 中)映射 MDC 的 Hashtable 条目。
    【解决方案2】:

    如果您的最终目标是轻松找到特定会话(或特定用户)的日志条目,您可以自动将会话 ID(或用户 ID 甚至自定义事务 ID)添加到每个日志条目。这可以使用Nested Diagnostic Context 或Mapped Diagnostic Context 来完成。 Google 可以为您提供许多使用示例。

    如果您真的想更改特定会话使用的特定类实例的日志级别,我认为这不是一个好主意。

    【讨论】:

    • 感谢您的建议。将检查 MDC。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 1970-01-01
    相关资源
    最近更新 更多