ウェブサイト検索

Log4j2の例チュートリアル - 設定、レベル、アペンダー


Apache Log4j2の例/tutorialへようこそ。アプリケーションについて最もイライラすることを専門の開発者に尋ねると、その答えはログに関連しているかもしれません。アプリケーションに適切なログがなければ、メンテナンスは悪夢のようになるでしょう。ほとんどのアプリケーションは開発テスト、単体テスト、統合テストを経ます。しかし、本番環境に入ると、常にユニークなシナリオや例外に直面します。特定のケースで何が起こったかを見極める唯一の方法は、ログを通してデバッグすることです。多くのフレームワークにはデフォルトのログ機構がありますが、業界標準のログメカニズムに従うのが最良です。Apache Log4jは最も広く使用されているログフレームワークの1つです。Apache Log4j 2は次のバージョンで、Log4jよりもはるかに優れています。

Log4jの例チュートリアル

このLog4j2の例/tutorialでは、Apache Log4j2の使い方を学びます。また、Log4j2のアーキテクチャ、log4j2の設定、log4j2のログレベル、アペンダー、フィルターなどについても探求します。

  1. Log4j2 概要
  2. Log4j2アーキテクチャ
  3. Log4j2の設定
  4. Log4j2 レベル
  5. Log4j2 ルックアップ
  6. Log4j2 アペンダー
  7. Log4j2 フィルター
  8. Log4j2 レイアウト
  9. どのLog4j2レベルを使用すべきですか
  10. Log4j2 チュートリアルの概要

Log4j2 概要

アプリケーションでロギングAPIを使用することは贅沢ではなく、必須です。Log4jはApache Softwareの下で公開されたオープンソースライブラリです。Eclipseデバッグや他のツールを使用してアプリケーションをデバッグすることはできますが、これは本番環境では十分ではなく、実行可能ではありません。ロギングメカニズムは、通常のデバッグでは見られないいくつかの利点を提供します。

カテゴリ/操作 (デバッグ、ログ記録)デバッグログ記録
人間の介入人間の介入が必要です人間の介入は必要ありません
持続的なメディウム永続的なストレージと統合できません永続ストレージ(ファイル、データベース、NoSQLデータベースなど)と統合可能です。
監査に使用された5月監査を達成するためには使用できません。効率的に使用されれば、監査を達成するために使用できます。
複雑な構造と流れに十分です十分ではありません; 流れに流されて迷うかもしれません。十分
生産性生産性が低いより生産的

上に示したように、ログメカニズムを使用することで、メンテナンスコストが少なく、より効率的になります。Apache Log4jはJavaアプリケーションでのログ記録のための先駆的なツールであるため、使用するべきです。

Log4j2アーキテクチャ

Log4jの例のチュートリアルに進む前に、Log4j2のアーキテクチャを見ておくことが良いです。下の画像はLog4j2 APIの重要なクラスを示しています。

  • アプリケーションは、特定の名前を持つLoggerを取得するためにLogManagerに要求します。

  • LogManager は適切な LoggerContext を見つけて、そこから Logger を取得します。

  • まだLoggerが作成されていない場合は、以下の3つの選択肢に従って作成され、LoggerConfigに関連付けられます:

    1. Loggerインスタンスが作成され、同じ名前のLoggerConfigに関連付けられます。例えば、getLogger(App.class)におけるApp.classは、文字列com.journaldev.Appとして評価されます。LoggerConfigの名前は完全修飾クラス名(ソフトウェアコンポーネント)と同一です。
    2. Loggerインスタンスが作成され、同じLoggerの親パッケージを持つLoggerConfigと関連付けられます。たとえば、com.journaldevがgetLogger("com.journaldev")で使用されます。
    3. ロガーインスタンスが作成され、ルートLoggerConfigに関連付けられます。ルートLoggerConfigは、設定ファイルがない場合や、ロガー宣言で定義されていない名前のロガーを取得する場合に使用されます。
  • LoggerConfigオブジェクトは、設定ファイルのLogger宣言から作成されます。LoggerConfigはまた、LogEventsを処理し、それらを定義されたLog4j2 Appendersに委譲するためにも使用されます。

  • ルートロガーは、その存在に関しては特別なケースです。常に存在し、あらゆるロガーヒエラルキーの最上部にあります。

  • 以下の文を使用してルートロガーを取得できます:

    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    Logger logger = LogManager.getRootLogger();
    
  • log4j2のロガーの名前は大文字と小文字を区別します。

  • ルートロガーを除いて、すべてのロガーはその名前をLogManager.getLogger()に渡すことで取得できます。

  • LoggerContextはログシステムの中心的なポイントであり、アプリケーション内に複数のLoggerContextが存在する場合があります。それぞれのLoggerContextに対して、アクティブな設定を行う必要があります。

  • Log4j2の設定には、すべてのログシステムの資産が含まれています。LoggerConfig、Appender、Filter、その他多くのものです。

  • 同じ名前を渡してLogManager.getLogger()を呼び出すことは、常に同じロガーインスタンスの参照を返します。

  • ログシステムの設定は通常、アプリケーションの初期化時に行われます。これはさまざまな形を取り得ます。プログラム的に、またはlog4j2の設定ファイルを読み込むことで行われます。

すべてのロガーは LoggerConfig オブジェクトに関連付けられており、LoggerConfig オブジェクトのセットがロガーの階層を構成しています。この概念はロガー階層として知られています。ロガー階層は親子関係を持つ LoggerConfig オブジェクトのセットで構成されています。すべてのロガー階層における最上位の要素はルートロガーです。Log4j2 が設定ファイルを見つけられない場合、ルートロガーのみがログを記録するために使用され、ログレベルは ERROR になります。以下の画像は、この場合に表示される警告メッセージを示しています。Error StatusLogger no log4j2 configuration file found. Using default configuration: logging only errors to the console.

下の表は、ロガーヒエラルキーにおける親子関係を示しています。

LoggerConfig(である)ルートコンcom.journaldevcom.journaldev.logging
ルートX子供子孫子孫
コン親X子供子孫
com.journaldev祖先親X子供
com.journaldev.logging祖先祖先親X

親子関係を明確にするために、上の表は次のように読むことができます:

  • ルートはcomの親です。
  • ルートは com.journaldev の祖先です。
  • Rootはcom.journaldev.loggingの祖先です。
  • comはRootの子供です。
  • comはcom.journaldevの親です。
  • com は com.journaldev.logging の祖先です。
  • com.journaldev.logging は com.journaldev の子孫です。そしてそのように続きます。

LoggerConfigのインスタンスは、名前の後にドットが付いている場合、その名前が子孫の名前のプレフィックスであるとき、別のLoggerConfigの先祖であると言います。また、LoggerConfigのインスタンスは、両者の間に中間の名前が存在しない場合、別のLoggerConfigの親であると言います。

Log4j2の設定

アプリケーションでLog4j2の構成を使用する方法はたくさんあります。

  1. XML、JSON、YAML、またはプロパティファイルで書かれた構成ファイルを使用して。
  2. プログラム的に、構成ファクトリーと構成実装を作成することによって。
  3. プログラム的に、設定インターフェースで公開されているAPIを呼び出すことによって。
  4. プログラム的に、内部ロガークラスのメソッドを呼び出すことによって。

私たちは主に設定ファイルに焦点を当てます。しかし、特定のLoggerに特定のロギング戦略を設定したい場合に備えて、プログラミングアプローチも知っておくことは良いことです。まず最初に、設定ファイルを提供しなかった場合を考えてみましょう。Log4j2の実装は、log4j2の設定ファイルの場所を指し示すlog4j.configurationFileというシステム変数があると仮定しています。

package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
    public static void main( String[] args ) {
    	Logger logger = LogManager.getRootLogger();
    	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
    }
}

シンプルな log4j2 の構成ファイルは以下のようになります。 configuration.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

そして、上記に示されたコードの詳細な説明はこちらです:

  • アプリはLogManagerのgetRootLoggerメソッドを呼び出すことによってルートロガーを参照しました。
  • LogManagerからのロガーの参照がLog4jシステムを開始しました。
  • Log4jは、log4j.configurationFileシステムプロパティを調べてlog4j2の設定ファイルを特定します。Log4jの設定は、JSON、YAML、XML形式で記述できます。
  • log4j.configurationFile システムプロパティは、System.setProperties("log4j.configurationFile","FILE_PATH") を通じて設定するか、以下の図のようにJVMパラメータとして渡すことができます。また、ファイルプロトコルのプレフィックスにも注意してください。

  • システムプロパティが定義されていない場合、構成の順序は以下の優先順位に従います:

    • プロパティ ConfigurationFactory はクラスパス内の log4j2-test.properties を探します。
    • YAML ConfigurationFactory はクラスパス内で log4j2-test.yaml または log4j2-test.yml を探します。
    • JSON ConfigurationFactoryはクラスパス内でlog4j2-test.jsnまたはlog4j2-test.jsonを探します。
    • XML ConfigurationFactory はクラスパス内で log4j2-test.xml を探します。
    • プロパティ ConfigurationFactory はクラスパス上の log4j2.properties を探します。
    • YAML ConfigurationFactoryは、クラスパス内でlog4j2.ymlまたはlog4j2.yamlを探します。
    • JSON ConfigurationFactoryは、クラスパス内にlog4j2.jsnまたはlog4j2.jsonを探します。
    • log4j2.xmlはクラスパスでXML ConfigurationFactoryによって探されます。
    • 構成ファイルが提供されていない場合、DefaultConfigurationが適用され、これにより一連のデフォルトの動作が導かれます:

      • ルートロガーが使用されます。
      • ルートロガーレベルはERRORに設定されます。
      • ルートロガーは、ログメッセージをコンソールに伝播します。
      • PatternLayoutは%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%nに設定されています

log4j2の設定ファイルを使用すると、log4j2の設定が非常に簡単になりますが、プログラムでどのように設定できるかを見てみましょう。これはすべてConfigurationFactoryを使用することについてです。

package com.journaldev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
public class App
{
    public static void main( String[] args ) throws FileNotFoundException, IOException {
 
    	// Get instance of configuration factory; your options are default ConfigurationFactory, XMLConfigurationFactory,
    	// 	YamlConfigurationFactory & JsonConfigurationFactory
    	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
 
    	// Locate the source of this configuration, this located file is dummy file contains just an empty configuration Tag
    	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
 
    	// Get a reference from configuration
    	Configuration configuration = factory.getConfiguration(configurationSource);
 
    	// Create default console appender
    	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
 
    	// Add console appender into configuration
    	configuration.addAppender(appender);
 
    	// Create loggerConfig
    	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
 
    	// Add appender
    	loggerConfig.addAppender(appender,null,null);
 
    	// Add logger and associate it with loggerConfig instance
    	configuration.addLogger("com", loggerConfig);
 
    	// Get context instance
    	LoggerContext context = new LoggerContext("JournalDevLoggerContext");
 
    	// Start logging system
    	context.start(configuration);
 
    	// Get a reference for logger
    	Logger logger = context.getLogger("com");
 
    	// LogEvent of DEBUG message
    	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
 
    	// LogEvent of Error message for Logger configured as FATAL
    	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
 
    	// LogEvent of ERROR message that would be handled by Root
    	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
    }
}
  • Log4j2によって提供されたConfigurationFactoryのいずれかを使用するか、デフォルトのものを使用できます。私たちは、ConfigurationFactoryのインスタンスを取得するためにXMLConfigurationFactoryを使用しました。
  • 工場は、対応する設定ファイルを渡すことで、必要な構成のインスタンスを提供します。
  • 構成インスタンスは、ログシステムを起動するためにLoggerContextと組み合わせて使用されます。
  • コンソールアペンダーが構成インスタンスにデフォルトのレイアウトで設定され、追加されました。このアペンダーは、メッセージをコンソールに出力します。
  • LoggerConfigインスタンスが提供された名前、LEVEL、フィルターなしで作成されました。このLoggerConfigインスタンスに対して作成されたAppenderが割り当てられます。
  • LoggerConfigインスタンスが設定インスタンスに追加されました。
  • 定義された名前でLoggerContextの新しいインスタンスが作成されます。
  • 構成インスタンスがLoggerContextインスタンスに渡され、後者の開始が呼び出されました。
  • LoggerContextからロガーインスタンスが取得されました。このロガーインスタンスは、一連のログイベントを発火させるために使用されます。
  • ロガーインスタンスは、Log4j2レベルセクションで説明される3つのイベントを発生させました。
  • ログ出力は、FATALレベルのメッセージを表示するように構成されています。
  • デフォルトでは、ルートロガーはERRORレベルのメッセージを出力するように設定されています。
  • エラーメッセージは、'com' ロガーによって記録されません。そのレベルは致命的です。

同じ構成はYAML、JSON、またはプロパティファイルを使用して行うことができます。ただし、log4j2のプロパティファイルの構成はlog4jのプロパティファイルとは異なるため、log4jのプロパティファイルの構成をlog4j2と一緒に使用しようとしていないことを確認してください。以下のエラーが発生します;

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

上記のコードを処理すると、以下の出力が得られます:

Logger Name :: com :: Passed Message ::
00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages

最初のログ行はcomロガーからのもので、2番目はルートロガーからのものです。comロガーのエラーメッセージは、そのレベルがFatalであるため、印刷されません。

Log4j2 レベル

上記のコード例でわかるように、LoggerConfigを定義するたびに、ログレベルも提供しています。デフォルトでは、log4j2のロギングは加算的です。これは、特定のロガーが使用されるときに、すべての親ロガーも使用されることを意味します。以下の画像がこの状況を明確にしています。

  • 先に述べたように、各ロガーはLoggerConfigインスタンスに関連付けられています。このloggerConfigは設定スコープで定義されています。
  • ログのレベルはLoggerConfigスコープで決定できます。
  • ロガーはその名前、親パッケージ、またはルートロガー自体を指定することによって取得できます。
  • ルートロガーはすべてのLoggerConfig階層の最上位ノードです。
  • 一度 com.journaldev ロガーを取得し、ログ記録のために logEvent を開始すると、loggerConfig (net.journaldev) はメッセージを記録し、メッセージは親のログレベルを無視して階層内で伝播されます。したがって、ログイベントは com と Root ロガーに伝播し、彼らも定義されたレベルに応じてメッセージを記録します。
  • コムロガーを取得し、ログ記録のためのlogEventを開始すると、loggerConfig(com)がメッセージを記録し、そのメッセージは親のログレベルに関係なく、階層上に伝播されます。つまり、ルートロガーはログイベントを伝播させ、メッセージも記録します。
  • net.journaldevの階層についても同様のケースです。
  • 次のセクションでは、付加的な概念についてのさらなる説明を加えます。
  • 親はフィルター概念を使用するか、加算インジケーターを false に設定することでメッセージを無視する可能性があるため、ログイベントは親に伝播しません。
  • それぞれのloggerConfigのレベルがログイベントのレベルよりも高い場合、ロガーがメッセージを無視する可能性があります。

