我的团队正在开发一个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实现这个目标?
答案 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()
在停止(终止)时从内存中删除上下文。