LogbackのFixedWindowRollingPolicyで、日時ローテートする。

Logbackの、FixedWindowRollingPolicyを使って、日時ローテートしたいときに使えるTriggeringEvent。

package com.example;

import java.io.File;
import java.util.Date;

import ch.qos.logback.core.Context;
import ch.qos.logback.core.rolling.TriggeringPolicyBase;
import ch.qos.logback.core.rolling.helper.RollingCalendar;

public class TimeBasedTriggeringPolicy extends TriggeringPolicyBase {

	public static final String TOP_OF_MONTH = "MONTH";

	public static final String TOP_OF_WEEK = "WEEK";

	public static final String TOP_OF_DAY = "DAY";

	public static final String HALF_OF_DAY = "HALF_OF_DAY";

	public static final String TOP_OF_HOUR = "HOUR";

	public static final String TOP_OF_MINUTE = "MINUTE";

	public static final String TOP_OF_SECOND = "SECOND";

	RollingCalendar rc;

	long currentTime;

	Date lastCheck = new Date();

	long nextCheck;

	// indicate whether the time has been forced or not
	boolean isTimeForced = false;

	private String rollingPeriod;

	@Override
	public void start() {
		// find out period from the filename pattern
		String rollingPeriodDatePattern = null;
		if (rollingPeriod != null) {
			rollingPeriodDatePattern = determinRollingPeriodPattern(this.context);
		} else {
			String msg = "The RollingPeriod option must be set before using TimeBasedTriggeringPolicy. ";
			addWarn(msg);
			throw new IllegalStateException(msg);
		}

		if (rollingPeriodDatePattern == null) {
			throw new IllegalStateException(
					"RollingPeriod ["
							+ rollingPeriod
							+ "] is not valid value. The valid values are "
							+ "[MONTH, WEEK, DAY, HALF_OF_DAY, HOUR, MINUTE, SECOND].");
		}

		rc = new RollingCalendar();
		rc.init(rollingPeriodDatePattern);
		rc.printPeriodicity(this);

		// currentTime = System.currentTimeMillis();
		lastCheck.setTime(getCurrentTime());
		nextCheck = rc.getNextCheckMillis(lastCheck);

		super.start();
	}

	private String determinRollingPeriodPattern(Context context) {
		String pattern = null;
		if (rollingPeriod.equals(TOP_OF_MONTH)) {
			pattern = "yyyy-MM";
		} else if (rollingPeriod.equals(TOP_OF_WEEK)) {
			pattern = "yyyy-MM-E";
		} else if (rollingPeriod.equals(TOP_OF_DAY)) {
			pattern = "yyyy-MM-E-dd";
		} else if (rollingPeriod.equals(HALF_OF_DAY)) {
			pattern = "yyyy-MM-E-dd-a";
		} else if (rollingPeriod.equals(TOP_OF_HOUR)) {
			pattern = "yyyy-MM-E-dd-a-HH";
		} else if (rollingPeriod.equals(TOP_OF_MINUTE)) {
			pattern = "yyyy-MM-E-dd-a-HH-mm";
		} else if (rollingPeriod.equals(TOP_OF_SECOND)) {
			pattern = "yyyy-MM-E-dd-a-HH-mm-ss";
		}
		return pattern;
	}

	public boolean isTriggeringEvent(File activeFile, Object event) {
		long time = getCurrentTime();

		if (time >= nextCheck) {

			lastCheck.setTime(time);
			nextCheck = rc.getNextCheckMillis(lastCheck);

			return true;
		} else {
			return false;
		}
	}

	public long getCurrentTime() {
		// if time is forced return the time set by user
		if (isTimeForced) {
			return currentTime;
		} else {
			return System.currentTimeMillis();
		}
	}

	public void setCurrentTime(long timeInMillis) {
		currentTime = timeInMillis;
		isTimeForced = true;
	}

	public void setRollingPeriod(String rollingPeriod) {
		this.rollingPeriod = rollingPeriod;
	}
}

使い方は、logback.xml内のアペンダに以下のように、triggeringPolicyを指定すればOK。

 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <File>hoge.log</File>
   
   <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <FileNamePattern>hoge.%i.log.zip</FileNamePattern>
      <MinIndex>1</MinIndex>
      <MaxIndex>3</MaxIndex>
    </rollingPolicy>
   
   <triggeringPolicy class="com.example.TimeBasedTriggeringPolicy">
      <!-- MONTH, WEEK, DAY, HALF_OF_DAY, HOUR, MINUTE, SECOND -->
      <RollingPeriod>MINUTE</RollingPeriod>
   </triggeringPolicy>


   <layout class="ch.qos.logback.classic.PatternLayout">
     <Pattern>%d{yyyy/MM/dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</Pattern>
   </layout>

 </appender>