S-JIS[2013-12-18] 変更履歴

slf4j

Javaでログを出力する為のインターフェースを定義しているslf4jのメモ。


概要

treeさんの『javaのロガーが多すぎて訳が解らないので整理してみました』によると、slf4jは(commons-loggingと同様の)ログ出力のインターフェースを定義しているライブラリーらしい。
ログを実際に出力するライブラリーとして、java.util.loggingやlog4j・logbackがあるらしい。


logbackの例

slf4j+logbackの例。

まず、slf4jとlogback-classicを使ったサンプルプロジェクトを作るgradleスクリプトは以下の通り。

build.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

ログ出力サンプル(java):

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の下にコピーされる)

src/main/resources/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>

	<root>
		<level value="INFO" />
		<appender-ref ref="STDOUT" />
	</root>
</configuration>

logbackのFileAppender

logback.xmlにファイルへの出力の設定を加える例。

src/main/resources/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というクラスもある。

時刻やファイルサイズでログファイル名を切り替えられる。


logbackで動的にログファイルをクリアする例

任意のタイミングでログファイルをクリアする例。

RollingFileAppenderを使用し、triggeringPolicyとrollingPolicyに独自クラスを指定する。
triggeringPolicyはファイル切り替えのトリガーとなる条件判定を行う。(SizeBasedTriggeringPolicyはファイルサイズを判定している)
rollingPolicyはファイルの切り替えを行う。(TimeBasedRollingPolicyは時刻付きのファイル名にリネームする)

MyTriggeringPolicy.java:

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メソッドが呼ばれる)

MyRollingPolicy.java:

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ではログファイルをリネームしている)

src/main/resources/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="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>

ログ出力サンプル(java):

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


Java目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま