On this page
Programmatic Configuration
Log4j 2 为应用程序提供了几种创建自己的程序化配置的方法:
指定一个自定义 ConfigurationFactory 以使用编程配置启动 Log4j
Log4j 启动后,使用配置器替换配置
结合使用配置文件和编程配置来初始化 Log4j
初始化后修改当前配置
ConfigurationBuilder API
从版本 2.4 开始,Log4j 提供了 ConfigurationBuilder 和一组组件构建器,使构建配置变得相当容易。诸如 LoggerConfig 或 Appender 之类的实际配置对象可能很笨拙。他们需要有关 Log4j 内部的大量知识,这使得如果您想要创建配置就很难使用它们。
新的 ConfigurationBuilder API(在 org.apache.logging.log4j.core.config.builder.api 包中)允许用户通过构造组件定义以代码创建 Configurations。无需直接使用实际的配置对象。组件定义已添加到 ConfigurationBuilder,一旦收集了所有定义,便会构造所有实际的配置对象(如 Loggers 和 Appenders)。
ConfigurationBuilder 具有可配置的基本组件的便捷方法,例如 Loggers,Appenders,Filter,Properties 等。但是,Log4j 2 的插件机制意味着用户可以创建任意数量的自定义组件。作为权衡,ConfigurationBuilder API 仅提供有限数量的“强类型”便捷方法,例如 newLogger(),newLayout()等。如果组件不存在便捷方法,则可以使用通用 builder.newComponent()方法。您要配置。
例如,构建器不知道可以在 RollingFileAppender 与 RoutingAppender 之类的特定组件上配置哪些子组件。要在 RollingFileAppender 上指定触发策略,可以使用 builder.newComponent()。
以下各节中提供了使用 ConfigurationBuilder API 的示例。
Understanding ConfigurationFactory
在初始化期间,Log4j 2 将搜索可用的ConfigurationFactories,然后选择要使用的那个。所选的 ConfigurationFactory 创建 Log4j 将使用的配置。 Log4j 如何找到可用的 ConfigurationFactories:
可以使用要使用的 ConfigurationFactory 的名称来设置名为 log4j2.configurationFactory 的系统属性。
可以使用要使用的 ConfigurationFactory 实例调用 ConfigurationFactory.setConfigurationFactory(ConfigurationFactory)。必须在调用 Log4j 之前调用它。
可以将 ConfigurationFactory 实现添加到 Classpath 中,并配置为“ ConfigurationFactory”类别中的插件。找到多个适用的 ConfigurationFactories 时,可以使用 Order 注解指定相对优先级。
ConfigurationFactories 具有“支持的类型”的概念,该概念基本上 Map 到 ConfigurationFactory 可以处理的配置文件的文件 extensions。如果指定了配置文件位置,则不会使用其支持的类型不包括“ *”或匹配文件 extensions 的 ConfigurationFactories。
使用 ConfigurationBuilder 和自定义 ConfigurationFactory 初始化 Log4j
以编程方式配置 Log4j 2 的一种方法是创建一个自定义 ConfigurationFactory,该工厂使用ConfigurationBuilder来创建 Configuration。下面的示例重写 getConfiguration()方法以返回由 ConfigurationBuilder 创建的 Configuration。创建 LoggerContext 时,这将导致 Configuration 自动挂接到 Log4j。在下面的示例中,由于它指定了受支持的类型“ *”,因此它将覆盖提供的所有配置文件。
@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomConfigurationFactory extends ConfigurationFactory {
static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
builder.setConfigurationName(name);
builder.setStatusLevel(Level.ERROR);
builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL).
addAttribute("level", Level.DEBUG));
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").
addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout").
addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
builder.add(appenderBuilder);
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
add(builder.newAppenderRef("Stdout")).
addAttribute("additivity", false));
builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
return builder.build();
}
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
return getConfiguration(loggerContext, source.toString(), null);
}
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
return createConfiguration(name, builder);
}
@Override
protected String[] getSupportedTypes() {
return new String[] {"*"};
}
}
从 2.7 版本开始,ConfigurationFactory.getConfiguration()方法采用一个附加的 LoggerContext 参数。
使用 ConfigurationBuilder 和 Configurator 重新配置 Log4j
自定义 ConfigurationFactory 的替代方法是使用 Configurator 进行配置。构造 Configuration 对象后,可以将其传递到 Configurator.initialize 方法之一以设置 Log4j 配置。
以这种方式使用配置器允许应用程序控制 Log4j 的初始化时间。但是,如果在调用 Configurator.initialize()之前尝试进行任何日志记录,则默认配置将用于这些日志事件。
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(Level.ERROR);
builder.setConfigurationName("BuilderTest");
builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
.addAttribute("level", Level.DEBUG));
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL)
.addAttribute("marker", "FLOW"));
builder.add(appenderBuilder);
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG)
.add(builder.newAppenderRef("Stdout")).addAttribute("additivity", false));
builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
ctx = Configurator.initialize(builder.build());
本示例说明如何创建包含 RollingFileAppender 的配置。
ConfigurationBuilder< BuiltConfiguration > builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel( Level.ERROR);
builder.setConfigurationName("RollingBuilder");
// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
builder.add( appenderBuilder );
// create a rolling file appender
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%t] %-5level: %msg%n");
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
appenderBuilder = builder.newAppender("rolling", "RollingFile")
.addAttribute("fileName", "target/rolling.log")
.addAttribute("filePattern", "target/archive/rolling-%d{MM-dd-yy}.log.gz")
.add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(appenderBuilder);
// create the new logger
builder.add( builder.newLogger( "TestLogger", Level.DEBUG )
.add( builder.newAppenderRef( "rolling" ) )
.addAttribute( "additivity", false ) );
builder.add( builder.newRootLogger( Level.DEBUG )
.add( builder.newAppenderRef( "rolling" ) ) );
LoggerContext ctx = Configurator.initialize(builder.build());
通过将配置文件与程序配置相结合来初始化 Log4j
有时您想使用配置文件进行配置,但需要进行一些其他的编程配置。一个可能的用例是,您希望允许使用 XML 进行灵活的配置,但同时请确保始终存在一些无法删除的配置元素。
实现此目的的最简单方法是扩展标准配置类之一(XMLConfiguration,JSONConfiguration),然后为扩展的类创建新的 ConfigurationFactory。标准配置完成后,可以将自定义配置添加到其中。
下面的示例显示了如何扩展 XMLConfiguration 以手动向配置添加 Appender 和 LoggerConfig。
@Plugin(name = "MyXMLConfigurationFactory", category = "ConfigurationFactory")
@Order(10)
public class MyXMLConfigurationFactory extends ConfigurationFactory {
/**
* Valid file extensions for XML files.
*/
public static final String[] SUFFIXES = new String[] {".xml", "*"};
/**
* Return the Configuration.
* @param source The InputSource.
* @return The Configuration.
*/
public Configuration getConfiguration(InputSource source) {
return new MyXMLConfiguration(source, configFile);
}
/**
* Returns the file suffixes for XML files.
* @return An array of File extensions.
*/
public String[] getSupportedTypes() {
return SUFFIXES;
}
}
public class MyXMLConfiguration extends XMLConfiguration {
public MyXMLConfiguration(final ConfigurationFactory.ConfigurationSource configSource) {
super(configSource);
}
@Override
protected void doConfigure() {
super.doConfigure();
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Layout layout = PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, config, null,
null,null, null);
final Appender appender = FileAppender.createAppender("target/test.log", "false", "false", "File", "true",
"false", "false", "4000", layout, null, "false", null, config);
appender.start();
addAppender(appender);
LoggerConfig loggerConfig = LoggerConfig.createLogger("false", "info", "org.apache.logging.log4j",
"true", refs, null, config, null );
loggerConfig.addAppender(appender, null, null);
addLogger("org.apache.logging.log4j", loggerConfig);
}
}
初始化后以编程方式修改当前配置
应用程序有时需要与实际配置分开自定义日志记录。 Log4j 尽管存在一些限制,但允许这样做:
如果更改了配置文件,则将重新加载配置,并且手动更改将丢失。
修改运行中的配置需要同步所有被调用的方法(addAppender 和 addLogger)。
因此,建议的自定义配置方法是扩展标准配置类之一,覆盖设置方法以首先执行 super.setup(),然后在将配置注册到应用程序之前将自定义的 Appenders,Filters 和 LoggerConfigs 添加到配置中用。
以下示例将一个 Appender 和一个使用该 Appender 的新 LoggerConfig 添加到当前配置中。
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
Layout layout = PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, config, null,
null,null, null);
Appender appender = FileAppender.createAppender("target/test.log", "false", "false", "File", "true",
"false", "false", "4000", layout, null, "false", null, config);
appender.start();
config.addAppender(appender);
AppenderRef ref = AppenderRef.createAppenderRef("File", null, null);
AppenderRef[] refs = new AppenderRef[] {ref};
LoggerConfig loggerConfig = LoggerConfig.createLogger("false", "info", "org.apache.logging.log4j",
"true", refs, null, config, null );
loggerConfig.addAppender(appender, null, null);
config.addLogger("org.apache.logging.log4j", loggerConfig);
ctx.updateLoggers();
}
以编程方式将日志事件附加到编写器和 OutputStreams
Log4j 2.5 提供了将日志事件追加到 Writers 和 OutputStreams 的工具。例如,这为在内部使用 Log4j 且仍要支持 JDBC API 的 JDBC 驱动程序实现者提供了简单的集成。 PrintStream)。
给定任何 Writer(例如 PrintWriter),您可以通过创建 WriterAppender 并更新 Log4j 配置,告诉 Log4j 将事件追加到该 Writer:
void addAppender(final Writer writer, final String writerName) {
final LoggerContext context = LoggerContext.getContext(false);
final Configuration config = context.getConfiguration();
final PatternLayout layout = PatternLayout.createDefaultLayout(config);
final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true);
appender.start();
config.addAppender(appender);
updateLoggers(appender, config);
}
private void updateLoggers(final Appender appender, final Configuration config) {
final Level level = null;
final Filter filter = null;
for (final LoggerConfig loggerConfig : config.getLoggers().values()) {
loggerConfig.addAppender(appender, level, filter);
}
config.getRootLogger().addAppender(appender, level, filter);
}
您可以使用 OutputStream 达到相同的效果,例如 PrintStream:
void addAppender(final OutputStream outputStream, final String outputStreamName) {
final LoggerContext context = LoggerContext.getContext(false);
final Configuration config = context.getConfiguration();
final PatternLayout layout = PatternLayout.createDefaultLayout(config);
final Appender appender = OutputStreamAppender.createAppender(layout, null, outputStream, outputStreamName, false, true);
appender.start();
config.addAppender(appender);
updateLoggers(appender, config);
}
区别在于使用 OutputStreamAppender 而不是 WriterAppender。