All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.util.RolloverFileOutputStream Maven / Gradle / Ivy

There is a newer version: 11.0.0.beta1
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.util; 

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

/** 
 * RolloverFileOutputStream.
 *
 * 

* This output stream puts content in a file that is rolled over every 24 hours. * The filename must include the string "yyyy_mm_dd", which is replaced with the * actual date when creating and rolling over the file. *

*

* Old files are retained for a number of days before being deleted. *

*/ public class RolloverFileOutputStream extends FilterOutputStream { private static Timer __rollover; final static String YYYY_MM_DD="yyyy_mm_dd"; final static String ROLLOVER_FILE_DATE_FORMAT = "yyyy_MM_dd"; final static String ROLLOVER_FILE_BACKUP_FORMAT = "HHmmssSSS"; final static int ROLLOVER_FILE_RETAIN_DAYS = 31; private RollTask _rollTask; private SimpleDateFormat _fileBackupFormat; private SimpleDateFormat _fileDateFormat; private final TimeZone _timeZone; private final String _filename; private File _file; private boolean _append; private int _retainDays; /* ------------------------------------------------------------ */ /** * @param filename The filename must include the string "yyyy_mm_dd", * which is replaced with the actual date when creating and rolling over the file. * @throws IOException if unable to create output */ public RolloverFileOutputStream(String filename) throws IOException { this(filename,true,ROLLOVER_FILE_RETAIN_DAYS); } /* ------------------------------------------------------------ */ /** * @param filename The filename must include the string "yyyy_mm_dd", * which is replaced with the actual date when creating and rolling over the file. * @param append If true, existing files will be appended to. * @throws IOException if unable to create output */ public RolloverFileOutputStream(String filename, boolean append) throws IOException { this(filename,append,ROLLOVER_FILE_RETAIN_DAYS); } /* ------------------------------------------------------------ */ /** * @param filename The filename must include the string "yyyy_mm_dd", * which is replaced with the actual date when creating and rolling over the file. * @param append If true, existing files will be appended to. * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. * @throws IOException if unable to create output */ public RolloverFileOutputStream(String filename, boolean append, int retainDays) throws IOException { this(filename,append,retainDays,TimeZone.getDefault()); } /* ------------------------------------------------------------ */ /** * @param filename The filename must include the string "yyyy_mm_dd", * which is replaced with the actual date when creating and rolling over the file. * @param append If true, existing files will be appended to. * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. * @param zone the timezone for the output * @throws IOException if unable to create output */ public RolloverFileOutputStream(String filename, boolean append, int retainDays, TimeZone zone) throws IOException { this(filename,append,retainDays,zone,null,null); } /* ------------------------------------------------------------ */ /** * @param filename The filename must include the string "yyyy_mm_dd", * which is replaced with the actual date when creating and rolling over the file. * @param append If true, existing files will be appended to. * @param retainDays The number of days to retain files before deleting them. 0 to retain forever. * @param zone the timezone for the output * @param dateFormat The format for the date file substitution. The default is "yyyy_MM_dd". * @param backupFormat The format for the file extension of backup files. The default is "HHmmssSSS". * @throws IOException if unable to create output */ public RolloverFileOutputStream(String filename, boolean append, int retainDays, TimeZone zone, String dateFormat, String backupFormat) throws IOException { this(filename,append,retainDays,zone,dateFormat,backupFormat,Calendar.getInstance(zone)); } RolloverFileOutputStream(String filename, boolean append, int retainDays, TimeZone zone, String dateFormat, String backupFormat, Calendar now) throws IOException { super(null); _timeZone = zone; if (dateFormat==null) dateFormat=ROLLOVER_FILE_DATE_FORMAT; _fileDateFormat = new SimpleDateFormat(dateFormat); if (backupFormat==null) backupFormat=ROLLOVER_FILE_BACKUP_FORMAT; _fileBackupFormat = new SimpleDateFormat(backupFormat); _fileBackupFormat.setTimeZone(zone); _fileDateFormat.setTimeZone(zone); if (filename!=null) { filename=filename.trim(); if (filename.length()==0) filename=null; } if (filename==null) throw new IllegalArgumentException("Invalid filename"); File testfile = new File(filename); _filename=testfile.getCanonicalPath(); _append=append; _retainDays=retainDays; synchronized(RolloverFileOutputStream.class) { if (__rollover==null) __rollover=new Timer(RolloverFileOutputStream.class.getName(),true); // Calculate Today's Midnight, based on Configured TimeZone (will be in past, even if by a few milliseconds) setFile(now); // This will schedule the rollover event to the next midnight scheduleNextRollover(now); } } /* ------------------------------------------------------------ */ /** * Get the "start of day" for the provided DateTime at the zone specified. * * @param cal the date time to calculate from * @return start of the day of the date provided */ public static Calendar toMidnight(Calendar cal) { Calendar ret = Calendar.getInstance(); ret.setTimeZone(cal.getTimeZone()); ret.setTime(cal.getTime()); ret.set(Calendar.HOUR_OF_DAY, 0); ret.set(Calendar.MINUTE, 0); ret.set(Calendar.SECOND, 0); ret.set(Calendar.MILLISECOND, 0); // next days midnight ret.add(Calendar.DAY_OF_MONTH, 1); return ret; } /* ------------------------------------------------------------ */ private void scheduleNextRollover(Calendar now) { _rollTask = new RollTask(); // Establish next day's midnight of provided calendar Calendar midnight = toMidnight(now); // Schedule next rollover event to occur, based on local machine's Unix Epoch milliseconds long delay = midnight.getTimeInMillis() - now.getTimeInMillis(); __rollover.schedule(_rollTask,delay); } /* ------------------------------------------------------------ */ public String getFilename() { return _filename; } /* ------------------------------------------------------------ */ public String getDatedFilename() { if (_file==null) return null; return _file.toString(); } /* ------------------------------------------------------------ */ public int getRetainDays() { return _retainDays; } /* ------------------------------------------------------------ */ synchronized void setFile(Calendar now) throws IOException { // Check directory File file=new File(_filename); File dir= new File(file.getParent()); if (!dir.isDirectory() || !dir.canWrite()) throw new IOException("Cannot write log directory "+dir); // Is this a rollover file? String filename=file.getName(); int i=filename.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD); if (i>=0) { file=new File(dir, filename.substring(0,i)+ _fileDateFormat.format(now.getTime()) + filename.substring(i+YYYY_MM_DD.length())); } if (file.exists()&&!file.canWrite()) throw new IOException("Cannot write log file "+file); // Do we need to change the output stream? if (out==null || !file.equals(_file)) { // Yep _file=file; if (!_append && file.exists()) file.renameTo(new File(file.toString()+"."+_fileBackupFormat.format(now.getTime()))); OutputStream oldOut=out; out=new FileOutputStream(file.toString(),_append); if (oldOut!=null) oldOut.close(); //if(log.isDebugEnabled())log.debug("Opened "+_file); } } /* ------------------------------------------------------------ */ void removeOldFiles(Calendar now) { if (_retainDays>0) { // Establish expiration time, based on configured TimeZone now.add(Calendar.DAY_OF_MONTH, (-1)*_retainDays); long expired = now.getTimeInMillis(); File file= new File(_filename); File dir = new File(file.getParent()); String fn=file.getName(); int s=fn.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD); if (s<0) return; String prefix=fn.substring(0,s); String suffix=fn.substring(s+YYYY_MM_DD.length()); String[] logList=dir.list(); for (int i=0;i=0) { File f = new File(dir,fn); if(f.lastModified() < expired) { f.delete(); } } } } } /* ------------------------------------------------------------ */ @Override public void write (byte[] buf) throws IOException { out.write (buf); } /* ------------------------------------------------------------ */ @Override public void write (byte[] buf, int off, int len) throws IOException { out.write (buf, off, len); } /* ------------------------------------------------------------ */ @Override public void close() throws IOException { synchronized(RolloverFileOutputStream.class) { try{super.close();} finally { out=null; _file=null; } if (_rollTask != null) { _rollTask.cancel(); } } } /* ------------------------------------------------------------ */ private class RollTask extends TimerTask { @Override public void run() { try { synchronized(RolloverFileOutputStream.class) { Calendar now = Calendar.getInstance(_timeZone); RolloverFileOutputStream.this.setFile(now); RolloverFileOutputStream.this.scheduleNextRollover(now); RolloverFileOutputStream.this.removeOldFiles(now); } } catch(Throwable t) { // Cannot log this exception to a LOG, as RolloverFOS can be used by logging t.printStackTrace(System.err); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy