Mercurial Hosting > luan
comparison src/org/eclipse/jetty/util/RolloverFileOutputStream.java @ 802:3428c60d7cfc
replace jetty jars with source
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Wed, 07 Sep 2016 21:15:48 -0600 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 801:6a21393191c1 | 802:3428c60d7cfc |
|---|---|
| 1 // | |
| 2 // ======================================================================== | |
| 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. | |
| 4 // ------------------------------------------------------------------------ | |
| 5 // All rights reserved. This program and the accompanying materials | |
| 6 // are made available under the terms of the Eclipse Public License v1.0 | |
| 7 // and Apache License v2.0 which accompanies this distribution. | |
| 8 // | |
| 9 // The Eclipse Public License is available at | |
| 10 // http://www.eclipse.org/legal/epl-v10.html | |
| 11 // | |
| 12 // The Apache License v2.0 is available at | |
| 13 // http://www.opensource.org/licenses/apache2.0.php | |
| 14 // | |
| 15 // You may elect to redistribute this code under either of these licenses. | |
| 16 // ======================================================================== | |
| 17 // | |
| 18 | |
| 19 package org.eclipse.jetty.util; | |
| 20 | |
| 21 import java.io.File; | |
| 22 import java.io.FileOutputStream; | |
| 23 import java.io.FilterOutputStream; | |
| 24 import java.io.IOException; | |
| 25 import java.io.OutputStream; | |
| 26 import java.text.SimpleDateFormat; | |
| 27 import java.util.Calendar; | |
| 28 import java.util.Date; | |
| 29 import java.util.GregorianCalendar; | |
| 30 import java.util.Locale; | |
| 31 import java.util.TimeZone; | |
| 32 import java.util.Timer; | |
| 33 import java.util.TimerTask; | |
| 34 | |
| 35 /** | |
| 36 * RolloverFileOutputStream | |
| 37 * | |
| 38 * This output stream puts content in a file that is rolled over every 24 hours. | |
| 39 * The filename must include the string "yyyy_mm_dd", which is replaced with the | |
| 40 * actual date when creating and rolling over the file. | |
| 41 * | |
| 42 * Old files are retained for a number of days before being deleted. | |
| 43 * | |
| 44 * | |
| 45 */ | |
| 46 public class RolloverFileOutputStream extends FilterOutputStream | |
| 47 { | |
| 48 private static Timer __rollover; | |
| 49 | |
| 50 final static String YYYY_MM_DD="yyyy_mm_dd"; | |
| 51 final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd"; | |
| 52 final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS"; | |
| 53 final static int ROLLOVER_FILE_RETAIN_DAYS = 31; | |
| 54 | |
| 55 private RollTask _rollTask; | |
| 56 private SimpleDateFormat _fileBackupFormat; | |
| 57 private SimpleDateFormat _fileDateFormat; | |
| 58 | |
| 59 private String _filename; | |
| 60 private File _file; | |
| 61 private boolean _append; | |
| 62 private int _retainDays; | |
| 63 | |
| 64 /* ------------------------------------------------------------ */ | |
| 65 /** | |
| 66 * @param filename The filename must include the string "yyyy_mm_dd", | |
| 67 * which is replaced with the actual date when creating and rolling over the file. | |
| 68 * @throws IOException | |
| 69 */ | |
| 70 public RolloverFileOutputStream(String filename) | |
| 71 throws IOException | |
| 72 { | |
| 73 this(filename,true,ROLLOVER_FILE_RETAIN_DAYS); | |
| 74 } | |
| 75 | |
| 76 /* ------------------------------------------------------------ */ | |
| 77 /** | |
| 78 * @param filename The filename must include the string "yyyy_mm_dd", | |
| 79 * which is replaced with the actual date when creating and rolling over the file. | |
| 80 * @param append If true, existing files will be appended to. | |
| 81 * @throws IOException | |
| 82 */ | |
| 83 public RolloverFileOutputStream(String filename, boolean append) | |
| 84 throws IOException | |
| 85 { | |
| 86 this(filename,append,ROLLOVER_FILE_RETAIN_DAYS); | |
| 87 } | |
| 88 | |
| 89 /* ------------------------------------------------------------ */ | |
| 90 /** | |
| 91 * @param filename The filename must include the string "yyyy_mm_dd", | |
| 92 * which is replaced with the actual date when creating and rolling over the file. | |
| 93 * @param append If true, existing files will be appended to. | |
| 94 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. | |
| 95 * @throws IOException | |
| 96 */ | |
| 97 public RolloverFileOutputStream(String filename, | |
| 98 boolean append, | |
| 99 int retainDays) | |
| 100 throws IOException | |
| 101 { | |
| 102 this(filename,append,retainDays,TimeZone.getDefault()); | |
| 103 } | |
| 104 | |
| 105 /* ------------------------------------------------------------ */ | |
| 106 /** | |
| 107 * @param filename The filename must include the string "yyyy_mm_dd", | |
| 108 * which is replaced with the actual date when creating and rolling over the file. | |
| 109 * @param append If true, existing files will be appended to. | |
| 110 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. | |
| 111 * @throws IOException | |
| 112 */ | |
| 113 public RolloverFileOutputStream(String filename, | |
| 114 boolean append, | |
| 115 int retainDays, | |
| 116 TimeZone zone) | |
| 117 throws IOException | |
| 118 { | |
| 119 | |
| 120 this(filename,append,retainDays,zone,null,null); | |
| 121 } | |
| 122 | |
| 123 /* ------------------------------------------------------------ */ | |
| 124 /** | |
| 125 * @param filename The filename must include the string "yyyy_mm_dd", | |
| 126 * which is replaced with the actual date when creating and rolling over the file. | |
| 127 * @param append If true, existing files will be appended to. | |
| 128 * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. | |
| 129 * @param dateFormat The format for the date file substitution. The default is "yyyy_MM_dd". | |
| 130 * @param backupFormat The format for the file extension of backup files. The default is "HHmmssSSS". | |
| 131 * @throws IOException | |
| 132 */ | |
| 133 public RolloverFileOutputStream(String filename, | |
| 134 boolean append, | |
| 135 int retainDays, | |
| 136 TimeZone zone, | |
| 137 String dateFormat, | |
| 138 String backupFormat) | |
| 139 throws IOException | |
| 140 { | |
| 141 super(null); | |
| 142 | |
| 143 if (dateFormat==null) | |
| 144 dateFormat=ROLLOVER_FILE_DATE_FORMAT; | |
| 145 _fileDateFormat = new SimpleDateFormat(dateFormat); | |
| 146 | |
| 147 if (backupFormat==null) | |
| 148 backupFormat=ROLLOVER_FILE_BACKUP_FORMAT; | |
| 149 _fileBackupFormat = new SimpleDateFormat(backupFormat); | |
| 150 | |
| 151 _fileBackupFormat.setTimeZone(zone); | |
| 152 _fileDateFormat.setTimeZone(zone); | |
| 153 | |
| 154 if (filename!=null) | |
| 155 { | |
| 156 filename=filename.trim(); | |
| 157 if (filename.length()==0) | |
| 158 filename=null; | |
| 159 } | |
| 160 if (filename==null) | |
| 161 throw new IllegalArgumentException("Invalid filename"); | |
| 162 | |
| 163 _filename=filename; | |
| 164 _append=append; | |
| 165 _retainDays=retainDays; | |
| 166 setFile(); | |
| 167 | |
| 168 synchronized(RolloverFileOutputStream.class) | |
| 169 { | |
| 170 if (__rollover==null) | |
| 171 __rollover=new Timer(RolloverFileOutputStream.class.getName(),true); | |
| 172 | |
| 173 _rollTask=new RollTask(); | |
| 174 | |
| 175 Calendar now = Calendar.getInstance(); | |
| 176 now.setTimeZone(zone); | |
| 177 | |
| 178 GregorianCalendar midnight = | |
| 179 new GregorianCalendar(now.get(Calendar.YEAR), | |
| 180 now.get(Calendar.MONTH), | |
| 181 now.get(Calendar.DAY_OF_MONTH), | |
| 182 23,0); | |
| 183 midnight.setTimeZone(zone); | |
| 184 midnight.add(Calendar.HOUR,1); | |
| 185 __rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L*60*60*24); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 /* ------------------------------------------------------------ */ | |
| 190 public String getFilename() | |
| 191 { | |
| 192 return _filename; | |
| 193 } | |
| 194 | |
| 195 /* ------------------------------------------------------------ */ | |
| 196 public String getDatedFilename() | |
| 197 { | |
| 198 if (_file==null) | |
| 199 return null; | |
| 200 return _file.toString(); | |
| 201 } | |
| 202 | |
| 203 /* ------------------------------------------------------------ */ | |
| 204 public int getRetainDays() | |
| 205 { | |
| 206 return _retainDays; | |
| 207 } | |
| 208 | |
| 209 /* ------------------------------------------------------------ */ | |
| 210 private synchronized void setFile() | |
| 211 throws IOException | |
| 212 { | |
| 213 // Check directory | |
| 214 File file = new File(_filename); | |
| 215 _filename=file.getCanonicalPath(); | |
| 216 file=new File(_filename); | |
| 217 File dir= new File(file.getParent()); | |
| 218 if (!dir.isDirectory() || !dir.canWrite()) | |
| 219 throw new IOException("Cannot write log directory "+dir); | |
| 220 | |
| 221 Date now=new Date(); | |
| 222 | |
| 223 // Is this a rollover file? | |
| 224 String filename=file.getName(); | |
| 225 int i=filename.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD); | |
| 226 if (i>=0) | |
| 227 { | |
| 228 file=new File(dir, | |
| 229 filename.substring(0,i)+ | |
| 230 _fileDateFormat.format(now)+ | |
| 231 filename.substring(i+YYYY_MM_DD.length())); | |
| 232 } | |
| 233 | |
| 234 if (file.exists()&&!file.canWrite()) | |
| 235 throw new IOException("Cannot write log file "+file); | |
| 236 | |
| 237 // Do we need to change the output stream? | |
| 238 if (out==null || !file.equals(_file)) | |
| 239 { | |
| 240 // Yep | |
| 241 _file=file; | |
| 242 if (!_append && file.exists()) | |
| 243 file.renameTo(new File(file.toString()+"."+_fileBackupFormat.format(now))); | |
| 244 OutputStream oldOut=out; | |
| 245 out=new FileOutputStream(file.toString(),_append); | |
| 246 if (oldOut!=null) | |
| 247 oldOut.close(); | |
| 248 //if(log.isDebugEnabled())log.debug("Opened "+_file); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 /* ------------------------------------------------------------ */ | |
| 253 private void removeOldFiles() | |
| 254 { | |
| 255 if (_retainDays>0) | |
| 256 { | |
| 257 long now = System.currentTimeMillis(); | |
| 258 | |
| 259 File file= new File(_filename); | |
| 260 File dir = new File(file.getParent()); | |
| 261 String fn=file.getName(); | |
| 262 int s=fn.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD); | |
| 263 if (s<0) | |
| 264 return; | |
| 265 String prefix=fn.substring(0,s); | |
| 266 String suffix=fn.substring(s+YYYY_MM_DD.length()); | |
| 267 | |
| 268 String[] logList=dir.list(); | |
| 269 for (int i=0;i<logList.length;i++) | |
| 270 { | |
| 271 fn = logList[i]; | |
| 272 if(fn.startsWith(prefix)&&fn.indexOf(suffix,prefix.length())>=0) | |
| 273 { | |
| 274 File f = new File(dir,fn); | |
| 275 long date = f.lastModified(); | |
| 276 if ( ((now-date)/(1000*60*60*24))>_retainDays) | |
| 277 f.delete(); | |
| 278 } | |
| 279 } | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 /* ------------------------------------------------------------ */ | |
| 284 @Override | |
| 285 public void write (byte[] buf) | |
| 286 throws IOException | |
| 287 { | |
| 288 out.write (buf); | |
| 289 } | |
| 290 | |
| 291 /* ------------------------------------------------------------ */ | |
| 292 @Override | |
| 293 public void write (byte[] buf, int off, int len) | |
| 294 throws IOException | |
| 295 { | |
| 296 out.write (buf, off, len); | |
| 297 } | |
| 298 | |
| 299 /* ------------------------------------------------------------ */ | |
| 300 /** | |
| 301 */ | |
| 302 @Override | |
| 303 public void close() | |
| 304 throws IOException | |
| 305 { | |
| 306 synchronized(RolloverFileOutputStream.class) | |
| 307 { | |
| 308 try{super.close();} | |
| 309 finally | |
| 310 { | |
| 311 out=null; | |
| 312 _file=null; | |
| 313 } | |
| 314 | |
| 315 _rollTask.cancel(); | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 /* ------------------------------------------------------------ */ | |
| 320 /* ------------------------------------------------------------ */ | |
| 321 /* ------------------------------------------------------------ */ | |
| 322 private class RollTask extends TimerTask | |
| 323 { | |
| 324 @Override | |
| 325 public void run() | |
| 326 { | |
| 327 try | |
| 328 { | |
| 329 RolloverFileOutputStream.this.setFile(); | |
| 330 RolloverFileOutputStream.this.removeOldFiles(); | |
| 331 | |
| 332 } | |
| 333 catch(IOException e) | |
| 334 { | |
| 335 // Cannot log this exception to a LOG, as RolloverFOS can be used by logging | |
| 336 e.printStackTrace(); | |
| 337 } | |
| 338 } | |
| 339 } | |
| 340 } |
