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. Конфигуратор
После того, как мы настроили Maven, нам нужно создать ConfigurationBuilder
, который является классом, который позволяет нам настраивать приложения, фильтры, макеты
и регистраторы.
Log4j 2 предоставляет несколько способов получить ConfigurationBuilder
.
Начнем с самого прямого пути:
ConfigurationBuilder<BuiltConfiguration> builder
= ConfigurationBuilderFactory.newConfigurationBuilder();
И чтобы начать настройку компонентов, ConfigurationBuilder
оснащен соответствующим новым
методом, таким как newAppender
или newLayout
, для каждого компонента.
Некоторые компоненты имеют разные подтипы, например FileAppender
или ConsoleAppender,
и в API они называются плагинами
.
3.1. Настройка приложений
Давайте сообщим сборщику
, куда отправлять каждую строку журнала, настроив приложение appender
: ``
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
и отправив его в приложение журнала
:
LoggerComponentBuilder logger = builder.newLogger("com", Level.DEBUG);
logger.add(builder.newAppenderRef("log"));
logger.addAttribute("additivity", false);
builder.add(logger);
Обратите внимание, что мы можем установить аддитивность
для наших регистраторов, которая указывает, должен ли этот регистратор наследовать свойства, такие как уровень ведения журнала и типы приложений, от своих предков.
3.6. Настройка других компонентов
Не все компоненты имеют специальный новый
метод в ConfigurationBuilder
.
Итак, в этом случае мы вызываем newComponent.
Например, поскольку TriggeringPolicyComponentBuilder
отсутствует , нам нужно использовать newComponent
для чего-то вроде указания нашей политики срабатывания для последовательного добавления файлов:
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.7. XML-эквивалент
ConfigurationBuilder
оснащен удобным методом для распечатки эквивалентного XML:
builder.writeXmlConfiguration(System.out);
Запуск вышеуказанной строки распечатывает:
<?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>
Это удобно, когда мы хотим перепроверить нашу конфигурацию или если мы хотим сохранить нашу конфигурацию, скажем, в файловой системе.
3.8. Собираем все вместе
Теперь, когда мы полностью настроены, давайте скажем Log4j 2 использовать нашу конфигурацию:
Configurator.initialize(builder.build());
После этого будущие вызовы Log4j 2 будут использовать нашу конфигурацию .
Обратите внимание, что это означает, что нам нужно вызвать Configurator.initialize
, прежде чем мы будем делать какие-либо вызовы LogManager.getLogger
.
4. Фабрика конфигураций
Теперь, когда мы увидели один способ получить и применить ConfigurationBuilder
, давайте рассмотрим еще один:
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[] { "*" };
}
}
В этом случае вместо использования ConfigurationBuilderFactory
мы создали подкласс ConfigurationFactory
, абстрактный класс, предназначенный для создания экземпляров Configuration
.
Затем вместо вызова Configurator.initialize
, как мы делали в первый раз, нам просто нужно сообщить Log4j 2 о нашей новой фабрике конфигурации.
Есть три способа сделать это:
- Статическая инициализация
- Свойство времени выполнения или
- Аннотация
@Plugin
_
4.1. Использовать статическую инициализацию
Log4j 2 поддерживает вызов setConfigurationFactory
во время статической инициализации:
static {
ConfigurationFactory custom = new CustomConfigFactory();
ConfigurationFactory.setConfigurationFactory(custom);
}
Этот подход имеет то же ограничение, что и последний подход, который мы видели, а именно то, что нам нужно будет вызывать его перед любыми вызовами LogManager.getLogger
.
4.2. Используйте свойство времени выполнения
Если у нас есть доступ к команде запуска Java, то Log4j 2 также поддерживает указание ConfigurationFactory
для использования с помощью параметра -D
:
-Dlog4j2.configurationFactory=com.foreach.log4j2.CustomConfigFactory
Основное преимущество этого подхода заключается в том, что нам не нужно беспокоиться о порядке инициализации, как в первых двух подходах.
4.3. Используйте аннотацию @Plugin
И, наконец, в обстоятельствах, когда мы не хотим возиться с командой запуска Java, добавляя -D
, мы можем просто аннотировать нашу CustomConfigurationFactory
аннотацией Log4j 2 @Plugin
:
@Plugin(
name = "CustomConfigurationFactory",
category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomConfigFactory
extends ConfigurationFactory {
// ... rest of implementation
}
Log4j 2 просканирует путь к классам на наличие классов, имеющих аннотацию @Plugin
, и, найдя этот класс в категории ConfigurationFactory
, будет использовать его.
4.4. Объединение со статической конфигурацией
Еще одно преимущество использования расширения ConfigurationFactory
заключается в том, что мы можем легко комбинировать нашу пользовательскую конфигурацию с другими источниками конфигурации, такими как XML:
public Configuration createConfiguration(
LoggerContext context,
ConfigurationSource src) {
return new WithXmlConfiguration(context, src);
}
Параметр источника
представляет собой статический файл конфигурации XML или JSON, который Log4j 2 находит, если он есть.
Мы можем взять этот файл конфигурации и отправить его в нашу пользовательскую реализацию XmlConfiguration
, где мы можем разместить любую переопределяющую конфигурацию, которая нам нужна:
public class WithXmlConfiguration extends XmlConfiguration {
@Override
protected void doConfigure() {
super.doConfigure(); // parse xml document
// ... add our custom configuration
}
}
5. Вывод
В этой статье мы рассмотрели, как использовать новый API ConfigurationBuilder
, доступный в Log4j 2.
Мы также рассмотрели возможность настройки ConfigurationFactory
в сочетании с ConfigurationBuilder
для более продвинутых вариантов использования.
Не забудьте проверить мои полные примеры на GitHub .