现在的位置: 首页 > 综合 > 正文

Log4j的扩展

2013年11月11日 ⁄ 综合 ⁄ 共 13393字 ⁄ 字号 评论关闭
一、业务需求
  log4j的DailyRollingFileAppender只能实现指定时间周期的log文件的备份,当指定周期结束时将现在的log文件加上指定的后缀后,重新开始写下一个周期的log文件。但是我这次的业务中,日方对log文件的要求如下:
    1)、每天写一个log文件,文件的后缀为yyyyMMdd
    2)、只保存七天的log文件,以前的log文件删除
二、设计
类图
  DailyRollingBackupFileAppender继承FileAppender实现了主要功能,但是备份的处理委托为BackupStrategy接口。DailyRollingFileFilter实现将指定的文件搜索出来,交给BackupStrategy处理。
三、实现
DailyRollingBackupFileAppender
package study.log;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FalseFileFilter;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

/**
 * <b>サブシステム名:</b>デジタルシネマ フレームワーク共通<br>
 * <b>機能名称:</b>ログ機能<br>
 * <b>処理説明:</b>週に保存Appenderを定義するクラス。<br>
 * <b>変更履歴:</b>2007/07/04 NTT-AT 新規<br>
 * <br>
 * 
 * 
@author NTT-AT
 * 
@since 1.0.0
 * 
@version 1.0.0 2007/07/04 初版
 * <p>
 
*/
public class DailyRollingBackupFileAppender extends FileAppender {

    /** バックアップ周期タイプル:エラー */
    
public static final int TOP_OF_TROUBLE = -1;

    /** バックアップ周期タイプル:分 */
    
public static final int TOP_OF_MINUTE = 0;

    /** バックアップ周期タイプル:時 */
    
public static final int TOP_OF_HOUR = 1;

    /** バックアップ周期タイプル:半日 */
    
public static final int HALF_DAY = 2;

    /** バックアップ周期タイプル:日 */
    
public static final int TOP_OF_DAY = 3;

    /** バックアップ周期タイプル:週 */
    
public static final int TOP_OF_WEEK = 4;

    /** バックアップ周期タイプル:月 */
    
public static final int TOP_OF_MONTH = 5;
    
    
/** バックアップ周期 */
    
private int backupCheckPeriod = 7;

    /** バックアップカレンダー */
    
private BackupCalendar backupCalendar = new BackupCalendar(-backupCheckPeriod);

    /** バックアップ策略 */
    
private BackupStrategy backupStrategy = new DeleteBackupStrategy();

    /** 日付パターン:デフォールトは'.'yyyy-MM-dd */
    
private String datePattern = "'.'yyyy-MM-dd";

    /** 新しいログファイル名 */
    
private String scheduledFilename;

    /** Rollingチェックタイミング */
    
private long nextCheck = System.currentTimeMillis() - 1;

    /** 現在の日時 */
    
private Date now = new Date();

    /** 日付フォーマット */
    
private SimpleDateFormat sdf;

    /** Rollingカレンダー */
    
private BackupCalendar rollingCalendar = new BackupCalendar();

    /** Rollingチェック周期 */
    
private int rollingCheckPeriod = TOP_OF_TROUBLE;

    /** タイムゾーン */
    
private static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");

    /** ファイルパス */
    
private File filePath = null;

