按日期生成文件夹,自动清理N天前的日志。并且可以设置每个文件最大内存为多少,以及当天允许生成的最大文件个数
API:log4j
主要步骤:继承log4j的org.apache.log4j.RollingFileAppender类,重写setFile、subAppend方法
配置文件:修改log4j的配置文件,将使用的类指向自己写的继承的类,改写日志文件目录格式
JAVA代码
1 package com.montnets.ljbank.util; 2 3 4 import java.io.File; 5 import java.io.IOException; 6 import java.text.ParseException; 7 import java.text.SimpleDateFormat; 8 import java.util.Date; 9 import java.util.HashMap; 10 import java.util.Map; 11 import java.util.regex.Matcher; 12 import java.util.regex.Pattern; 13 14 import org.apache.log4j.RollingFileAppender; 15 import org.apache.log4j.helpers.CountingQuietWriter; 16 import org.apache.log4j.helpers.LogLog; 17 import org.apache.log4j.spi.LoggingEvent; 18 19 import com.montnets.ljbank.constant.ConfigConstant; 20 21 //继承log4j的RollingFileAppender类 22 public class MyRollingFileAppender extends RollingFileAppender { 23 24 private long nextRollover = 0; 25 private static Map<String, BeginFileData> fileMaps = new HashMap<String, BeginFileData>(); 26 private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); 27 private static final SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); 28 29 public void rollOver () { 30 31 File target; 32 File file; 33 int maxBackupIndexLeng = String.valueOf(maxBackupIndex).length(); 34 if (qw != null) { 35 long size = ((CountingQuietWriter) qw).getCount(); 36 LogLog.debug("rolling over count=" + size); 37 nextRollover = size + maxFileSize; 38 } 39 //1 40 LogLog.debug("maxBackupIndex=" + maxBackupIndex); 41 String nowDateString = sdf.format(new Date()); 42 String newFileName = (fileName.indexOf(".") != -1 ? fileName.substring(0, 43 fileName.lastIndexOf(".")) : fileName); 44 45 boolean renameSucceeded = true; 46 String nowDateStr = sdf1.format(new Date()); 47 if (maxBackupIndex > 0) { 48 49 50 // file = new File(newFileName + '.' + nowDateString + '.' 51 // + getIndex(maxBackupIndex, maxBackupIndexLeng)); 52 53 file = new File(newFileName + '.' + nowDateStr + '.' 54 + getIndex(maxBackupIndex, maxBackupIndexLeng)); 55 56 if (file.exists()) { 57 renameSucceeded = file.delete(); 58 } 59 /** 60 * 删除最后一个文件,文件名+1 61 * */ 62 for (int i = maxBackupIndex - 1; (i >= 1 && renameSucceeded); i--) { 63 // file = new File(newFileName + '.' + nowDateString + '.' 64 // + getIndex(i, maxBackupIndexLeng)); 65 file = new File(newFileName + '.' + nowDateStr + '.' 66 + getIndex(i, maxBackupIndexLeng)); 67 if (file.exists()) { 68 //行动文件名 69 // target = new File(newFileName + '.' + nowDateString + '.' 70 // + getIndex(i + 1, maxBackupIndexLeng)); 71 target = new File(newFileName + '.' + nowDateStr + '.' 72 + getIndex(i + 1, maxBackupIndexLeng)); 73 LogLog.debug("Renaming file " + file + " to " + target); 74 renameSucceeded = file.renameTo(target); 75 } 76 } 77 78 if (renameSucceeded) { 79 BeginFileData beginFileData = fileMaps.get(fileName); 80 // 在每天一个日志目录的方式下,检测日期是否变更了,如果变更了就要把变更后的日志文件拷贝到变更后的日期目录下。 81 String pattern = "yyyy/MM/dd"; 82 if (newFileName.indexOf(nowDateString) == -1 83 && beginFileData.getFileName().indexOf(pattern) != -1) { 84 newFileName = beginFileData.getFileName().replace(pattern, 85 nowDateString); 86 newFileName = (newFileName.indexOf(".") != -1 ? newFileName 87 .substring(0, newFileName.lastIndexOf(".")) : newFileName); 88 } 89 // target = new File(newFileName + '.' + nowDateString + '.' 90 // + getIndex(1, maxBackupIndexLeng)); 91 target = new File(newFileName + '.' + nowDateStr + '.' 92 + getIndex(1, maxBackupIndexLeng)); 93 this.closeFile(); 94 file = new File(fileName); 95 LogLog.debug("Renaming file " + file + " to " + target); 96 97 renameSucceeded = file.renameTo(target); 98 if (!renameSucceeded) { 99 try { 100 this.setFile(fileName, true, bufferedIO, bufferSize); 101 } catch (IOException e) { 102 LogLog.error("setFile(" + fileName + ", true) call failed.", e); 103 } 104 } 105 } 106 } 107 if (renameSucceeded) { 108 109 try { 110 111 this.setFile(fileName, false, bufferedIO, bufferSize); 112 nextRollover = 0; 113 } catch (IOException e) { 114 LogLog.error("setFile(" + fileName + ", false) call failed.", e); 115 } 116 } 117 //删除指定日期前文件 118 //清理指定日期前的日志 119 String rootDir = (fileName.indexOf("/") != -1 ? fileName.substring(0, 120 fileName.indexOf("/")) : fileName); 121 long expireTime = ConfigConstant.MAXDAYS*24*60*60*1000L; //ConfigConstant.MAXDAYS是从配置文件中读取的一个常量,表示日志保留天数 122 cleanExpireFiles(rootDir,expireTime); 123 } 124 125 /** 126 * 文件个数的长度补零,如果文件个数为10那么文件的个数长度就是2位,第一个文件就是01,02,03.... 127 * 128 * @param i 129 * @param maxBackupIndexLeng 130 * @return 131 */ 132 private String getIndex (int i, int maxBackupIndexLeng) { 133 String index = String.valueOf(i); 134 int len = index.length(); 135 for (int j = len; j < maxBackupIndexLeng; j++) { 136 index = "0" + index; 137 } 138 return index + ".log"; 139 } 140 141 /** 142 * This method differentiates RollingFileAppender from its super class. 143 * 144 * @since 0.9.0 145 */ 146 protected void subAppend (LoggingEvent event) { 147 super.subAppend(event); 148 if (fileName != null && qw != null) { 149 150 String nowDate = sdf.format(new Date()); 151 // 检测日期是否已经变更了,如果变更了就要重创建日期目录 152 if (!fileMaps.get(fileName).getDate().equals(nowDate)) { 153 rollOver(); 154 return; 155 } 156 157 long size = ((CountingQuietWriter) qw).getCount(); 158 if (size >= maxFileSize && size >= nextRollover) { 159 rollOver(); 160 } 161 } 162 } 163 164 private void cleanExpireFiles(String savePath,long expireTime) { 165 //日志根目录 166 File fileRootDir= new File(savePath); 167 if(!fileRootDir.exists()){ 168 return; 169 } 170 //遍历根目录下的文件夹 171 //如果文件是n天前的就删除 172 //当前时间 173 long currentTime =System.currentTimeMillis(); 174 File file = null; 175 try{ 176 177 File[] files = fileRootDir.listFiles(); 178 if(files != null && files.length > 0){ 179 for(int i = 0; i< files.length; i++){ 180 file = files[i]; 181 long fileTime = file.lastModified(); 182 if(file.isDirectory()){ 183 cleanExpireFiles(file.getAbsolutePath(),expireTime); 184 //文件夹内文件为空,则删除成功 185 file.delete(); 186 }else{ 187 //获取文件中的日期 188 String fileTimeStr = getRqStr(file.getName()); 189 Date fileDate = null; 190 try { 191 if(fileTimeStr !=null){ 192 fileDate =sdf1.parse(fileTimeStr); 193 fileTime = fileDate.getTime(); 194 } 195 } catch (ParseException e) { 196 fileTime = currentTime; 197 // fileTime = file.lastModified(); 198 } 199 //如果文件最后更新时间是N天前就删除 200 if(currentTime - fileTime > expireTime){ 201 file.delete(); 202 } 203 } 204 } 205 } 206 }catch (Exception e) { 207 LogLog.error("删除过期日志失败!", e); 208 } 209 } 210 211 @Override 212 public synchronized void setFile (String fileName, boolean append, 213 boolean bufferedIO, int bufferSize) throws IOException { 214 215 String pattern = "yyyy/MM/dd"; 216 String nowDate = sdf.format(new Date()); 217 // 如果文件路径包含了“yyyy-MM-dd”就是每天一个日志目录的方式记录日志(第一次的时候) 218 if (fileName.indexOf(pattern) != -1) { 219 String beginFileName = fileName; 220 fileName = fileName.replace(pattern, nowDate); 221 fileMaps.put(fileName, new BeginFileData(beginFileName, nowDate)); 222 } 223 BeginFileData beginFileData = fileMaps.get(fileName); 224 // 检测日期是否已经变更了,如果变更了就要把原始的字符串给fileName变量,把变更后的日期做为开始日期 225 if (!beginFileData.getDate().equals(nowDate)) { 226 // 获取出第一次的文件名 227 beginFileData.setDate(nowDate); 228 fileName = beginFileData.getFileName().replace(pattern, nowDate); 229 fileMaps.put(fileName, beginFileData); 230 } 231 232 // D:/data/test/yyyy-MM-dd/test.log 替换yyyy-MM-dd为当前日期。 233 File file = new File(fileName); 234 File parentFile = file.getParentFile(); 235 if (!parentFile.exists()) { 236 parentFile.mkdirs(); 237 } 238 239 super.setFile(fileName, append, this.bufferedIO, this.bufferSize); 240 } 241 242 /** 243 * 获取文件中的日期 244 * @param mes 245 * @return 246 */ 247 public static String getRqStr(String mes){ 248 String format = ".*([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]).*"; 249 String yms = null; 250 Pattern pattern = Pattern.compile(format); 251 Matcher matcher = pattern.matcher(mes); 252 if (matcher.matches()) { 253 pattern = Pattern.compile(".*(\\d{4}-\\d{2}-\\d{2}).*"); 254 matcher = pattern.matcher(mes); 255 if (matcher.matches()) { 256 yms = matcher.group(1); 257 } 258 return yms; 259 } 260 return yms; 261 262 } 263 public static void main(String[] args) { 264 String rootDir = "E:\\dell\\workspaces\\MyEclipse 10\\ljBank\\logger"; 265 long expireTime = 1*24*60*60*1000L; 266 new MyRollingFileAppender().cleanExpireFiles(rootDir,expireTime); 267 } 268 269 private class BeginFileData { 270 271 public BeginFileData (String fileName, String date) { 272 super(); 273 this.fileName = fileName; 274 this.date = date; 275 } 276 277 private String fileName; 278 private String date; 279 280 public String getFileName () { 281 return fileName; 282 } 283 public void setFileName (String fileName) { 284 this.fileName = fileName; 285 } 286 public String getDate () { 287 return date; 288 } 289 public void setDate (String date) { 290 this.date = date; 291 } 292 } 293 }
log4j.properties
log4j.rootLogger=console,logfile log4j.additivity.org.apache=true log4j.logger.org.apache=off log4j.logger.com.mchange=off # 配置为继承RollingFileAppender类重写其方法的子类 log4j.appender.logfile=com.montnets.ljbank.util.MyRollingFileAppender log4j.appender.logfile.File=logger/yyyy/MM/dd/ljBankLog.log log4j.appender.logfile.Threshold=INFO # 每个日志文件的最大内存 log4j.appender.logfile.MaxFileSize=20MB # 一天内允许生成日志文件的最大个数 log4j.appender.logfile.maxBackupIndex=30 log4j.appender.logfile.layout=org.apache.log4j.PatternLayout log4j.appender.logfile.layout.ConversionPattern=[%p]%d{yy/MM/dd HH\:mm\:ss\:SSS} %m%n