
org.butor.log4j.TimeBasedRollingPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of butor-log4j Show documentation
Show all versions of butor-log4j Show documentation
This project is an log4j specific module, contains utility specific to log4j.
The newest version!
/**
* Copyright 2013-2019 Butor Inc.
*
* Licensed 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.butor.log4j;
import static com.google.common.collect.Iterables.skip;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newLinkedHashSet;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.log4j.rolling.RolloverDescription;
import org.apache.log4j.rolling.RolloverDescriptionImpl;
import org.apache.log4j.rolling.helper.Action;
import org.apache.log4j.rolling.helper.ActionBase;
import com.google.common.primitives.Longs;
/**
* Same as org.apache.log4j.rolling.TimeBasedRollingPolicy, but we added the ability to delete old backup files.
*
* @author jdemers
*
*/
public class TimeBasedRollingPolicy extends TimeBasedRollingPolicyFromApacheLog4jExtras {
private Long timeDeltaForFilenameChange;
private int maxBackupIndex = 0;
private int numberOfBackupFilenamesToCheckForRegularCleanup = 24;
private int numberOfExtraBackupFilenamesToCheckForFirstCleanup = 365;
private boolean firstCleanupRan = false;
public void setMaxBackupIndex(int maxBackupIndex) {
this.maxBackupIndex = maxBackupIndex;
}
public void setNumberOfBackupFilenamesToCheckForRegularCleanup(int numberOfBackupFilenamesToCheckForRegularCleanup) {
this.numberOfBackupFilenamesToCheckForRegularCleanup = numberOfBackupFilenamesToCheckForRegularCleanup;
}
public void setNumberOfExtraBackupFilenamesToCheckForFirstCleanup(int numberOfExtraBackupFilenamesToCheckForFirstCleanup) {
this.numberOfExtraBackupFilenamesToCheckForFirstCleanup = numberOfExtraBackupFilenamesToCheckForFirstCleanup;
}
@Override
public RolloverDescription rollover(String currentActiveFile) {
RolloverDescription rolloverDescription = super.rollover(currentActiveFile);
if (rolloverDescription == null) {
// We'll wait until next rollover before deleting anything
return null;
}
if (maxBackupIndex <= 0) {
// This means cleanup is deactivated
return rolloverDescription;
}
String activeFileName = rolloverDescription.getActiveFileName();
boolean append = rolloverDescription.getAppend();
Action synchronous = rolloverDescription.getSynchronous();
final Action asynchronous = rolloverDescription.getAsynchronous();
Action newAsynchronous = new ActionBase() {
@Override
public boolean execute() throws IOException {
boolean success = true;
if (asynchronous != null) {
success &= asynchronous.execute();
}
int searchFileCount = maxBackupIndex + numberOfBackupFilenamesToCheckForRegularCleanup;
if (!firstCleanupRan) {
searchFileCount += numberOfExtraBackupFilenamesToCheckForFirstCleanup;
}
for (String backupFileToDelete : skip(getBackupFiles(searchFileCount), maxBackupIndex)) {
// This is not very nice, but it was also not very nice in org.apache.log4j.rolling.TimeBasedRollingPolicy
success &= deleteFileWithoutSuffix(backupFileToDelete, "");
success &= deleteFileWithoutSuffix(backupFileToDelete, ".gz");
success &= deleteFileWithoutSuffix(backupFileToDelete, ".zip");
}
firstCleanupRan = true;
return success;
}
private boolean deleteFileWithoutSuffix(String filename, String suffix) {
if (filename.endsWith(suffix)) {
File file = new File(filename.substring(0, filename.length() - suffix.length()));
if (file.exists()) {
return file.delete();
}
}
return true;
}
};
return new RolloverDescriptionImpl(activeFileName, append, synchronous, newAsynchronous);
}
private Iterable getBackupFiles(int searchFileCount) {
// The time delta could vary according to the current time.
// For instance, if we have a formatting with month precision ('yyyy-MM'), some months are longer than other.
// We would not want to miss a shorther month (February), because the delta was calculated on the month of January.
// So dividing the delta by 2 should be more than enough to prevent that
long timeIncrement = -getTimeDeltaForFilenameChange() / 2;
if (timeIncrement == 0) {
return Collections.emptyList();
}
List backupFiles = newArrayList();
for (String filename : getNextFilenames(searchFileCount, System.currentTimeMillis(), timeIncrement)) {
backupFiles.add(filename);
}
return backupFiles;
}
private Iterable getNextFilenames(int filenameCount, long fromTime, long timeIncrement) {
Set nextFilenames = newLinkedHashSet();
for (long time = fromTime; nextFilenames.size() < filenameCount; time += timeIncrement) {
nextFilenames.add(getFilename(time));
}
return nextFilenames;
}
private long getTimeDeltaForFilenameChange() {
if (timeDeltaForFilenameChange == null) {
long nextTimeThatFilenameChange = findNextTimeThatFilenameChange(System.currentTimeMillis());
long nextTimeThatFilenameChangeAgain = findNextTimeThatFilenameChange(nextTimeThatFilenameChange);
long timeDelta = nextTimeThatFilenameChangeAgain - nextTimeThatFilenameChange;
timeDeltaForFilenameChange = Long.valueOf(timeDelta);
}
return timeDeltaForFilenameChange.longValue();
}
private long findNextTimeThatFilenameChange(long baseTime) {
String baseFilename = getFilename(baseTime);
long lowerBound = baseTime;
long delta = 1;
long upperBound = baseTime + delta;
while (delta < Longs.MAX_POWER_OF_TWO && getFilename(upperBound).equals(baseFilename)) {
lowerBound = upperBound;
delta <<= 1;
upperBound = baseTime + delta;
}
if (!(delta < Longs.MAX_POWER_OF_TWO)) {
// The filename never changes!!
return baseTime;
}
while (upperBound - lowerBound > 1) {
long newBound = (lowerBound + upperBound) / 2;
if (getFilename(newBound).equals(baseFilename)) {
lowerBound = newBound;
} else {
upperBound = newBound;
}
}
return upperBound;
}
private String getFilename(long n) {
StringBuffer buf = new StringBuffer();
formatFileName(new Date(n), buf);
return buf.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy