Програмна конфигурация с Log4j 2

1. Въведение

В този урок ще разгледаме различни начини за програмно конфигуриране на Apache Log4j 2.

2. Първоначална настройка

За да започнем да използваме Log4j 2, просто трябва да включим зависимостите log4j-core и log4j-slf4j-impl в нашия pom.xml :

 org.apache.logging.log4j log4j-core 2.11.0   org.apache.logging.log4j log4j-slf4j-impl 2.11.0 

3. ConfigurationBuilder

След като конфигурираме Maven, трябва да създадем ConfigurationBuilder , който е класът, който ни позволява да конфигурираме приложения, филтри, оформления и регистратори.

Log4j 2 предоставя няколко начина за получаване на ConfigurationBuilder .

Нека започнем с най-прекия начин:

ConfigurationBuilder 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 (име, приставка) ни позволява да дадем на приложението име, което по-късно ще се окаже важно. Тези приложения, които сме нарекли stdout и log, макар че бихме могли да ги наречем каквото и да било.

Също така сме казали на конструктора кой плъгин за приложения (или, по-просто, какъв вид добавка) да използва. Конзолата и файлът се отнасят до приложенията на Log4j 2 за съответно записване в стандартен out и файловата система.

Въпреки че 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. Конфигуриране на Root Logger

Сега, когато знаем до къде ще бъдат изпратени регистрационните файлове, искаме да конфигурираме кои регистрационни файлове ще отиват до всяка дестинация.

Основният регистратор е най-високият регистратор, нещо като Object в Java. Този регистратор е това, което ще се използва по подразбиране, освен ако не бъде заменено.

И така, нека използваме root регистратор, за да зададем нивото на регистрация по подразбиране на ERROR и добавката по подразбиране към нашия stdout appender отгоре:

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.

For example, because there isn't a TriggeringPolicyComponentBuilder, we need to use newComponent for something like specifying our triggering policy for rolling file appenders:

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. The XML Equivalent

ConfigurationBuilder comes equipped with a handy method to print out the equivalent XML:

builder.writeXmlConfiguration(System.out);

Running the above line prints out:

This comes in handy when we want to double-check our configuration or if we want to persist our configuration, say, to the file system.

3.8. Putting It All Together

Now that we are fully configured, let's tell Log4j 2 to use our configuration:

Configurator.initialize(builder.build());

After this is invoked, future calls to Log4j 2 will use our configuration.

Note that this means that we need to invoke Configurator.initialize before we make any calls to LogManager.getLogger.

4. ConfigurationFactory

Now that we've seen one way to get and apply a ConfigurationBuilder, let's take a look at one more:

public class CustomConfigFactory extends ConfigurationFactory { public Configuration createConfiguration( LoggerContext context, ConfigurationSource src) { ConfigurationBuilder builder = super .newConfigurationBuilder(); // ... configure appenders, filters, etc. return builder.build(); } public String[] getSupportedTypes() { return new String[] { "*" }; } }

In this case, instead of using ConfigurationBuilderFactory, we subclassed ConfigurationFactory, an abstract class targetted for creating instances of Configuration.

Then, instead of calling Configurator.initialize like we did the first time, we simply need to let Log4j 2 know about our new configuration factory.

There are three ways to do this:

  • Static initialization
  • A runtime property, or
  • The @Plugin annotation

4.1. Use Static Initialization

Log4j 2 supports calling setConfigurationFactory during static initialization:

static { ConfigurationFactory custom = new CustomConfigFactory(); ConfigurationFactory.setConfigurationFactory(custom); }

This approach has the same limitation as for the last approach we saw, which is that we'll need to invoke it before any calls to LogManager.getLogger.

4.2. Use a Runtime Property

If we have access to the Java startup command, then Log4j 2 also supports specifying the ConfigurationFactory to use via a -D parameter:

-Dlog4j2.configurationFactory=com.baeldung.log4j2.CustomConfigFactory

The main benefit of this approach is that we don't have to worry about initialization order as we do with the first two approaches.

4.3. Use the @Plugin Annotation

And finally, in circumstances where we don't want to fiddle with the Java startup command by adding a -D, we can simply annotate our CustomConfigurationFactory with the Log4j 2 @Plugin annotation:

@Plugin( name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY) @Order(50) public class CustomConfigFactory extends ConfigurationFactory { // ... rest of implementation }

Log4j 2 will scan the classpath for classes having the @Plugin annotation, and, finding this class in the ConfigurationFactory category, will use it.

4.4. Combining With Static Configuration

Another benefit to using a ConfigurationFactory extension is that we can easily combine our custom configuration with other configuration sources like XML:

public Configuration createConfiguration( LoggerContext context, ConfigurationSource src) { return new WithXmlConfiguration(context, src); } 

The source parameter represents the static XML or JSON configuration file that Log4j 2 finds if any.

Можем да вземем този конфигурационен файл и да го изпратим до нашата персонализирана реализация на 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.