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つ目のメッセージだけがログファイルに記録される。