Konfigurasi Terprogram dengan Log4j 2

1. Perkenalan

Dalam tutorial ini, kita akan melihat berbagai cara untuk mengkonfigurasi Apache Log4j 2 secara terprogram.

2. Pengaturan Awal

Untuk mulai menggunakan Log4j 2, kita hanya perlu menyertakan dependensi log4j-core dan log4j-slf4j-impl di pom.xml kita :

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

3. ConfigurationBuilder

Setelah Maven dikonfigurasi, maka kita perlu membuat ConfigurationBuilder , yaitu kelas yang memungkinkan kita mengonfigurasi appenders, filter, tata letak, dan logger.

Log4j 2 menyediakan beberapa cara untuk mendapatkan ConfigurationBuilder .

Mari kita mulai dengan cara paling langsung:

ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();

Dan untuk mulai mengonfigurasi komponen, ConfigurationBuilder dilengkapi dengan metode baru yang sesuai , seperti newAppender atau newLayout , untuk setiap komponen.

Beberapa komponen memiliki subtipe yang berbeda, seperti FileAppender atau ConsoleAppender, dan ini disebut dalam API sebagai plugin .

3.1. Mengonfigurasi Appenders

Mari beri tahu pembuat tempat untuk mengirim setiap baris log dengan mengonfigurasi 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);

Meskipun sebagian besar metode baru tidak mendukung ini, newAppender (nama, plugin) memungkinkan kita memberi nama appender, yang nantinya akan menjadi penting. Penambah ini, kami telah memanggil stdout dan log, meskipun kami dapat menamainya apa saja.

Kami juga telah memberi tahu builder plugin appender mana (atau, lebih sederhananya, appender jenis apa) yang akan digunakan. Konsol dan File merujuk ke appenders Log4j 2 untuk penulisan standar dan sistem file, masing-masing.

Meskipun Log4j 2 mendukung beberapa appender, mengonfigurasinya menggunakan Java bisa sedikit rumit karena AppenderComponentBuilder adalah kelas umum untuk semua jenis appender.

Ini membuatnya memiliki metode seperti addAttribute dan addComponent, bukan setFileName dan 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); 

Dan, terakhir, jangan lupa memanggil builder.add untuk menambahkannya ke konfigurasi utama!

3.2. Mengonfigurasi Filter

Kita dapat menambahkan filter ke setiap appenders kita, yang memutuskan setiap baris log apakah itu harus ditambahkan atau tidak.

Mari gunakan plugin MarkerFilter di appender konsol kami:

FilterComponentBuilder flow = builder.newFilter( "MarkerFilter", Filter.Result.ACCEPT, Filter.Result.DENY); flow.addAttribute("marker", "FLOW"); console.add(flow);

Perhatikan bahwa metode baru ini tidak mengizinkan kita memberi nama filter, tetapi meminta kita untuk menunjukkan apa yang harus dilakukan jika filter lolos atau gagal.

Dalam kasus ini, kami membuatnya sederhana, menyatakan bahwa jika MarkerFilter lolos, maka TERIMA logline-nya. Jika tidak, TOLAK .

Perhatikan dalam kasus ini bahwa kami tidak menambahkan ini ke pembuat melainkan ke appenders yang ingin kami gunakan filter ini.

3.3. Mengonfigurasi Tata Letak

Selanjutnya, mari tentukan tata letak untuk setiap baris log. Dalam kasus ini, kami akan menggunakan plugin PatternLayout :

LayoutComponentBuilder standard = builder.newLayout("PatternLayout"); standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"); console.add(standard); file.add(standard); rolling.add(standard);

Sekali lagi, kami telah menambahkan ini secara langsung ke appenders yang sesuai alih-alih ke pembuat secara langsung.

3.4. Mengonfigurasi Root Logger

Sekarang kita tahu ke mana log akan dikirim, kita ingin mengkonfigurasi log mana yang akan pergi ke setiap tujuan.

Root logger adalah logger tertinggi, sejenis Objek di Java. Logger inilah yang akan digunakan secara default kecuali diganti.

Jadi, mari gunakan logger root untuk menyetel tingkat logging default ke ERROR dan appender default ke appender stdout kami dari atas:

RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.ERROR); rootLogger.add(builder.newAppenderRef("stdout")); builder.add(rootLogger);

Untuk mengarahkan logger kami ke appender tertentu, kami tidak memberikannya contoh dari pembuatnya. Sebaliknya, kami merujuknya dengan nama yang kami berikan sebelumnya.

3.5. Mengonfigurasi Logger Tambahan

Pencatat anak dapat digunakan untuk menargetkan paket atau nama pencatat tertentu.

Mari tambahkan pencatat untuk paket com di aplikasi kita, setel tingkat pencatatan ke DEBUG dan minta mereka masuk ke appender log kita :

LoggerComponentBuilder logger = builder.newLogger("com", Level.DEBUG); logger.add(builder.newAppenderRef("log")); logger.addAttribute("additivity", false); builder.add(logger);

Perhatikan bahwa kita bisa menyetel aditif dengan logger kita, yang menunjukkan apakah logger ini harus mewarisi properti seperti level logging dan tipe appender dari leluhurnya.

3.6. Konfigurasi Komponen Lain

Tidak semua komponen memiliki metode baru khusus di ConfigurationBuilder .

Jadi, dalam hal ini, kami memanggil komponen baru.

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.

Kita dapat mengambil file konfigurasi itu dan mengirimkannya ke implementasi kustom XmlConfiguration kita di mana kita dapat menempatkan konfigurasi pengganti apa pun yang kita butuhkan:

public class WithXmlConfiguration extends XmlConfiguration { @Override protected void doConfigure() { super.doConfigure(); // parse xml document // ... add our custom configuration } }

5. Kesimpulan

Pada artikel ini, kami melihat cara menggunakan API ConfigurationBuilder baru yang tersedia di Log4j 2.

Kami juga melihat penyesuaian ConfigurationFactory yang dikombinasikan dengan ConfigurationBuilder untuk kasus penggunaan yang lebih canggih.

Jangan lupa untuk melihat contoh lengkap saya di GitHub.