では、上記で説明した加法性に関連する例を見てみましょう:

import net.NetApp;
import net.journaldev.NetJournalDevApp;
import com.ComApp;
import com.journaldev.ComJournalDevApp;
public class Main {
	public static void main(String [] args){
		new ComApp();
		new ComJournalDevApp();
		new NetApp();
		new NetJournalDevApp();
	}
}
package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ComJournalDevApp {
	public ComJournalDevApp(){
		Logger logger = LogManager.getLogger(ComJournalDevApp.class);
		logger.trace("COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::");
	}
}
package net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetApp {
	public NetApp(){
		Logger logger = LogManager.getLogger(NetApp.class);
		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
	}
}
package net.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetJournalDevApp {
	public NetJournalDevApp(){
		Logger logger = LogManager.getLogger(NetJournalDevApp.class);
		logger.error("NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::");
	}
}

log4j2の設定ファイルは以下のようになります:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

メインクラスを実行すると、以下の結果が得られます:

10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

以下に上記のコードに関する詳細な説明があります。

  • 設定ファイルには、Root、com、com.journaldev、net、net.journaldev の5つの loggerConfig インスタンスが定義されています。これは、上記の Logger 階層と同様です。
  • ルートのレベルはERRORに設定されており、実際にはそれがデフォルト値です。
  • com および com.journaldev のレベルは TRACE に設定されています。
  • net & net.journaldevのレベルはERRORに設定されています。
  • ComAPP と ComJournalDevApp のロガーのメッセージがそれぞれ2回と3回表示されていることに気付いたかもしれません。これらのメッセージは、com および com.journalDev パッケージにある ComApp および ComJournalDevApp のロガーハイアラキーに従って表示されています。NetApp と NetJournalDevApp クラスについても同様のケースがあります。
  • 親は、加算指標がデフォルトで真に設定されているとして伝播します。

ロギングスペースは、ロギングイベントのレベルとloggerConfigのレベルに加えて、ロガーヒエラルキーも考慮します。

では、comのLoggerConfigをINFOに変更し、プログラム全体はそのままにしたらどうなるでしょうか?

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="INFO">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

その結果は以下のようになります:

11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
  • 確かに、ComAPPのログイベントが無視されていることに気づくかもしれません。それはcomパッケージのloggerConfigで定義されたレベルによるものです。INFO(400)レベルは、ここでのログイベントのレベルであるTRACE(600)よりも低いため、ComAppのメッセージはもう表示されません。表示させるためには、comのLoggerConfigのレベルをTRACE(600)またはALL(Integer.MAX_VALUE)に変更する必要があります。

ログイベントが表示されることを確認するために、LoggerConfigのレベルはログイベントのレベル以上である必要があります。

以下の表はlog4j2のレベルとそれぞれの重みを示しています:

レベル重量
オフ
致命的100
エラー200
警告300
情報400
デバッグ500
トレース600
すべて整数の最大値

確かに、上の表は言葉以上に多くのことを明確にし、LoggerConfigのレベルがINFOであるためにLogイベントTRACEが表示されない主な原因を示しています。

ロガー階層でのログイベントの伝播はこの計算を超えており、レベルは無視されることに注意してください。

しかし、com.journaldevのLoggerConfigを設定から削除し、com.journaldev.loggingの新しいものを追加して、設定ファイルを以下のようにするとどうなりますか?

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

上記のlog4j2設定で何が起こったかを理解するのに、以下の図がより便利かもしれません。

  • com.journaldev.loggingという名前のLoggerによってログイベントがスローされた場合、その名前(つまり、com.journaldev.logging)に関連付けられたLoggerConfigがそれを処理し、メッセージを印刷するために使用されます。
  • com.journaldev.logging LoggerConfigのadditive属性はデフォルトでtrueに設定されているため、ログイベントは親に伝播されており、ここで言う親はcom.journaldevを指します。
  • com.journaldev LoggerConfigが設定で定義されていない場合、何もアクションは起こらず、ログイベントはcomまで伝播され、次にRoot LoggerConfigインスタンスに渡されます。
  • Com & Rootはログイベントを受け取り、そのレベルに関係なく印刷します。

上記のポイントに基づいて、以下の出力が表示されます。

14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

そして、次の点に気付くかもしれません:

  • comパッケージのログイベントが2回表示されています。一つはcom用、もう一つはRoot用です。
  • com.journaldevのログイベントが2回表示されました。1回はcom、もう1回はRootのためです。以前は3回あったものの、現在はcom.journaldevのLoggerConfigが存在しないため、com.journaldevパッケージでのログ記録は行われていない可能性があり、イベントはcomとRootに伝播しているでしょう。
  • com.journaldev.loggingでのログイベントは3回表示されました。1回目はcom.journaldev.loggingパッケージ、2回目はcom、3回目はRootのためです。Logger Hierarchyの伝播によれば、4回表示されるべきですが、com.jounraldev LoggerConfigの不在のため、3回表示されます。

もしあなたがレベルを指定せずに com.journaldev LoggerConfig インスタンスを定義した場合、それは親のレベルを継承します。

しかし、もしあなたが設定ファイルで com.journaldev LoggerConfig を定義したものの、LoggerConfig のレベルを指定し忘れた場合はどうでしょうか。幸運なことに、Logger Hierarchy の概念がここで役立ち、com.journaldev はその親からレベル値を継承します。以下はサンプル設定ファイルと、各ロガー設定のログレベルに関する表です。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>
ログ名割り当てられたLoggerConfigロガー設定レベルログレベル
ルートルートエラーエラー
コンコントレーストレース
com.journaldevコントレーストレース
com.journaldev.loggingcom.journaldev.loggingトレーストレース
  • com.journaldev.loggingパッケージは、すでにTRACEログレベルのLoggerConfigに関連付けられています。
  • com.journaldevパッケージは、指定されたログレベルがないLoggerConfigに既に関連付けられているため、親ログレベルを継承します。そして、確実にcomパッケージの値はTRACEになります。
  • comパッケージはすでにTRACEログレベルでLoggerconfigに関連付けられています。
  • デフォルトでは、ルートはログレベルとしてERRORを持っています。
  • comパッケージが宣言されていない場合、com.journaldev LoggerConfigはRootのログレベルを継承します。

以下は、com.journaldevがcomのログレベルを継承しているときの実行結果です。

14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

そして、com パッケージの LoggerConfig を宣言しない場合の結果は以下のようになります:

14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

comおよびcom.journaldevに対してメッセージがログに記録されていないことに気づかれるかもしれません。以下にその理由を示します。

  • comパッケージに関連するLoggerConfigの削除は、そのパッケージで言及されたすべてのログイベントを無視させることになります。
  • comパッケージの設定にLoggerConfigが定義されていないため、com.journaldevに関連付けられたLoggerConfigは親からログレベルを継承します。comは定義されておらず、Logger階層は最上位に達し、現在はRootを参照しています。ルートのログレベルはERROR(200)で、com.journaldevのログイベントのレベルはTRACE(600)です - ComJournalDevAppを参照してください - 前述の式に従うと、LoggerConfigのレベルはログイベント以上でなければならず、それは偽ですので、com.journaldevに対してここにはメッセージは表示されません。

最後に、以下の表は、ログシステムを使用する際に直面する可能性のあるすべてのログシナリオを示しています。

X (該当なし)ロガー設定レベルオフ(0)致命的(100)エラー(200)警告(300)情報(400)デバッグ(500)TRACE(600)すべて(最大)
イベントレベルXXXXXXXXX
オフ(0)Xはいいいえいいえいいえいいえいいえいいえいいえ
致命的(100)Xいいえはいはいはいはいはいはいはい
エラー(200)Xいいえいいえはいはいはいはいはいはい
警告(300)Xいいえいいえいいえはいはいはいはいはい
情報(400)Xいいえいいえいいえいいえはいはいはいはい
デバッグ(500)Xいいえいいえいいえいいえいいえはいはいはい
TRACE(600)Xいいえいいえいいえいいえいいえいいえはいはい
すべて(最大)Xいいえいいえいいえいいえいいえいいえいいえはい
  • OFF/ALLログイベントを投げるために使用できる直接的な方法はありません。
  • 主に、OFF/ALLのログイベントを送信するために、logger.log(Level.OFF, "Msg ") または logger.log(LEVEL.ALL, "Msg ") を使用できます。
  • ログメソッドは、述べられた方程式に従ってログイベントを処理する責任があります。

処理に関する方程式は次のように言っています: LoggerConfigのレベルがログイベントのレベル以上であれば、そのイベントはさらに処理されるために受け入れられます。

ログイベントはさらなる処理のために受け入れられます - これは非常に重要です。なぜなら、Log4j2フィルターを使用して、受け入れられたイベントが処理されるのを防ぐ能力があるからです。additiveプロパティをfalseに設定することで、ログイベントを親ロガーに伝播させないようにできます。以下に以前に見たのと同じ例を示しますが、今回はadditivity属性を使用していますので、違いに気づくかもしれません。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

そして、実行の結果は以下のようになります:

17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
17:55:30.560 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
17:55:30.561 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
17:55:30.562 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

そして、ログイベントがその親ロガーに伝播しないことに気付くかもしれません。

Log4j2 ルックアップ

理想的には、ログ設定ファイルに値を渡す方法として、ルックアップを定義できます。Log4j2は、異なるコンテキストから値を設定するために独立して使用できる異なるセットのルックアップを提供します。

  • コンテキストマップの検索
  • 日付検索
  • 環境検索
  • Java ルックアップ
  • JNDI ルックアップ
  • JVM入力引数検索(JMX)
  • 主要な論点検索
  • 地図検索
  • 構造化データ検索
  • システムプロパティの検索
  • ウェブ検索

Log4j2のドキュメンテーションを参照して、すべてのタイプのルックアップの詳細を確認できますが、ここではLog4j2のルックアップの基本をカバーするいくつかの例を見ていきましょう。環境ルックアップは、環境値を渡す方法を表しています(Linuxの/etc/profile、Windowsのシステム環境、またはアプリケーションのスタートアップスクリプトによって)。私たちのほとんどが知っているように、アプリケーションが使用するための環境値のセットを定義する能力があります。環境変数を定義する最も有名な方法を見てみましょう。

  1. Windowsの環境機能を使用して環境変数を定義します:

    • コンピュータのアイコンを右クリックし、プロパティを選択します。コントロールパネルのホームが表示されるはずです。
    • 詳細なシステム設定をクリックし、次に環境変数ウィンドウを開きます。
    • システム変数セクションの下で、JournalDevの値を持つ変数JournalDevVarを定義します。
    • log4j2.xmlのPatternLayoutを更新して、新しく追加した変数を含める。

  1. スタートアップスクリプト機能を使用して、環境変数を定義してください。

    • 代わりに、通常のデフォルトスクリプトを使用するのではなく、Eclipse IDEの実行スクリプト機能を使用できます。実行メニューをクリックし、実行構成を選択してください。
    • 環境タブに移動し、そこで変数を定義してください。

修正されたlog4j2.xmlファイルを今見て、環境変数の使い方に注意してください。

<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n"/>
</Console>

そして、実行の結果は以下のようになります:

23:57:02.511 JournalDev www.journaldev.com [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
23:57:02.517 JournalDev www.journaldev.com [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
23:57:02.520 JournalDev www.journaldev.com [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
23:57:02.523 JournalDev www.journaldev.com [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
23:57:02.527 JournalDev www.journaldev.com [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

しかし、ここで少し問題に直面するかもしれません。特にOSの環境変数を定義しているときで、これはEclipseのキャッシュに関係しています。理想的には、Eclipseは起動時にすべてのシステム変数をキャッシュしており、それらは「実行」-「実行構成」-「環境」タブの下にあり、選択ボタンをクリックすると確認できます。

EnvironmentLookup lookup = new EnvironmentLookup();
LogManager.getRootLogger().error(lookup.lookup("JournalDevSecondVar"));

Log4j2 アペンダー

以前に、Lookupsを使用して変数を構成ファイルに挿入する方法を見たでしょう。しかし、メッセージが通過する媒体を変更したいかもしれません。直接コンソールを使用する代わりに、メッセージが永久に保持されるように、ファイルやデータベースリポジトリのようなものを望むかもしれません。Log4j2は多くのAppenderを提供しており、Appenderについての詳細を得るためにlog4j2のドキュメントを参照できます。簡単に言えば、以下はすべてのLog4j2 Appenderのリストです。

  1. ConsoleAppender
  2. AsyncAppender
  3. FailoverAppender
  4. FileAppender
  5. FlumeAppender
  6. JDBCアペンダ
  7. JMSアペンダ
  8. JPAアペンダ
  9. メモリーマッピングされたファイルアペンダ
  10. NoSQLアペンダ
  11. OutputStreamAppender
  12. ランダムアクセスファイルアペンダ
  13. RewriteAppender
  14. ロールファイルアペンダ
  15. ロールランダムアクセスファイルアペンダ
  16. RoutingAppender
  17. SMTPアペンダ
  18. SocketAppender
  19. SyslogAppender

イベントを記録するために最も一般的に使用される媒体は、コンソール、ファイル、そしてデータベースです。ファイルはメッセージを保存できますが、データベースはそれらを監査するために使用される可能性があります。この目的のために、このセクションではJDBCAppenderがどのように効率的に使用できるかに焦点を当てます。

JDBCアペンダ

JDBCAppenderの主な目的は、JDBC接続を介してログイベントをリレーショナルテーブルに書き込むことです。このチュートリアルはその目的ではないため、接続プールの最適化方法について多くの時間を消費して説明することはありません。しかし、データベースにログイベントを書くのに役立つ完全な機能例は確実に得られます。それでは、本題に入る前に、JDBCAppenderを適切に設定するために必要なすべてのパラメータとその説明を見てみましょう。

パラメータ名タイプ説明
名前String必須、アペンダーの名前
例外を無視するブーリアンデフォルト値はtrueに設定されており、発生した例外はログに記録され、無視されます。falseの値は、例外が呼び出し元に伝播されることを意味します。
フィルターフィルターこのアペンダーによってログイベントが処理されるかどうかを判断するために使用されるフィルター。
バッファサイズ整数デフォルト値はゼロであり、これはログイベントに対してバッファリングが行われていないことを示しています。値が0より大きい場合、Appenderはログイベントをバッファし、バッファが指定された制限に達したときにフラッシュします。
接続ソースConnectionSource必要な接続は、データベース接続を取得すべき接続元です。
テーブル名String必要です。ログイベントを保存するテーブルの名前です。
カラム構成列構成[]必要な情報、追加の情報は、使用される列に設定され、各列にデータがどのように永続化されるかを指定することができます。これは複数の要素で処理できます。
パラメータ名タイプ説明
jndi名Stringjavax.sql.Datasourceがバインドされている必要な完全なプレフィックス付きJNDI名。
パラメータ名タイプ説明
クラスString必要なもの: JDBC接続を取得するためのスタティックファクトリメソッドを含むクラスの完全修飾名。
方法ブーリアン必要、JDBC接続を取得するための静的ファクトリメソッドの名前。
パラメータ名タイプ説明
名前String必須、データベースのカラム名
パターンStringログイベントがフォーマットされる任意の法的パターンを指定する能力
文字通りStringこの列にリテラル値を指定する能力(つまり、SEQ.NEXTVAL)
イベントタイムスタンプですブーリアンイベントがタイムスタンプを考慮するかどうかを示します
はUnicodeですブーリアンUnicode目的のため、詳細についてはLog4j2のドキュメントを参照してください。
isClobブーリアン文字列大オブジェクトを保存するためには、さらなる詳細についてLog4j2のドキュメントを参照してください。

JNDIを使用することが強制されているため、私たちの例はOracleデータベースとApache Tomcat 7の接続データソースを構成します。

  • もしあなたがOracleデータベースをあなたの環境にインストールしていないなら、できればインストールしていただけるとありがたいです。Oracleについてあまり詳しくない場合は、Express Editionのインストールをお勧めします。
  • あなたの環境にApache Tomcat 7をインストールします。
  • EclipseにMaven WebAppプロジェクトを作成してください。

  • プロジェクトが正常に作成されたことを確認し、pomでエラーに気付いた場合は、それを修正してください。
  • Log4j2の依存関係を追加します。
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-api</artifactId>
   <version>2.2</version>
</dependency>
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-core</artifactId>
   <version>2.2</version>
</dependency>
  • MySQLデータソース宣言を含むようにコンテキストを設定してください。Apacheのドキュメントによると、このファイルはWebアプリケーションのMETA-INFフォルダー内にあるべきです。

<Context path="/JournalDevWebLogging"
	privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<Resource name="jdbc/JournalDevDB" auth="Container"
			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
			url="jdbc:mysql://localhost:3306/journaldev" />
</Context>
  • データベースを設定し、ログテーブルを作成してください。

CREATE TABLE `logging` (
  `EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
  `EVENT_DATE` datetime DEFAULT NULL,
  `LEVEL` varchar(45) DEFAULT NULL,
  `LOGGER` varchar(45) DEFAULT NULL,
  `MSG` varchar(45) DEFAULT NULL,
  `THROWABLE` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`EVENT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • あなたのlog4j2.xmlを以下のように設定してください:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • 参照用のロガーを取得し、イベントをログに記録できるWebリソースを作成します。
package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
			Logger logger = LogManager.getLogger(JournalDevServlet.class);
			logger.trace("JournalDev Database Logging Message !");
	}
}
  • データソースの初期化が適切に行われることを保証するために、ServletContextListenerを任意で構成することができます。
package com.journaldev;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
public class JournalDevServletContextListener implements ServletContextListener{
	private InitialContext context = null;
	public void contextDestroyed(ServletContextEvent event) {
	}
	public void contextInitialized(ServletContextEvent event) {
		try {
			// Get initial context
			context = new InitialContext();
			// Get a reference for sub context env
			Context envContext = (Context)context.lookup("java:comp/env");
			// Get a reference for sub context jdbc and then locating the data source defined
			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("JournalDevDB"));
		} catch (NamingException e) {
			LogManager.getRootLogger().error(e);
		}
	}
}
  • web.xmlファイル内にサーブレットを定義してください。
  • アプリケーションを実行し、上記で定義されたサーブレットにアクセスします。以下のログが表示されます。
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product\11.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product\11.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\JournalDev\eclipse;;.
Mar 15, 2015 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:JournalDevWebLogging' did not find a matching property.
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:41 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1020 ms
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/journaldev; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:43 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1909 ms

Log4j2 フィルター

ログイベントを処理するためのLoggerConfig候補があったとしても、それを設定してログイベントをバックエンドのAppenderに渡さないようにすることができます。これはlog4j2フィルターによって実現できます。このセクションは、log4j2におけるフィルターの使用に関する侵襲的で膨大なチュートリアルを提供することを目的としていません。フィルターについてはそれぞれに多くの記事が必要です。しかしここでは、概念を学ぶために最もシンプルなフィルターの使い方を示します。使用できる最もシンプルなフィルターの1つはBurstFilterであり、これは最大制限に達した後にイベントを静かに破棄することで、LogEventsが処理される速度を制御するためのメカニズムを提供します。今のところ、BurstFilterを使用するために必要なすべての詳細が以下に示されています。

パラメータ名タイプ説明
レベルStringフィルタリングされるメッセージのレベル
評価浮遊する許可する1秒あたりの平均イベント数
マックスバースト整数イベントが平均レートを超えたためにフィルタリングされる前に発生できる最大イベント数。デフォルトはレートの10倍です。
マッチでStringフィルターが一致したときに取るべきアクション。受け入れる、拒否する、または中立のいずれかです。デフォルトは中立です。
ミスマッチ時Stringフィルターが一致しない場合のアクション。受け入れる、拒否する、またはニュートラルのいずれかです。デフォルトはニュートラルです。

さて、あなたのデータベースアペンダー内のBurstFilterの位置を見てください。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<BurstFilter level="TRACE" rate="20" maxBurst="2"/>
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • データベースアペンダはバーストフィルターを考慮しますが、コンソールアペンダは考慮しません。
  • コンソールロガーを使用すると、すべてのログイベントが記録されますが、データベースアペンダーはバーストフィルターによって一部のイベントが処理されず、記録されません。
  • このLogEventsの拒否は、使用されるLoggerがLogEventsの処理候補であるにもかかわらず達成されます。これは、以下のJournalDevServletに示されているように非常に合理的です。

package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Logger logger = LogManager.getLogger(JournalDevServlet.class);
		for(int i = 0 ; i < 1000 ; i++){
			logger.trace("Index :: "+i+" :: JournalDev Database Logging Message !");
			LogManager.getRootLogger().error("Index :: "+i+" :: JournalDev Database Logging Message !");
		}
	}
}

そのLoggerConfigsはそこに投げられたログイベントを処理する候補ですが、フィルターがいくつかのイベントを処理およびログするのを防いでいます。ログの全体的な概念を理解するために、これをロギングスペースの概念として追加することができます。

Log4j2 レイアウト

異なるAppenderがログイベントを消費し、各Appenderの性質によるため、レイアウトはログイベントを消費する人のニーズに応じた形式でLogEventを形成するように作られています。Log4j 1.xやLogback APIでは、ログイベントのレイアウト変換は文字列にされていましたが、Log4j2のレイアウトは異なる変換方法を考慮しています。それはLogEventをバイトの配列に変換することです。この新しいタイプの変換は、バイト配列が正しい値を含むことを保証するためにCharsetを構成することを強制します。Apache Log4j2の公式サイトに戻り、レイアウトとLog4j2が提供するさまざまなタイプについてさらに確認することを強くお勧めします。このセクションでは、ほとんどの開発者によって常に使用されている最も有名なレイアウトを考慮します。おそらくあなたも聞いたことがあるでしょう。それはPatternLayoutです。

Log4j2 パターンレイアウト

パターンレイアウトは、LogEventをフォーマットすることを目的とした、構成可能で柔軟な文字列パターンです。この種のフォーマットは変換パターンの概念に依存しています。このセクションでは、パターンレイアウトが提供する最も重要な機能を示します。変換パターンは、C言語のprintfが提供する変換パターンに関連しています。一般に、変換パターンはリテラルテキストとフォーマット制御式(変換指定子と呼ばれる)で構成されます。以下の図は、変換パターンがどのような部分から構成されているかを示しています。

上の図は変換パターンを簡素化するための試みですが、レイアウトや特にパターンレイアウトの詳細についてはApache Log4j2のドキュメントを参照する方が良いでしょう。また、ログイベントについても上記を参照し、メッセージのフォーマットに使用されている変換パターンを常に確認することができます。

どのLog4j2レベルを使用すべきですか

あなたが自分に問うかもしれない最も重要な質問は、特定のログイベントレベルをいつ使用すべきかということです。開発の分野では、DEBUGログイベントを使用するのが一般的ですが、プロダクションではINFOまたはWARNレベルを使用するべきです。以下の表は、どのケースでどのlog4j2レベルを使用するべきかを示します。

ログイベントレベル使用すべき時
オフイベントが記録されないとき
致命的重大なエラーが発生すると、アプリケーションが続行できなくなります。
エラーアプリケーションにエラーが発生した場合、回復可能な可能性があります
警告エラーにつながる可能性のあるイベントが発生したとき
情報情報提供のためのイベントがあるとき
デバッグ一般的なデバッグイベントが必要なとき
トレースアプリケーションの流れを捕捉する、通常は細かいデバッグメッセージがあるとき
すべてすべてのイベントが記録されるべき時

Log4j2 チュートリアルの概要

Log4j2はApacheのロギングフレームワークの改良版です。Log4j2はLog4j1.xから新しい機能とパフォーマンスの向上を提供しています。このlog4j2のチュートリアルは、すべてを一箇所で理解するのに役立つことを目的としています。これらの概念のいくつかは一度にすべてを説明するのがそれほど簡単ではないため、概念を説明し、さらなる明確化のためのサンプルを用意する努力を封じることにしました。アペンダー、フィルター、レイアウト、およびルックアップはこのルールの対象です。 いくつかの重要なポイント 下記のアプリケーションを実行するために障害を避けるために、以下を確認してください:

  • あなたのEclipse IDEはMavenに対応しています。
  • あなたのApache Tomcatには、Apache Homeのlibフォルダー内にmysql-connector JARが含まれています。
  • あなたはMavenの使い方を知っています。

Apache Log4j 2 のサンプルプロジェクトをダウンロード

これでlog4j2チュートリアルは終了です。アプリケーションでLog4j2を使用するために必要な重要なポイントのほとんどがカバーされていることを願っています。

関連記事: