临时提高多线程服务中的log4j2记录器级别

时间:2019-08-28 15:31:08

标签: java multithreading log4j2

这对您的Log4j2大师来说是一个很长的问题。

我有一项服务:

  1. 有非常严格的性能要求
  2. 使用log4j2进行了许多日志记录调用。

典型呼叫被门控,例如:

if ( LOG.isInfoEnabled() ) {
  LOG.info("everything's fine"); 
}

由于日志消息的数量和性能需求,该服务通常在日志记录设置为WARN的情况下运行(即,消息不多)。

但是,有人要求我在服务调用中建立一个参数,如果给出该参数,它将导致它:

  1. 暂时将日志记录级别提高到参数中要求的级别(例如INFO或TRACE)
  2. 添加一个WriterAppender来捕获PrintWriter中的日志记录。
  3. PrintWriter日志数据追加到请求响应。

由于我对每个日志记录调用的门控,似乎很明显,我实际上需要暂时提高日志记录级别,如下所示:

LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration cfg = ctx.getConfiguration();
LoggerConfig loggerCfg = cfg.getLoggerConfig("com.mycompany.scm");
loggerCfg.setLevel(logLevel);
.. other code to add `WriterAppender` ...
ctx.updateLoggers();

但是我对此有一个直接的问题,因为它导致日志记录也必须转到服务的日志文件。那可能不是世界的尽头,但如果可能的话,我想避免这种情况。

我这样做是通过让默认日志记录通过按级别过滤的附加程序来完成的,因此即使打开了日志记录,它也不会写入比默认日志文件所需的消息更详细的消息。 (例如,通过我的.properties文件):

appenders=scm_warn, scm_info 

appender.scm_warn.type = Console
appender.scm_warn.name = SCM_WARN
appender.scm_warn.layout.type = PatternLayout
appender.scm_warn.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
appender.scm_warn.filter.threshold.type = ThresholdFilter
appender.scm_warn.filter.threshold.level = warn

appender.scm_info.type = Console
appender.scm_info.name = SCM_INFO
appender.scm_info.layout.type = PatternLayout
appender.scm_info.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
appender.scm_info.filter.threshold.type = ThresholdFilter
appender.scm_info.filter.threshold.level = info

loggers = coreConfigurator

logger.coreConfigurator.name = com.mycompany.scm
logger.coreConfigurator.level = warn
logger.coreConfigurator.additivity = false   # do not let configurator log messages get processed by client application's parent or root logger.
logger.coreConfigurator.appenderRefs = core
logger.coreConfigurator.appenderRef.core.ref = SCM_WARN

...这样,即使日志记录级别得到提高,多余的消息也不会进入主日志文件(我只希望它们进入我的PrintWriter)。

现在是问题!

如何仅针对当前线程临时增加日志级别(就像我在上面的代码中尝试的那样)?

如果同时有三(3)个服务呼叫,我...

  1. ...希望每个添加的Appender只写由创建Appender的线程生成的日志消息。
  2. ...希望添加的每个Appender在添加请求完成后都被删除。
  3. ...只要没有其他请求在启用此日志记录参数的情况下仍在运行,就希望将日志记录级别恢复为原来的状态。

理想情况下,我认为这听起来像我希望每个线程都具有一个完全独立的日志记录上下文。那可能吗?对如何执行所有这些操作有任何想法吗?

2 个答案:

答案 0 :(得分:1)

您可能会使用自定义Context Selector来使每个线程具有不同的上下文,但是当多个线程想要写入同一日志文件时,这可能会引起问题,因此可能不可行。

另一种方法是编写一个自定义Appender,该自定义ThreadLocal用于存储StringWriter。如果尚未为该线程建立StringWriter,则附件将跳过日志记录。此自定义Appender应该添加到Log4J配置文件中,因此它始终存在并接收日志条目。

通过创建StringWriter并将其分配给ThreadLocal,运行代码,然后清除ThreadLocal并从{获取记录的信息,可以启用对特定线程的记录。 {1}}。由于任何线程最初都没有StringWriter,所以附加程序不会执行任何操作,因此不应以任何明显的方式影响性能。

您仍然必须使用其他附加程序上的过滤器来进行已经进行的级别升级。

答案 1 :(得分:0)

您可以:

  • 访问类记录器并更改日志级别(根据您的建议): LogManager.getLogger(Class.forName("your.class.package")).setLevel(Level.FATAL);

  • 使用其他记录器;只需配置两个不同的记录器。