package com.ycsoft.commons.log4j; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.log4j.RollingFileAppender; import org.apache.log4j.helpers.CountingQuietWriter; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; //继承log4j的RollingFileAppender类 public class MttangLog4jRollingFileAppender extends RollingFileAppender { private long nextRollover = 0; private static Map<String, BeginFileData> fileMaps = new HashMap<String, BeginFileData>(); private static final SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd"); // synchronization not necessary since doAppend is alreasy synched public void rollOver() { File target; File file; int maxBackupIndexLeng = String.valueOf(maxBackupIndex).length(); if (qw != null) { long size = ((CountingQuietWriter) qw).getCount(); LogLog.debug("rolling over count=" + size); // if operation fails, do not roll again until // maxFileSize more bytes are written nextRollover = size + maxFileSize; } LogLog.debug("maxBackupIndex=" + maxBackupIndex); String nowDateString = sdf.format(new Date()); String newFileName = (fileName.indexOf(".") != -1 ? fileName.substring( 0, fileName.lastIndexOf(".")) : fileName); boolean renameSucceeded = true; // If maxBackups <= 0, then there is no file renaming to be done. if (maxBackupIndex > 0) { // Delete the oldest file, to keep Windows happy. file = new File(newFileName + '.' + nowDateString + '.' + getIndex(maxBackupIndex, maxBackupIndexLeng)); if (file.exists()) { renameSucceeded = file.delete(); } // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, // 2} for (int i = maxBackupIndex - 1; (i >= 1 && renameSucceeded); i--) { file = new File(newFileName + '.' + nowDateString + '.' + getIndex(i, maxBackupIndexLeng)); if (file.exists()) { target = new File(newFileName + '.' + nowDateString + '.' + getIndex(i + 1, maxBackupIndexLeng)); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); } } if (renameSucceeded) { BeginFileData beginFileData = fileMaps.get(fileName); System.out.println("fileName= " + fileName + "\t beginFileData=" + beginFileData); // 在每天一个日志目录的方式下,检测日期是否变更了,如果变更了就要把变更后的日志文件拷贝到变更后的日期目录下。 if (newFileName.indexOf(nowDateString) == -1 && beginFileData.getFileName().indexOf("yyyy-MM-dd") != -1) { newFileName = beginFileData.getFileName().replace( "yyyy-MM-dd", nowDateString); newFileName = (newFileName.indexOf(".") != -1 ? newFileName .substring(0, newFileName.lastIndexOf(".")) : newFileName); } target = new File(newFileName + '.' + nowDateString + '.' + getIndex(1, maxBackupIndexLeng)); this.closeFile(); file = new File(fileName); LogLog.debug("Renaming file " + file + " to " + target); renameSucceeded = file.renameTo(target); // // if file rename failed, reopen file with append = true // if (!renameSucceeded) { try { this.setFile(fileName, true, bufferedIO, bufferSize); } catch (IOException e) { LogLog.error("setFile(" + fileName + ", true) call failed.", e); } } } } // // if all renames were successful, then // if (renameSucceeded) { try { // This will also close the file. This is OK since multiple // close operations are safe. this.setFile(fileName, false, bufferedIO, bufferSize); nextRollover = 0; } catch (IOException e) { LogLog .error("setFile(" + fileName + ", false) call failed.", e); } } } /** * 文件个数的长度补零,如果文件个数为10那么文件的个数长度就是2位,第一个文件就是01,02,03.... * * @param i * @param maxBackupIndexLeng * @return */ private String getIndex(int i, int maxBackupIndexLeng) { String index = String.valueOf(i); int len = index.length(); for (int j = len; j < maxBackupIndexLeng; j++) { index = "0" + index; } return index + ".log"; } /** * This method differentiates RollingFileAppender from its super class. * * @since 0.9.0 */ protected void subAppend(LoggingEvent event) { super.subAppend(event); if (fileName != null && qw != null) { String nowDate = sdf.format(new Date()); // 检测日期是否已经变更了,如果变更了就要重创建日期目录 if (!fileMaps.get(fileName).getDate().equals(nowDate)) { rollOver(); return; } long size = ((CountingQuietWriter) qw).getCount(); if (size >= maxFileSize && size >= nextRollover) { rollOver(); } } } @Override public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException { String nowDate = sdf.format(new Date()); // 如果文件路径包含了“yyyy-MM-dd”就是每天一个日志目录的方式记录日志(第一次的时候) if (fileName.indexOf("yyyy-MM-dd") != -1) { String beginFileName = fileName; fileName = fileName.replace("yyyy-MM-dd", nowDate); fileMaps.put(fileName, new BeginFileData(beginFileName, nowDate)); } BeginFileData beginFileData = fileMaps.get(fileName); // 检测日期是否已经变更了,如果变更了就要把原始的字符串给fileName变量,把变更后的日期做为开始日期 if (!beginFileData.getDate().equals(nowDate)) { // 获取出第一次的文件名 beginFileData.setDate(nowDate); fileName = beginFileData.getFileName().replace("yyyy-MM-dd", nowDate); fileMaps.put(fileName, beginFileData); } // D:/data/test/yyyy-MM-dd/test.log 替换yyyy-MM-dd为当前日期。 super.setFile(fileName, append, this.bufferedIO, this.bufferSize); } class BeginFileData { public BeginFileData(String fileName, String date) { super(); this.fileName = fileName; this.date = date; } private String fileName; private String date; public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } } }