«1. Введение
В этом руководстве мы рассмотрим различные способы программной настройки Apache Log4j 2.
2. Первоначальная настройка
Чтобы начать использовать Log4j 2, нам просто нужно включить log4j- core и log4j-slf4j-impl в нашем pom.xml:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.0</version>
</dependency>
3. ConfigurationBuilder
После того, как мы настроили Maven, нам нужно создать ConfigurationBuilder, который является классом, который позволяет нам настраивать приложения, фильтры, макеты и регистраторы.
Log4j 2 предоставляет несколько способов получить ConfigurationBuilder.
Начнем с самого прямого пути:
ConfigurationBuilder<BuiltConfiguration> builder
= ConfigurationBuilderFactory.newConfigurationBuilder();
И чтобы начать настройку компонентов, ConfigurationBuilder оснащен соответствующим новым методом, таким как newAppender или newLayout, для каждого компонента.
Некоторые компоненты имеют разные подтипы, такие как FileAppender или ConsoleAppender, и в API они называются подключаемыми модулями.
3.1. Настройка аппендеров
Давайте сообщим сборщику, куда отправлять каждую строку журнала, настроив аппендер:
AppenderComponentBuilder console
= builder.newAppender("stdout", "Console");
builder.add(console);
AppenderComponentBuilder file
= builder.newAppender("log", "File");
file.addAttribute("fileName", "target/logging.log");
builder.add(file);
Хотя большинство новых методов не поддерживают это, newAppender(name, plugin) позволяет нам дать аппендеру имя , что в дальнейшем окажется важным. Эти приложения мы назвали stdout и log, хотя могли бы назвать их как угодно.
Мы также сообщили сборщику, какой подключаемый модуль приложения (или, проще говоря, какой тип приложения) использовать. Console и File относятся к приложениям Log4j 2 для записи в стандартный вывод и в файловую систему соответственно.
Хотя Log4j 2 поддерживает несколько приложений, их настройка с помощью Java может быть немного сложной, поскольку AppenderComponentBuilder является универсальным классом для всех типов приложений.
Благодаря этому у него есть такие методы, как addAttribute и addComponent вместо setFileName и addTriggeringPolicy:
AppenderComponentBuilder rollingFile
= builder.newAppender("rolling", "RollingFile");
rollingFile.addAttribute("fileName", "rolling.log");
rollingFile.addAttribute("filePattern", "rolling-%d{MM-dd-yy}.log.gz");
builder.add(rollingFile);
И, наконец, не забудьте вызвать builder.add, чтобы добавить его к основной конфигурации!
3.2. Настройка фильтров
Мы можем добавить фильтры к каждому из наших добавлений, которые решают для каждой строки журнала, следует ли ее добавлять или нет.
Давайте воспользуемся подключаемым модулем MarkerFilter в нашем приложении консоли:
FilterComponentBuilder flow = builder.newFilter(
"MarkerFilter",
Filter.Result.ACCEPT,
Filter.Result.DENY);
flow.addAttribute("marker", "FLOW");
console.add(flow);
Обратите внимание, что этот новый метод не позволяет нам назвать фильтр, но он просит нас указать, что делать, если фильтр проходит или не проходит .
В этом случае мы упростили задачу, заявив, что если MarkerFilter проходит успешно, тогда логлайн ПРИНИМАЕТСЯ. В противном случае, ОТРИЦАТЬ его.
Обратите внимание, что в этом случае мы добавляем это не к построителю, а к приложениям, которые мы хотим использовать для этого фильтра.
3.3. Настройка макетов
Далее давайте определим макет для каждой строки журнала. В этом случае мы будем использовать плагин PatternLayout:
LayoutComponentBuilder standard
= builder.newLayout("PatternLayout");
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");
console.add(standard);
file.add(standard);
rolling.add(standard);
Опять же, мы добавили их непосредственно в соответствующие приложения, а не напрямую в конструктор.
3.4. Настройка корневого регистратора
Теперь, когда мы знаем, куда будут отправляться журналы, мы хотим настроить, какие журналы будут отправляться в каждое место назначения.
Корневой регистратор — это самый высокий регистратор, вроде Object в Java. Этот регистратор будет использоваться по умолчанию, если он не будет переопределен.
Итак, давайте используем корневой регистратор, чтобы установить уровень ведения журнала по умолчанию на ERROR и добавление по умолчанию к нашему добавлению stdout сверху: экземпляр застройщика. Вместо этого мы обращаемся к нему по имени, которое мы дали ему ранее.
RootLoggerComponentBuilder rootLogger
= builder.newRootLogger(Level.ERROR);
rootLogger.add(builder.newAppenderRef("stdout"));
builder.add(rootLogger);
3.5. Настройка дополнительных регистраторов
Дочерние регистраторы можно использовать для целевых пакетов или имен регистраторов.
Давайте добавим регистратор для пакета com в наше приложение, установив уровень ведения журнала DEBUG и отправив его в приложение журнала: logger должен наследовать такие свойства, как уровень ведения журнала и типы приложений, от своих предков.
3.6. Настройка других компонентов
LoggerComponentBuilder logger = builder.newLogger("com", Level.DEBUG);
logger.add(builder.newAppenderRef("log"));
logger.addAttribute("additivity", false);
builder.add(logger);
Не все компоненты имеют специальный новый метод в ConfigurationBuilder.
Итак, в этом случае мы вызываем newComponent.
«Например, поскольку TriggeringPolicyComponentBuilder отсутствует, нам нужно использовать newComponent для чего-то вроде определения нашей политики срабатывания для последовательного добавления файлов:
3.7. XML-эквивалент
ConfigurationBuilder оснащен удобным методом для распечатки эквивалентного XML:
ComponentBuilder triggeringPolicies = builder.newComponent("Policies")
.addComponent(builder.newComponent("CronTriggeringPolicy")
.addAttribute("schedule", "0 0 0 * * ?"))
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy")
.addAttribute("size", "100M"));
rolling.addComponent(triggeringPolicies);
Выполнение приведенной выше строки выводит: нашу конфигурацию или если мы хотим сохранить нашу конфигурацию, скажем, в файловой системе.
3.8. Собираем все вместе
builder.writeXmlConfiguration(System.out);
Теперь, когда мы полностью настроены, давайте скажем Log4j 2 использовать нашу конфигурацию:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="stdout">
<PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" />
<MarkerFilter onMatch="ACCEPT" onMisMatch="DENY" marker="FLOW" />
</Console>
<RollingFile name="rolling"
fileName="target/rolling.log"
filePattern="target/archive/rolling-%d{MM-dd-yy}.log.gz">
<PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" />
<Policies>
<CronTriggeringPolicy schedule="0 0 0 * * ?" />
<SizeBasedTriggeringPolicy size="100M" />
</Policies>
</RollingFile>
<File name="FileSystem" fileName="target/logging.log">
<PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" />
</File>
</Appenders>
<Loggers>
<Logger name="com" level="DEBUG" additivity="false">
<AppenderRef ref="log" />
</Logger>
<Root level="ERROR" additivity="true">
<AppenderRef ref="stdout" />
</Root>
</Loggers>
</Configuration>
После того, как это будет вызвано, будущие вызовы Log4j 2 будут использовать нашу конфигурацию.
Обратите внимание, что это означает, что нам нужно вызвать Configurator.initialize, прежде чем мы будем делать какие-либо вызовы LogManager.getLogger.
4. ConfigurationFactory
Configurator.initialize(builder.build());
Теперь, когда мы рассмотрели один способ получения и применения ConfigurationBuilder, давайте рассмотрим еще один:
В этом случае вместо использования ConfigurationBuilderFactory мы создали подкласс ConfigurationFactory , абстрактный класс, предназначенный для создания экземпляров Configuration.
Затем вместо вызова Configurator.initialize, как мы делали в первый раз, нам просто нужно сообщить Log4j 2 о нашей новой фабрике конфигурации.
Есть три способа сделать это:
public class CustomConfigFactory
extends ConfigurationFactory {
public Configuration createConfiguration(
LoggerContext context,
ConfigurationSource src) {
ConfigurationBuilder<BuiltConfiguration> builder = super
.newConfigurationBuilder();
// ... configure appenders, filters, etc.
return builder.build();
}
public String[] getSupportedTypes() {
return new String[] { "*" };
}
}
Статическая инициализация Свойство времени выполнения или аннотация @Plugin
4.1. Использовать статическую инициализацию
Log4j 2 поддерживает вызов setConfigurationFactory во время статической инициализации:
-
Этот подход имеет те же ограничения, что и последний подход, который мы видели, а именно то, что нам нужно будет вызывать его перед любыми вызовами LogManager .getLogger.
4.2. Используйте свойство времени выполнения
Если у нас есть доступ к команде запуска Java, то Log4j 2 также поддерживает указание ConfigurationFactory для использования с помощью параметра -D:
static {
ConfigurationFactory custom = new CustomConfigFactory();
ConfigurationFactory.setConfigurationFactory(custom);
}
Основное преимущество этого подхода заключается в том, что мы не не нужно беспокоиться о порядке инициализации, как мы делаем с первыми двумя подходами.
4.3. Используйте аннотацию @Plugin
И, наконец, в обстоятельствах, когда мы не хотим возиться с командой запуска Java, добавляя -D, мы можем просто аннотировать нашу CustomConfigurationFactory с помощью аннотации Log4j 2 @Plugin:
-Dlog4j2.configurationFactory=com.baeldung.log4j2.CustomConfigFactory
~ ~~ Log4j 2 просканирует путь к классам на наличие классов, имеющих аннотацию @Plugin, и, найдя этот класс в категории ConfigurationFactory, будет использовать его.
4.4. Сочетание со статической конфигурацией
Еще одним преимуществом использования расширения ConfigurationFactory является то, что мы можем легко комбинировать нашу пользовательскую конфигурацию с другими источниками конфигурации, такими как XML:
@Plugin(
name = "CustomConfigurationFactory",
category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomConfigFactory
extends ConfigurationFactory {
// ... rest of implementation
}
Параметр источника представляет собой статический файл конфигурации XML или JSON, который Log4j 2 находит, если что.
Мы можем взять этот файл конфигурации и отправить его в нашу пользовательскую реализацию XmlConfiguration, где мы можем поместить любую переопределяющую конфигурацию, которая нам нужна:
5. Заключение
public Configuration createConfiguration(
LoggerContext context,
ConfigurationSource src) {
return new WithXmlConfiguration(context, src);
}
В этой статье мы рассмотрели, как использовать новый API ConfigurationBuilder, доступный в Log4j 2.
Мы также рассмотрели возможность настройки ConfigurationFactory в сочетании с ConfigurationBuilder для более продвинутых вариантов использования.
public class WithXmlConfiguration extends XmlConfiguration {
@Override
protected void doConfigure() {
super.doConfigure(); // parse xml document
// ... add our custom configuration
}
}
Не забудьте проверить мои полные примеры на GitHub.
«
We also took a look at customizing ConfigurationFactory in combination with ConfigurationBuilder for more advanced use cases.
Don’t forget to check out my complete examples over on GitHub.