    /**
     * <b>機能概要:</b> コンストラクタ。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>親のコンストラクタを呼び出す
     * </ul>
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public DailyRollingBackupFileAppender() {
        
super();
    }

    /**
     * <b>機能概要:</b> コンストラクタ。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>親のコンストラクタを呼び出す
     * </ul>
     * 
     * 
@param layout ライアウト
     * 
@param filename ファイル名
     * 
@param datePattern 日時パタン
     * 
@throws IOException ファイル異常
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public DailyRollingBackupFileAppender(Layout layout, String filename, String datePattern) throws IOException {
        
this(layout, filename, datePattern, 7new DeleteBackupStrategy());
    }

    /**
     * <b>機能概要:</b> コンストラクタ。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>親のコンストラクタを呼び出す
     * </ul>
     * 
     * 
@param layout ライアウト
     * 
@param filename ファイル名
     * 
@param datePattern 日時パタン
     * 
@param backupPeriod バックアップ周期
     * 
@param backupStrategy バックアップ策略
     * 
@throws IOException ファイル異常
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public DailyRollingBackupFileAppender(Layout layout,
                                          String filename,
                                          String datePattern,
                                          
int backupPeriod,
                                          BackupStrategy backupStrategy) 
throws IOException {
        
super(layout, filename, true);
        
this.datePattern = datePattern;
        activateOptions();
    }

    /**
     * <b>機能概要:</b> バックアップ策略を取得する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ策略を取得する
     * </ul>
     * 
@return BackupStrategy バックアップ策略
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public BackupStrategy getBackupStrategy() {
        
return backupStrategy;
    }

    /**
     * <b>機能概要:</b> バックアップ策略を設定する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ策略を設定する
     * </ul>
     * 
@param backupStrategy バックアップ策略
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public void setBackupStrategy(BackupStrategy backupStrategy) {
        
this.backupStrategy = backupStrategy;
    }

    /**
     * <b>機能概要:</b> バックアップ周期を取得する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ策略を取得する
     * </ul>
     * 
@return int バックアップ周期
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public int getBackupCheckPeriod() {
        
return backupCheckPeriod;
    }

    /**
     * <b>機能概要:</b> バックアップ周期を設定する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ周期を設定する
     * </ul>
     * 
@param backupCheckPeriod バックアップ周期
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public void setBackupCheckPeriod(int backupCheckPeriod) {
        
this.backupCheckPeriod = backupCheckPeriod;
        backupCalendar.setPeriod(
-backupCheckPeriod);
    }

    /**
     * <b>機能概要:</b> 日付パターンを設定する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>日付パターンを設定する
     * </ul>
     * 
@param pattern 日付パターン
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public void setDatePattern(String pattern) {
        datePattern 
= pattern;
    }

    /**
     * <b>機能概要:</b> 日付パターンを取得する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>日付パターンを取得する
     * </ul>
     * 
@return String 日付パターン
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
public String getDatePattern() {
        
return datePattern;
    }

    /**
     * <b>機能概要:</b> オプッションを設定する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>オプッションを設定する
     * </ul>
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    @Override
    
public void activateOptions() {
        
super.activateOptions();
        
if (datePattern != null && fileName != null) {
            now.setTime(System.currentTimeMillis());
            sdf 
= new SimpleDateFormat(datePattern);
            
int type = computeCheckPeriod();
            printPeriodicity(type);
            rollingCalendar.setType(type);
            backupCalendar.setType(type);
            File file 
= new File(fileName);
            scheduledFilename 
= fileName + sdf.format(new Date(file.lastModified()));
            filePath 
= new File(file.getAbsolutePath()).getParentFile();
        } 
else {
            LogLog.error(
"Either File or DatePattern options are not set for appender [" + name + "].");
        }
    }

    /**
     * <b>機能概要:</b> バックアップ/Rolling周期タイプを記録する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ/Rolling周期タイプを記録する
     * </ul>
     * 
@param type バックアップ/Rolling周期タイプ
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
private void printPeriodicity(int type) {
        
switch (type) {
        
case TOP_OF_MINUTE:
            LogLog.debug(
"Appender [" + name + "] to be rolled every minute.");
            
break;
        
case TOP_OF_HOUR:
            LogLog.debug(
"Appender [" + name + "] to be rolled on top of every hour.");
            
break;
        
case HALF_DAY:
            LogLog.debug(
"Appender [" + name + "] to be rolled at midday and midnight.");
            
break;
        
case TOP_OF_DAY:
            LogLog.debug(
"Appender [" + name + "] to be rolled at midnight.");
            
break;
        
case TOP_OF_WEEK:
            LogLog.debug(
"Appender [" + name + "] to be rolled at start of week.");
            
break;
        
case TOP_OF_MONTH:
            LogLog.debug(
"Appender [" + name + "] to be rolled at start of every month.");
            
break;
        
default:
            LogLog.warn(
"Unknown periodicity for appender [" + name + "].");
        }
    }

    /**
     * <b>機能概要:</b> バックアップ/Rolling周期タイプを計算する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ/Rolling周期タイプを計算する
     * </ul>
     * 
@return int バックアップ/Rolling周期タイプ
     * 
     * 
@since 1.0.0
     * <p>
     
*/
    
protected int computeCheckPeriod() {
        BackupCalendar rollingCalendar 
= new BackupCalendar(gmtTimeZone, Locale.ENGLISH);
        Date epoch 
= new Date(0);
        
if (datePattern != null) {
            
for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
                SimpleDateFormat simpleDateFormat 
= new SimpleDateFormat(datePattern);
                simpleDateFormat.setTimeZone(gmtTimeZone); 
// do all date formatting in GMT
                String r0 = simpleDateFormat.format(epoch);
                rollingCalendar.setType(i);
                Date next 
= new Date(rollingCalendar.getNextCheckMillis(epoch));
                String r1 
= simpleDateFormat.format(next);
                
// logger.debug("Type = "+i+", r0 = "+r0+", r1 = "+r1);
                if (r0 != null && r1 != null && !r0.equals(r1)) {
                    
return i;
                }
            }
        }
        
return TOP_OF_TROUBLE; // Deliberately head for trouble...
    }

    /**
     * <b>機能概要:</b> バックアップ/Rollingの処理を行う。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ/Rollingの処理を行う
     * </ul>
     * 
@since 1.0.0
     * <p>
     
*/
    
void rollOver() {

        /* Compute filename, but only if datePattern is specified */
        
if (datePattern == null) {
            errorHandler.error(
"Missing DatePattern option in rollOver().");
            
return;
        }

        String datedFilename = fileName + sdf.format(now);
        
// It is too early to roll over because we are still within the
        
// bounds of the current interval. Rollover will occur once the
        
// next interval is reached.
        if (scheduledFilename.equals(datedFilename)) {
            
return;
        }

        // close current file, and rename it to datedFilename
        this.closeFile();

        File target = new File(scheduledFilename);
        
if (target.exists()) {
            target.delete();
        }

        File file = new File(fileName);
        
boolean result = file.renameTo(target);
        
if (result) {
            LogLog.debug(fileName 
+ " -> " + scheduledFilename);
        } 
else {
            LogLog.error(
"Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");
        }

        try {
            
// This will also close the file. This is OK since multiple
            
// close operations are safe.
            this.setFile(fileName, falsethis.bufferedIO, this.bufferSize);
        } 
catch (IOException e) {
            errorHandler.error(
"setFile(" + fileName + ", false) call failed.");
        }
        scheduledFilename 
= datedFilename;
        
        now.setTime(System.currentTimeMillis());
        Collection 
< ? > fileList = FileUtils.listFiles(filePath,
                                        
new DailyRollingFileFilter(fileName,
                                                                   datePattern,
                                                                   backupCheckPeriod,
                                                                   sdf.format(backupCalendar.getNextCheckDate(now))),
                                        FalseFileFilter.INSTANCE);
        
for (Object obj : fileList) {
            
try {
                backupStrategy.backup((File)obj);
            } 
catch (Exception e) {
                errorHandler.error(
"backup(" + obj + ") call failed.");
            }
        }
    }

    /**
     * <b>機能概要:</b> ログ内容を記録する。<br>
     * <br>
     * <b>処理詳細:</b> <br>
     * <ul>
     * <li>バックアップ/Rolling処理をチェックする
     * <li>ログ内容を記録する
     * </ul>
     * 
@param event ログイベント
     * 
@since 1.0.0
     * <p>
     
*/
    @Override
    
protected void subAppend(LoggingEvent event) {
        
long n = System.currentTimeMillis();
        
if (n >= nextCheck) {
            now.setTime(n);
            nextCheck 
= rollingCalendar.getNextCheckMillis(now);
            rollOver();
        }
        
super.subAppend(event);
    }

    /**
     * <b>サブシステム名:</b>デジタルシネマ フレームワーク共通<br>
     * <b>機能名称:</b>ログ機能<br>
     * <b>処理説明:</b>バックアップ/Rolling周期カレンダーを定義するクラス。<br>
     * <b>変更履歴:</b>2007/07/04 NTT-AT 新規<br>
     * <br>
     * 
     * 
@author NTT-AT
     * 
@since 1.0.0
     * 
@version 1.0.0 2007/07/04 初版
     * <p>
     
*/
    
class BackupCalendar extends GregorianCalendar {

        /** バージョンID */
        
private static final long serialVersionUID = 2882906031608620390L;
        
        
/** バックアップ/Rolling周期カレンダータイプ */
        
private int type = DailyRollingBackupFileAppender.TOP_OF_TROUBLE;

        /** バックアップ/Rolling周期 */
        
private int period = 1;
        
        
/**
         * <b>機能概要:</b> コンストラクタ。<br>
         * <br>
         * <b>処理詳細:</b> <br>
         * <ul>
         * <li>親のコンストラクタを呼び出す
         * </ul>
         * 
         * 
@since 1.0.0
         * <p>
         
*/
        BackupCalendar() {
            
super();
        }
        
        
/**
         * <b>機能概要:</b> コンストラクタ。<br>
         * <br>
         * <b>処理詳細:</b> <br>
         * <ul>
         * <li>親のコンストラクタを呼び出す
         * </ul>
         * 
         * 
@param period バックアップ/Rolling周期
         * 
@since 1.0.0
         * <p>
         
*/
        BackupCalendar(
int period) {
            
super();
            
this.period = period;
        }
        
        
/**
         * <b>機能概要:</b> コンストラクタ。<br>
         * <br>
         * <b>処理詳細:</b> <br>
         * <ul>
         * <li>親のコンストラクタを呼び出す
         * </ul>
         * 
@param

抱歉!评论已关闭.