1. 序章

このチュートリアルでは、ApacheLog4j2をプログラムで構成するさまざまな方法を見ていきます。

2. 初期設定

Log4j 2の使用を開始するには、log4j-corelog4j-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 には、コンポーネントごとにnewAppendernewLayoutなどの対応するnewメソッドが装備されています。

一部のコンポーネントには、 FileAppenderConsoleAppender、などの異なるサブタイプがあり、これらはAPIではpluginsと呼ばれます。

3.1. アペンダーの構成

appender を構成して、各ログ行の送信先をbuilderに伝えましょう。

AppenderComponentBuilder console 
  = builder.newAppender("stdout", "Console"); 

builder.add(console);

AppenderComponentBuilder file 
  = builder.newAppender("log", "File"); 
file.addAttribute("fileName", "target/logging.log");

builder.add(file);

ほとんどのnewメソッドはこれをサポートしていませんが、 newAppender(name、plugin)を使用すると、アペンダーに名前を付けることができます。これは後で重要になることがわかります。 これらのアペンダーは、 stdoutおよびlog、と呼んでいますが、任意の名前を付けることができます。

また、ビルダーにどのアペンダープラグイン(またはより簡単に言えば、どの種類のアペンダー)を使用するかを指示しました。 ConsoleFileは、それぞれ標準出力とファイルシステムへの書き込み用のLog4j2のアペンダーを参照します。

Log4j 2はいくつかのアペンダーをサポートしていますが、AppenderComponentBuilderはすべてのアペンダータイプの汎用クラスであるため、Javaを使用してそれらを構成するのは少し難しい場合があります。

これにより、setFileNameおよびaddTriggeringPolicyの代わりに、addAttributeおよびaddComponentのようなメソッドが作成されます。

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);

このnewメソッドではフィルターに名前を付けることはできませんが、フィルターが成功または失敗した場合の対処方法を指定するように求められることに注意してください。

この場合、 MarkerFilter が合格すると、ACCEPTログラインになります。 それ以外の場合は、 DENYit。

この場合、これを builder に追加するのではなく、このフィルターを使用するアペンダーに追加することに注意してください。

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);

繰り返しになりますが、これらを builder に直接追加するのではなく、適切なアペンダーに直接追加しました。

3.4. ルートロガーの構成

ログの送信先がわかったので、各宛先に送信するログを構成します。

ルートロガーは、JavaのObjectのような最高のロガーです。 このロガーは、オーバーライドされない限り、デフォルトで使用されるものです。

それでは、ルートロガーを使用して、デフォルトのログレベルを ERROR に設定し、デフォルトのアペンダーを上からstdoutアペンダーに設定しましょう。

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

builder.add(rootLogger);

ロガーを特定のアペンダーに向けるために、ビルダーのインスタンスを指定しません。 代わりに、以前に付けた名前で参照します。

3.5. 追加のロガーの構成

子ロガーは、特定のパッケージまたはロガー名をターゲットにするために使用できます。

アプリケーションにcomパッケージのロガーを追加し、ログレベルを DEBUG に設定して、ログappenderに移動させます。

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

builder.add(logger);

ロガーで加法性を設定できることに注意してください。これは、このロガーがログレベルやアペンダータイプなどのプロパティを祖先から継承する必要があるかどうかを示します。

3.6. その他のコンポーネントの構成

すべてのコンポーネントがConfigurationBuilderに専用のnewメソッドを持っているわけではありません。

したがって、その場合は、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. すべてを一緒に入れて

完全に構成されたので、Log4j2に構成を使用するように指示しましょう。

Configurator.initialize(builder.build());

これが呼び出された後、 Log4j 2への今後の呼び出しでは、構成が使用されます。

これは、 LogManager.getLogger を呼び出す前に、Configurator.initializeを呼び出す必要があることを意味します。

4. ConfigurationFactory

ConfigurationBuilder を取得して適用する1つの方法を確認したので、もう1つ見てみましょう。

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 を使用する代わりに、Configurationのインスタンスを作成することを目的とした抽象クラスであるConfigurationFactoryをサブクラス化しました。

次に、最初に行ったように Configurator.initialize を呼び出す代わりに、Log4j2に新しい構成ファクトリについて通知する必要があります。

これを行うには3つの方法があります。

  • 静的初期化
  • ランタイムプロパティ、または
  • @Pluginアノテーション

4.1. 静的初期化を使用する

Log4j 2は、静的初期化中のsetConfigurationFactoryの呼び出しをサポートしています。

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

このアプローチには、最後に見たアプローチと同じ制限があります。つまり、LogManager.getLoggerを呼び出す前にを呼び出す必要があります。

4.2. ランタイムプロパティを使用する

Java起動コマンドにアクセスできる場合、Log4j 2は、-Dパラメーターを介して使用するConfigurationFactoryの指定もサポートします。

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

このアプローチの主な利点は、最初の2つのアプローチのように初期化の順序を気にする必要がないことです。

4.3. @Pluginアノテーションを使用する

そして最後に、 -D を追加してJava起動コマンドをいじりたくない状況では、CustomConfigurationFactoryにLog4j2で注釈を付けることができます。 ] @Plugin アノテーション:

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

  // ... rest of implementation
}

Log4j 2は、クラスパスをスキャンして @Plugin アノテーションを持つクラスを探し、ConfigurationFactoryカテゴリでこのクラスを見つけて使用します。

4.4. 静的構成との組み合わせ

ConfigurationFactory 拡張機能を使用するもう1つの利点は、カスタム構成をXMLなどの他の構成ソースと簡単に組み合わせることができることです。

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

source パラメーターは、Log4j2が検出する静的XMLまたはJSON構成ファイルを表します。

その構成ファイルを取得して、 XmlConfiguration のカスタム実装に送信し、必要なオーバーライド構成を配置できます。

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

        // ... add our custom configuration
    }
}

5. 結論

この記事では、Log4j2で利用可能な新しいConfigurationBuilderAPIの使用方法について説明しました。

また、より高度なユースケースのために、ConfigurationFactoryConfigurationBuilderと組み合わせてカスタマイズすることも検討しました。

GitHubで私の完全な例をチェックすることを忘れないでください。