blob: 39ea9f7ef47bdc020a02bd98ed6bce2b460b3b95 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sentry.provider.db.log.appender;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Writer;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.LoggingEvent;
public class RollingFileWithoutDeleteAppender extends FileAppender {
/**
* The default maximum file size is 10MB.
*/
protected long maxFileSize = 10 * 1024 * 1024;
private long nextRollover = 0;
/**
* The default constructor simply calls its {@link FileAppender#FileAppender
* parents constructor}.
*/
public RollingFileWithoutDeleteAppender() {
super();
}
/**
* Instantiate a RollingFileAppender and open the file designated by
* <code>filename</code>. The opened filename will become the output
* destination for this appender.
* <p>
* If the <code>append</code> parameter is true, the file will be appended to.
* Otherwise, the file desginated by <code>filename</code> will be truncated
* before being opened.
*/
public RollingFileWithoutDeleteAppender(Layout layout, String filename,
boolean append) throws IOException {
super(layout, getLogFileName(filename), append);
}
/**
* Instantiate a FileAppender and open the file designated by
* <code>filename</code>. The opened filename will become the output
* destination for this appender.
* <p>
* The file will be appended to.
*/
public RollingFileWithoutDeleteAppender(Layout layout, String filename)
throws IOException {
super(layout, getLogFileName(filename));
}
/**
* Get the maximum size that the output file is allowed to reach before being
* rolled over to backup files.
*/
public long getMaximumFileSize() {
return maxFileSize;
}
/**
* Implements the usual roll over behaviour.
* <p>
* <code>File</code> is renamed <code>File.yyyyMMddHHmmss</code> and closed. A
* new <code>File</code> is created to receive further log output.
*/
// synchronization not necessary since doAppend is already synched
public void rollOver() {
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;
}
this.closeFile(); // keep windows happy.
String newFileName = getLogFileName(fileName);
try {
// This will also close the file. This is OK since multiple
// close operations are safe.
this.setFile(newFileName, false, bufferedIO, bufferSize);
nextRollover = 0;
} catch (IOException e) {
if (e instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
LogLog.error("setFile(" + newFileName + ", false) call failed: " + e.getMessage(), e);
}
}
public synchronized void setFile(String fileName, boolean append,
boolean bufferedIO, int bufferSize) throws IOException {
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
if (append) {
File f = new File(fileName);
((CountingQuietWriter) qw).setCount(f.length());
}
}
/**
* Set the maximum size that the output file is allowed to reach before being
* rolled over to backup files.
* <p>
* This method is equivalent to {@link #setMaxFileSize} except that it is
* required for differentiating the setter taking a <code>long</code> argument
* from the setter taking a <code>String</code> argument by the JavaBeans
* {@link java.beans.Introspector Introspector}.
*
* @see #setMaxFileSize(String)
*/
public void setMaximumFileSize(long maxFileSize) {
this.maxFileSize = maxFileSize;
}
/**
* Set the maximum size that the output file is allowed to reach before being
* rolled over to backup files.
* <p>
* In configuration files, the <b>MaxFileSize</b> option takes an long integer
* in the range 0 - 2^63. You can specify the value with the suffixes "KB",
* "MB" or "GB" so that the integer is interpreted being expressed
* respectively in kilobytes, megabytes or gigabytes. For example, the value
* "10KB" will be interpreted as 10240.
*/
public void setMaxFileSize(String value) {
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
}
protected void setQWForFiles(Writer writer) {
this.qw = new CountingQuietWriter(writer, errorHandler);
}
/**
* This method differentiates RollingFileAppender from its super class.
*/
protected void subAppend(LoggingEvent event) {
super.subAppend(event);
if (fileName != null && qw != null) {
long size = ((CountingQuietWriter) qw).getCount();
if (size >= maxFileSize && size >= nextRollover) {
rollOver();
}
}
}
// Mangled file name. Append the current timestamp
private static String getLogFileName(String oldFileName) {
return getFileNameWithoutTimestamp(oldFileName) + "."
+ Long.toString(System.currentTimeMillis());
}
/**
* Remove trailing timestamp from filename
* @param fileName original filename with or without trailing timestamp
* @return Filename without trailing timestamp
*/
private static String getFileNameWithoutTimestamp(String fileName) {
if (fileName.matches("^.*\\.\\d+$")) {
return fileName.substring(0, fileName.lastIndexOf('.'));
} else {
return fileName;
}
}
}