如何使用log4j2

时间:2016-06-01 18:23:12

标签: java logging log4j2

我的团队正在开发一个NetBeans插件,它使用日志记录到指定文件。日志系统使用SLF4J + Log4J2;我所知道的唯一配置信息是log4j2.xml文件,其中包含插件的日志记录属性,以及以下内容:

    LoggerContext loggerContext = (LoggerContext)LogManager.getContext(false);
    loggerContext.reconfigure();

(我使用SLF4J和NetBeans这一事实并不重要。)

我的问题是,当插件启动时开始记录的正确方法是什么,并在插件退出时停止记录? (JVM继续使用NetBeans,因此日志文件不会自动关闭。)

我查了LoggerContext并看到stop()terminate()方法,但我找不到应用程序如何使用LoggerContext的任何文档,所以我不知道这个LifeCycle内容是内部细节还是应用程序应该使用的内容。

更具体的细节:

我们的插件生命周期类似于下图(一次只允许一个实例运行)。 " A"和" B"请参阅我们希望生效的日志配置。

     [Something starts within the JVM to load log4j classes first.
      It might be our plugin, it might be something else.
A     log4j's default mechanism kicks in to create log configuration A]
|
|    [time passes]
|
|    [our plugin starts]
A    [log4j classes first loaded, 
|    default mechanism kicks in to create log configuration A]
A    setup log configuration B
A B  log event 1
A B  log event 2
A B  log event 3
A    shutdown log configuration B
|    [our plugin exits]
|
|    [time passes]
|
|    [our plugin starts]
A    setup log configuration B
A B  log event 1
A B  log event 2
A B  log event 3
A    shutdown log configuration B
|    [our plugin exits]
|
|    [time passes]
|
     [JVM exits]

配置A与JVM关联,是第一次由JVM加载时由log4j创建的默认配置。

配置B由插件以编程方式进行管理,并且应该具有独立于配置A的显式启动/关闭(并且配置A不应受到影响)。

有没有办法用log4j 2.0实现这个目标?

2 个答案:

答案 0 :(得分:2)

在Log4j 2.5中,您可以调用Configurator.shutdown()。使用Log4j 2.6,您可以调用LogManager.shutdown()。

答案 1 :(得分:2)

您可以安全地为应用程序的不同组件使用单独的LoggerContext

terminate()stop()完全相同。实际上,前者只是称后者而不做其他事情。 terminate()LoggerContext自己的api的一部分,而stop()是更广泛的LifeCycle界面的一部分。

如果要正确实现日志记录上下文的分离,请使用上下文选择器的机制。 Lo4j2为负责选择ContextSelector将返回的上下文的类提供接口LogManager.getContext()。开箱即用的几种实现方式:

  • BasicContextSelector根据当前主题选择上下文。
  • BundleContextSelector用于在OSGI环境中使用。
  • JndiContextSelector用于单个servlet容器中的多个Web应用程序。
  • ClassLoaderContextSelector根据调用者的类加载器选择上下文。

要指定您要使用的选择器,请设置Log4jContextSelector Java选项。

例如,如果您的插件在不同的线程中运行,则可以选择BasicContextSelector

-DLog4jContextSelector=org.apache.logging.log4j.core.selector.BasicContextSelector

以这种方式为你的插件使用单独的LoggerContext(此代码必须在插件的线程中运行):

// Create a separate context for the plugin
LoggerContext pluginContext = new LoggerContext("PluginContext");

// Setup pluginContext...

// BasicContextSelector uses ContextAnchor.THREAD_CONTEXT
// to bind contexts to threads:
ContextAnchor.THREAD_CONTEXT.set(pluginContext);

// Your plugin works and has access to your logging context
LogManager.getContext(false); // Returns pluginContext

// Stop and remove the plugin's logging context
pluginContext.stop();
ContextAnchor.THREAD_CONTEXT.set(null);

根据插件的体系结构,您可以使用其中一个实现或提供自己的实现,这很简单,您只需要实现以下方法:

  • getContext()根据提供给LogManager.getContext(...)的参数创建新的上下文(或返回现有的上下文)。
  • getLoggerContexts()返回可用上下文的集合(之前创建的上下文)。
  • removeContext()在停止(终止)时从内存中删除上下文。