Javaのロガーと言えば「SLF4J + LOGBack」が主流になってるかと思いますが、log4jやらcommons-logging、インターフェースにアダプタや実装など大分複雑になっています。今回は他のロガーは置いといて「SLF4J + LOGBack」の使い方のみまとめておきたいと思います。
事前準備
SLF4J Binary files と LOGBack Download からAPIをダウンロードします。
解凍すると複数のjarファイルが含まれていますが、slf4j-api-1.7.12.jar
をインターフェース、logback-classic-1.1.3.jar
とlogback-core-1.1.3.jar
を実装として使用します。その他は今回の内容からは省きますが、アダプターやブリッジと呼ばれるものです。
SLF4J + LOGBackについて
Javaでロギングを行うためには、基本的に「インターフェース」と「実装」が必要になります。SLF4Jがインターフェース、LOGBackが実装です。
初めに SLF4J Manual にもある通りHello Worldから試してみたいと思います。クラスパスには import しているslf4j-api-1.7.12.jar
のみ追加しました。
package com.tasknotes.slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Slf4jSample { public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Slf4jSample.class); logger.info("Hello World"); } }
実行すると以下のメッセージが出力されます。slf4jバインディングが見つからないというメッセージです。slf4jは実装が含まれておらず、ログを出力するためのインターフェースになりますのでこのような結果となります。
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
試しにslf4jバインディングの一つであるslf4j-simple-1.6.1.jar
をクラスパスに追加して実行してみましょう。そうすると次のように出力されるはずです。import には記述しなくてもOKです。
[main] INFO com.tasknotes.slf4j.Slf4jSample - Hello World
slf4j-simple-1.6.1.jar
はすべてのイベントをSystem.err
に対して出力するシンプルな実装のためのバインディングです。INFOレベルかそれ以上のメッセージのみが出力されます。
public static void main(String[] args) { Logger logger = LoggerFactory.getLogger(Slf4jSample.class); logger.trace("trace log"); logger.debug("debug log"); logger.info("info log"); logger.warn("warn log"); logger.error("error log"); } // 実行結果 - トレースとデバッグが出力されない [main] INFO com.tasknotes.slf4j.Slf4jSample - info log [main] WARN com.tasknotes.slf4j.Slf4jSample - warn log [main] ERROR com.tasknotes.slf4j.Slf4jSample - error log
LOGBackの使用
先程のslf4j-simple-1.6.1.jar
をクラスパスから除去して、logback-classic-1.1.3.jar
とlogback-core-1.1.3.jar
を追加して下さい。これは2つセットでないとエラーになります。上記と同じコードを実行すると次のような結果になります。
17:47:35.849 [main] DEBUG com.tasknotes.slf4j.Slf4jSample - debug log 17:47:35.853 [main] INFO com.tasknotes.slf4j.Slf4jSample - info log 17:47:35.854 [main] WARN com.tasknotes.slf4j.Slf4jSample - warn log 17:47:35.854 [main] ERROR com.tasknotes.slf4j.Slf4jSample - error log
※ 後述しますがTRACEが出力されないのは、logback.xmlを使用しない場合、デフォルトでDEBUG以上が対象となっているからです。
プレースホルダの使用とスタックトレースの出力
SLF4Jではプレースホルダが使用できます。波括弧を文字列中に埋め込み、カンマで区切って置き換える値を渡します。可変長引数になってますのでいくつでも渡す事が可能です。
logger.info("info log : UserId = {}, Name = {}", 1234, "山田"); // 実行結果 18:26:23.299 [main] INFO com.tasknotes.slf4j.Slf4jSample - info log : UserId = 1234, Name = 山田
スタックトレースを出力する場合にはカンマで区切って引数の末尾に渡してやります。プレースホルダを一緒に使用する場合でも引数の最後で Throwable を渡せば大丈夫です。
try { String hoge = null; hoge.length(); } catch(Exception e) { logger.error("error log ->", e); } // 実行結果 18:30:15.179 [main] ERROR com.tasknotes.slf4j.Slf4jSample - error log -> java.lang.NullPointerException: null at com.tasknotes.slf4j.Slf4jSample.main(Slf4jSample.java:16) ~[bin/:na]
このプレースホルだのおかげでLog4jでよく見かけていたif (logger.isDebugEnabled())
で不要な文字列結合を避けるための記述も不要になります。文字列生成をライブラリの内側で処理するようになり、ログを出力しない場合は文字列生成が行われなくなりました。
What is the fastest way of (not) logging? - SLF4J
設定ファイルのlogback.xmlについて
これまで見てきた通りlogback.xmlが無くても動きますが、使用することによってログの出力先と出力のフォーマット、出力レベルやメール送信などを指定する事ができます。logback.xmlはクラスパスが通っているところ(src/main/resource等)に作成して下さい。
基本的な設定内容は以下のようになります。設定内容ついての詳細は公式サイト 第3章 logbackの設定 を参照して下さい。
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} %-5level %logger{10} %msg%n</pattern> </encoder> </appender> <logger name="com.tasknotes.slf4j" level="INFO"/> <root level="TRACE"> <appender-ref ref="STDOUT" /> </root> </configuration>
appender
appender要素には「どこに、どのように」出力するのかを記述します。上記のサンプルではSTDOUTとなっていますが、FILEに出力したりMAIL送信を指定する事も出来ます。
root
root要素は一つだけ指定できます。level属性にはTRACE、DEBUG、INFO、WARN、ERROR、ALLまたはOFFのいずれかを指定でき、大文字小文字は区別しません。デフォルトはDEBUGです。appender-ref要素で指定したappenderがロガーに追加されます。ということは、定義してあるappenderをここで指定していないとログに出力されないので注意が必要です。
logger
ロガーの出力レベルを指定します。logger要素は複数指定する事が可能です。単純にログレベルの制御だけならroot要素だけでいいのですが、特定のパッケージだけレベルを変えたいという場合はlogger要素を指定します。上記の例ではcom.tasknotes.slf4j
パッケージのログレベルをINFO以上、root要素のレベルをTRACE以上としていますので、com.tasknotes.slf4j
パッケージから出力されるロガーはTRACEとDEBUGは出力されずINFO以上のみとなります。ここでもappender-ref要素を追加する事が可能です。