ないわー。なんで Log4j 2.0 使ってないの?
何が変わったの?
ロギングライブラリとしての基本的な考え方は変わっていない。Logger のインスタンスをクラスごとに作ったり、Appender を関連付けてコンソールやファイルに出力したり、trace/debug/info/warn/error といったログレベルを使い分けたり。
けれども、全体的に見直しがはかられて、「いまどきのロギングライブラリ」になっている。
というか、一言で言うと、SLF4J っぽくなっている。
おさらい: Log4j 1.2 ではこうやってた
まずは Log4j の jar ファイルを持ってくる。Maven を使っている場合は、POM に依存ライブラリとして以下を追加していた。
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
次は設定ファイルだ。log4j.xml という名前の XML ファイルを作って、クラスパスが通っている場所に置くのがいちばん手早い。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="console" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p [%t]: %m%n" /> </layout> </appender> <root> <level value="debug" /> <appender-ref ref="console" /> </root> </log4j:configuration>
準備ができたらいよいよ Java でコーディング。Logger のインスタンスを作って、ログ出力用のメソッドにメッセージを渡す。
import org.apache.log4j.Logger; public class Main { private static final Logger LOG = Logger.getLogger(Main.class); public static void main(String[] args) { MemoryUsage usage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); LOG.info("ヒープ使用量: " + usage.getUsed() + "/" + usage.getMax()); } }
……。
いまどきこんなログ出力してたらいけませんよ。
Log4j 2.0 だとどうなるの?
大枠は変わらない。ここでもまずは参照する jar を持ってこよう。Maven の場合は、こんな感じで 2 つ追加する。
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.0-beta3</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.0-beta3</version> </dependency>
次に設定ファイル。これまでとは微妙に違う、log4j2.xml というファイル名で作成する。
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <appenders> <Console name="console"> <PatternLayout pattern="%-5level [%t]: %msg%n" /> </Console> </appenders> <loggers> <root level="debug"> <appender-ref ref="console" /> </root> </loggers> </configuration>
appenders 要素と loggers 要素が新たに登場している (ともに複数形の -s が付いていることに注意)。一段インデントが深くなったけど、かわりに個々のアペンダやロガーは Log4j 1.2 のときより少し短く書けるようになった。
最後に Java のソース。
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Main { private static final Logger LOG = LogManager.getLogger(Main.class); public static void main(String[] args) { MemoryUsage usage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); LOG.info("ヒープ使用量: {}/{}", usage.getUsed(), usage.getMax()); } }
今までと変わったのは、以下のポイント。
新メソッドはじめました
Log4j 2.0 では、これまでのフィードバックを反映して他にも様々な新機能が用意されている。
詳しくは公式サイトのドキュメントを眺めてもらうとして、ここでは、すぐに使えそうな新設のログ出力メソッドについて紹介しておく。
几帳面な人は、メソッドの入り口と出口で TRACE レベルのログを出す、ということをやっているかもしれない。今までは trace() を使っていたと思うが、Log4j 2.0 では専用のログ出力メソッドが新設された。
public int add(int a, int b) { LOG.entry(a, b); int sum = a + b; return LOG.exit(sum); }
こんな感じで、入り口で entry() にメソッドの引数を渡したり、戻り値を return する前に exit() を通すと、下記のような定型のログが出力される。なお、exit() は、ログを出力するだけで、渡された引数をそのまま返すメソッドになっている。
TRACE [main]: entry parms(100, 200) TRACE [main]: exit with (300)
同様に、例外を catch したときに ERROR レベルのログを出すための catching() とか、例外を投げるときに使うための throwing() とかもある。
あ、そうそう。Log4j 2.0 の PatternLayout では、デフォルトだと例外のメッセージやスタックトレースが出力されないので注意したい。下記のように、パターンの最後に %ex と書いておくと、1.2 の時と同様にメッセージとスタックトレースが出るようになる。
<PatternLayout pattern="%-5level [%t]: %msg%n%ex" />
なんかめんどくさくなったのか、と思われたかもしれないが、その代わり、スタックトレースの行数を指定できるようになっている。例えば次のように {5} を付けると、例外メッセージとスタックトレースあわせて最初の 5 行だけ出力されるようになる。
<PatternLayout pattern="%-5level [%t]: %msg%n%ex{5}" />
互換性がないのがいやな場合は?
ここまで見てきたように、Log4j 2.0 は従来の Log4j 1.2 と互換性がない。パッケージ名が変わっていたり、なくなったメソッドがあったり。MDC と NDC が統合されて ThreadContext になった、みたいな変更もある。
Log4j 2.0 に乗り換えてみたいけど、Log4j 1.2 で書いてきた既存のコードを全部直すのはちょっとなぁ……と思われるかもしれない。が、そんなあなたのために、Log4j 2.0 に Log4j 1.2 互換の API をラッパーとしてかぶせることもできるようになっている。
使い方は互換 API の jar を追加するだけ。Maven の場合は、Log4j 2.0 のライブラリに加えて、下記を追加するだけでいい。
<dependency> <groupId>org.apache.logging.log4j.adapters</groupId> <artifactId>log4j12-api</artifactId> <version>2.0-beta3</version> </dependency>
ただし、あくまで Log4j 1.2 の皮を被るだけなので、設定ファイルは Logj 2.0 の形式で用意する必要がある。
おわりに
POM の記述例を見て気付かれたかもしれないが、実はまだ Log4j 2.0 はベータ版。そのため、製品にいきなり使うのは不安、ということはあるかもしれない。しかし、現状でもふつーに動いているので、少なくとも個人で書くコードなら Log4j 2.0 の利用をお勧めしたい。
可変長引数や高パフォーマンスを求めて SLF4J を使ったことのある人は、Log4j 2.0 を見て「うわ、SLF4J にそっくり!」と感じるだろう。API とロガー実装で jar が分離された点とか、ログメッセージのプレースホルダが {} なところとか。言い換えると、そういう人は Log4j 2.0 へ乗り換えても苦労しないと思う。
「えっ、じゃぁ SLF4J でいいじゃん」って? それはまぁ正しい。が、その一方で、本当は SLF4J を使いたいんだけど職場力学的に「SLF4J にしよう」と言えず悶々としている人には朗報だ。これからは、「Log4J のバージョンを最新のやつにしましょう」と言えばすむのだから。