org.eclipse.jetty.util.RolloverFileOutputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
//
// ========================================================================
// Copyright (c) 1995-2014 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.Date;
import java.util.GregorianCalendar;
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 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
*/
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
*/
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
*/
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.
* @throws IOException
*/
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 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
*/
public RolloverFileOutputStream(String filename,
boolean append,
int retainDays,
TimeZone zone,
String dateFormat,
String backupFormat)
throws IOException
{
super(null);
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");
_filename=filename;
_append=append;
_retainDays=retainDays;
setFile();
synchronized(RolloverFileOutputStream.class)
{
if (__rollover==null)
__rollover=new Timer(RolloverFileOutputStream.class.getName(),true);
_rollTask=new RollTask();
Calendar now = Calendar.getInstance();
now.setTimeZone(zone);
GregorianCalendar midnight =
new GregorianCalendar(now.get(Calendar.YEAR),
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH),
23,0);
midnight.setTimeZone(zone);
midnight.add(Calendar.HOUR,1);
__rollover.scheduleAtFixedRate(_rollTask,midnight.getTime(),1000L*60*60*24);
}
}
/* ------------------------------------------------------------ */
public String getFilename()
{
return _filename;
}
/* ------------------------------------------------------------ */
public String getDatedFilename()
{
if (_file==null)
return null;
return _file.toString();
}
/* ------------------------------------------------------------ */
public int getRetainDays()
{
return _retainDays;
}
/* ------------------------------------------------------------ */
private synchronized void setFile()
throws IOException
{
// Check directory
File file = new File(_filename);
_filename=file.getCanonicalPath();
file=new File(_filename);
File dir= new File(file.getParent());
if (!dir.isDirectory() || !dir.canWrite())
throw new IOException("Cannot write log directory "+dir);
Date now=new Date();
// 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)+
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)));
OutputStream oldOut=out;
out=new FileOutputStream(file.toString(),_append);
if (oldOut!=null)
oldOut.close();
//if(log.isDebugEnabled())log.debug("Opened "+_file);
}
}
/* ------------------------------------------------------------ */
private void removeOldFiles()
{
if (_retainDays>0)
{
long now = System.currentTimeMillis();
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);
long date = f.lastModified();
if ( ((now-date)/(1000*60*60*24))>_retainDays)
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;
}
_rollTask.cancel();
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private class RollTask extends TimerTask
{
@Override
public void run()
{
try
{
RolloverFileOutputStream.this.setFile();
RolloverFileOutputStream.this.removeOldFiles();
}
catch(IOException e)
{
// Cannot log this exception to a LOG, as RolloverFOS can be used by logging
e.printStackTrace();
}
}
}
}