Log4j2は、他のロギングライブラリの呼び出しを、Log4j2に転送するコンポーネントを提供しています。
要は、他のロギングライブラリのふりをしてLog4j2へ流すコンポーネントがあるということですね。
以下のパターンがあります。
- Log4j 1.2 → Log4j2
- Commons Logging(JCL) → Log4j2
- SLF4J → Log4j2
- Log4j2 → SLF4J
最後だけ、逆ですね。これが+αの部分です。
それぞれのMaven依存関係は、こちらに網羅されています。
Maven and Ivy Artifacts
http://logging.apache.org/log4j/2.x/maven-artifacts.html
では、それぞれ簡単に使っていってみます。なお、基本的にこれらのAPIを動作させるのに、本物のライブラリ(例えばLog4j 1.2のJARファイル)は不要です。
以降の例では、少なくともpom.xmlに以下のLog4j2 Core APIの依存関係が定義されているものとします。
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.0-rc2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.0-rc2</version> </dependency>
また、log4j2.xmlは以下の定義とします。
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyy/MM/dd HH:mm:ss.SSS} %-5level - [log4j2] %msg%n%ex"/> </Console> </Appenders> <Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
*Log4j2で出力したことがわかりやすいように、[log4j2]を入れました
Log4j 1.2 → Log4j2
Log4j 1.2のAPIを使用して出力された内容を、Log4j2へ送るコンポーネントです。
Log4j 1.2 Bridge
http://logging.apache.org/log4j/2.x/log4j-1.2-api/index.html
Maven依存関係には、以下を加えます。
<!-- Log4j 1.2 Bridge --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>2.0-rc2</version> </dependency>
Log4j 1.2自体は不要です。他のライブラリの依存関係にLog4j 1.2が含まれている場合は、excludeして使うような利用方法になるでしょう。
サンプルコード。
src/main/java/org/littlewings/log4j2/Log4jToLog4j2.java
package org.littlewings.log4j2; import org.apache.log4j.Logger; public class Log4jToLog4j2 { public static void main(String... args) { Logger logger = Logger.getLogger(Log4jToLog4j2.class); logger.info("Log4j 1.2のAPIから、Log4j2へ出力"); } }
実行結果。
2014/06/28 22:02:00.784 INFO - [log4j2] Log4j 1.2のAPIから、Log4j2へ出力
Commons Logging → Log4j2
Commons LoggingのAPIを使用して出力された内容を、Log4j2へ送るコンポーネントです。
Commons Logging Bridge
http://logging.apache.org/log4j/2.x/log4j-jcl/index.html
Maven依存関係には、以下を加えます。
<!-- Log4j2 Commons Logging Bridge --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>2.0-rc2</version> </dependency>
サンプルコード。
src/main/java/org/littlewings/log4j2/JclToLog4j2.java
package org.littlewings.log4j2; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class JclToLog4j2 { public static void main(String... args) { Log logger = LogFactory.getLog(JclToLog4j2.class); logger.info("Commons LoggingのAPIから、Log4j2へ出力"); } }
実行結果。
2014/06/28 22:04:58.327 INFO - [log4j2] Commons LoggingのAPIから、Log4j2へ出力
Commons Loggingのふりをして、Log4j2へログ出力を転送できました。
SLF4J → Log4j2
SLF4JのAPIを使用して出力された内容を、Log4j2へ送るコンポーネントです。
Log4j 2 SLF4J Binding
http://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html
なぜ、Bridgeと言ったりBindingと言ったりするのか…?なお、後述のSLF4JへのAdapterと一緒に使用してはいけません。
Maven依存関係には、以下を加えます。
<!-- SLF4J Bridge --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.0-rc2</version> </dependency>
サンプルコード。
src/main/java/org/littlewings/log4j2/Slf4jToLog4j2.java
package org.littlewings.log4j2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Slf4jToLog4j2 { public static void main(String... args) { Logger logger = LoggerFactory.getLogger(Slf4jToLog4j2.class); logger.info("SLF4JのAPIから、Log4j2へ出力"); } }
実行結果。
2014/06/28 22:11:05.113 INFO - [log4j2] SLF4JのAPIから、Log4j2へ出力
こちらも、SLF4JのふりをしてLog4j2へログ出力を転送しています。
Log4j2 → SLF4J
先ほどまでとは、方向が逆のコンポーネントになります。
Log4j 2 to SLF4J Adapter
http://logging.apache.org/log4j/2.x/log4j-to-slf4j/index.html
これまでは、
「とあるロギングライブラリのAPI呼び出し」をLog4j2へ転送していましたが、
こちらは
「Log4j2の呼び出しをSLF4Jへ転送する」となります。
このため、先ほど紹介した「Log4j 2 SLF4J Binding」と一緒に使うと、Log4j2のAPIとSLF4JのAPIの行き来を繰り返すことになってしまうため、両方同時に使用してはいけません。
今回のMaven依存関係は、このようになります。
<!-- SLF4J Adapter --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.0-rc2</version> </dependency> <!-- SLF4J & Logback --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.2</version> </dependency>
「Log4j 2 to SLF4J Adapter」に加えて、SLF4J自体が必要です。裏は、Logbackとします。
ログ出力はLogbackなので、設定ファイルも用意しました。
src/main/resources/logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} %-5level - [SLF4J & Logback] %msg%n</pattern> </encoder> </appender> <root level="trace"> <appender-ref ref="STDOUT" /> </root> </configuration>
SLF4JとLogbackを自己主張。
サンプルコードは、このようになります。
src/main/java/org/littlewings/log4j2/Log4j2ToSlf4j.java
package org.littlewings.log4j2; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; public class Log4j2ToSlf4j { public static void main(String... args) { Logger logger = LogManager.getLogger(Log4j2ToSlf4j.class); logger.info("Log4j2のAPIから、SLF4Jへ出力"); } }
今までと違い、表に出てくるのはLog4j2のAPIとなります。
実行結果。
2014/06/28 22:18:23.460 INFO - [SLF4J & Logback] Log4j2のAPIから、SLF4Jへ出力
注意点としては
Use of this adapter may cause some loss of performance as the Log4j 2 Messages must be formatted before they can be passed to SLF4J. With Log4j 2 as the implementation these would normally be formatted only when they are accessed by a Filter or Appender.
http://logging.apache.org/log4j/2.x/log4j-to-slf4j/index.html
とのことなので、Log4j2のAPIからSLF4Jにメッセージを渡す時に、変換が必要なためパフォーマンスが犠牲になるとのことです。まあ、そりゃそうですよね…。
というか、このパターンは使うのでしょうか??
「Log4j 2 to SLF4J Adapter」はちょっと特殊ですが、その他のコンポーネントを使ってLog4j2が使えるといいなぁ、と。特にLog4j 1.2の置き換えに。