S-JIS[2013-12-18] 変更履歴
Javaでログを出力する為のインターフェースを定義しているslf4jのメモ。
treeさんの『javaのロガーが多すぎて訳が解らないので整理してみました』によると、slf4jは(commons-loggingと同様の)ログ出力のインターフェースを定義しているライブラリーらしい。
ログを実際に出力するライブラリーとして、java.util.loggingやlog4j・logbackがあるらしい。
slf4j+logbackの例。
まず、slf4jとlogback-classicを使ったサンプルプロジェクトを作るgradleスクリプトは以下の通り。
apply plugin: 'java' apply plugin: 'eclipse' defaultTasks 'jar' group = 'com.example' version = '0.1-SNAPSHOT' sourceCompatibility = 1.7 targetCompatibility = 1.7 def defaultEncoding = 'UTF-8' [compileJava, compileTestJava]*.options*.encoding = defaultEncoding repositories { mavenCentral() } dependencies { compile group: 'org.slf4j', name : 'slf4j-api', version: '1.7.5' compile group: 'ch.qos.logback', name : 'logback-classic', version: '1.0.12' testCompile 'junit:junit:4.11' } eclipse.classpath.file { whenMerged { classpath -> classpath.entries.findAll { entry -> entry.kind == 'output' }*.path = 'classes' } }
> gradle eclipse
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class LogExample { private static final Logger LOG = LoggerFactory.getLogger(LogExample.class);
public static void main(String[] args) { LOG.info("info-message1"); } }
classesディレクトリー(コンパイル先)の直下にlogback.xmlを置いておくとlogbackの定義として読み込まれる。
(src/main/resourcesの下にファイルを置いておくと、コンパイルしたときにclassesの下にコピーされる)
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <target>System.out</target> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level %msg%n</pattern> </encoder> </appender> <root> <level value="INFO" /> <appender-ref ref="STDOUT" /> </root> </configuration>
logback.xmlにファイルへの出力の設定を加える例。
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <target>System.out</target> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>D:/tmp/logger-example.txt</file> <encoder> <charset>UTF-8</charset> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level %msg%n</pattern> </encoder> </appender> <root> <level value="INFO" /> <appender-ref ref="STDOUT" /> <appender-ref ref="FILE" /> </root> </configuration>
FileAppenderでは、file要素でログファイル名を指定する。
この例ではappender-refでSTDOUTとFILEの両方を指定しているので、コンソールとファイルの両方に同じログが出力される。
FileAppenderのサブクラスにRollingFileAppenderというクラスもある。
時刻やファイルサイズでログファイル名を切り替えられる。
任意のタイミングでログファイルをクリアする例。
RollingFileAppenderを使用し、triggeringPolicyとrollingPolicyに独自クラスを指定する。
triggeringPolicyはファイル切り替えのトリガーとなる条件判定を行う。(SizeBasedTriggeringPolicyはファイルサイズを判定している)
rollingPolicyはファイルの切り替えを行う。(TimeBasedRollingPolicyは時刻付きのファイル名にリネームする)
package com.example.logger; import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; import ch.qos.logback.core.rolling.TriggeringPolicyBase;
public class MyTriggeringPolicy<E> extends TriggeringPolicyBase<E> { private static final AtomicBoolean reset = new AtomicBoolean();
public static void reset() { reset.set(true); }
@Override public boolean isTriggeringEvent(File activeFile, E event) { boolean r = reset.getAndSet(false); // System.out.printf("MyTriggeringPolicy#isTriggeringEvent(%s, %s)\t%b%n", activeFile, event, r); return r; } }
LOG.info()等のログ出力メソッドが呼ばれる度にisTriggeringEventメソッドが呼ばれる。
今回はresetメソッドを用意しておき、これが呼ばれるとトリガーをオンにする。(isTriggeringEventメソッドでtrueを返す。これにより、rollingPolicyのrolloverメソッドが呼ばれる)
package com.example.logger; import java.io.File; import ch.qos.logback.core.rolling.RollingPolicyBase; import ch.qos.logback.core.rolling.RolloverFailure;
public class MyRollingPolicy extends RollingPolicyBase { @Override public void rollover() throws RolloverFailure { String fileName = getActiveFileName(); File file = new File(fileName); boolean r = file.delete(); // System.out.println("MyRollingPolicy#rollover()\tdelete=" + r); } @Override public String getActiveFileName() { String fileName = super.getParentsRawFileProperty(); //logback.xmlのappender要素で指定されているファイル名 return fileName; } }
今回の例では、rolloverメソッドの中で現在のログファイルを削除している。
(TimeBasedRollingPolicyではログファイルをリネームしている)
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <target>System.out</target> <encoder> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level %msg%n</pattern> </encoder> </appender> <appender name="RESET_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>D:/tmp/logger-mypollicy.txt</file> <triggeringPolicy class="com.example.logger.MyTriggeringPolicy" /> <rollingPolicy class="com.example.logger.MyRollingPolicy" /> <encoder> <charset>UTF-8</charset> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level %msg%n</pattern> </encoder> </appender> <root> <level value="INFO" /> <appender-ref ref="STDOUT" /> <appender-ref ref="RESET_FILE" /> </root> </configuration>
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
public class LogExample { private static final Logger LOG = LoggerFactory.getLogger(LogExample.class);
public static void main(String[] args) { LOG.info("info-message1"); MyTriggeringPolicy.reset(); //ログファイルをクリアする LOG.info("info-message2"); } }
この例では1つ目のメッセージを出力した後にログファイルをクリアしているので、2つ目のメッセージだけがログファイルに記録される。