Skip to content

Commit

Permalink
[LOGMGR-30] Add ability to compress files when rotated if the suffix …
Browse files Browse the repository at this point in the history
…ends with .zip or .gz.
  • Loading branch information
jamezp committed May 5, 2017
1 parent bb5cae2 commit 042fe8d
Show file tree
Hide file tree
Showing 8 changed files with 530 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@

package org.jboss.logmanager.handlers;

import org.jboss.logmanager.ExtLogRecord;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.io.File;
import java.io.FileNotFoundException;

import java.util.logging.ErrorManager;

import org.jboss.logmanager.ExtLogRecord;

/**
* A file handler which rotates the log at a preset time interval. The interval is determined by the content of the
* suffix string which is passed in to {@link #setSuffix(String)}.
Expand All @@ -46,6 +41,7 @@ public class PeriodicRotatingFileHandler extends FileHandler {
private Period period = Period.NEVER;
private long nextRollover = Long.MAX_VALUE;
private TimeZone timeZone = TimeZone.getDefault();
private SuffixRotator suffixRotator = SuffixRotator.EMPTY;

/**
* Construct a new instance with no formatter and no output file.
Expand Down Expand Up @@ -124,17 +120,22 @@ protected void preWrite(final ExtLogRecord record) {
/**
* Set the suffix string. The string is in a format which can be understood by {@link java.text.SimpleDateFormat}.
* The period of the rotation is automatically calculated based on the suffix.
* <p>
* If the suffix ends with {@code .gz} or {@code .zip} the file will be compressed on rotation.
* </p>
*
* @param suffix the suffix
* @throws IllegalArgumentException if the suffix is not valid
*/
public void setSuffix(String suffix) throws IllegalArgumentException {
final SimpleDateFormat format = new SimpleDateFormat(suffix);
final SuffixRotator suffixRotator = SuffixRotator.parse(suffix);
final String dateSuffix = suffixRotator.getDatePattern();
final SimpleDateFormat format = new SimpleDateFormat(dateSuffix);
format.setTimeZone(timeZone);
final int len = suffix.length();
final int len = dateSuffix.length();
Period period = Period.NEVER;
for (int i = 0; i < len; i ++) {
switch (suffix.charAt(i)) {
switch (dateSuffix.charAt(i)) {
case 'y': period = min(period, Period.YEAR); break;
case 'M': period = min(period, Period.MONTH); break;
case 'w':
Expand All @@ -149,14 +150,15 @@ public void setSuffix(String suffix) throws IllegalArgumentException {
case 'K':
case 'h': period = min(period, Period.HOUR); break;
case 'm': period = min(period, Period.MINUTE); break;
case '\'': while (suffix.charAt(++i) != '\''); break;
case '\'': while (dateSuffix.charAt(++i) != '\''); break;
case 's':
case 'S': throw new IllegalArgumentException("Rotating by second or millisecond is not supported");
}
}
synchronized (outputLock) {
this.format = format;
this.period = period;
this.suffixRotator = suffixRotator;
final long now;
final File file = getFile();
if (file != null && file.lastModified() > 0) {
Expand All @@ -177,14 +179,22 @@ protected final String getNextSuffix() {
return nextSuffix;
}

/**
* Returns the file rotator for this handler.
*
* @return the file rotator
*/
SuffixRotator getSuffixRotator() {
return suffixRotator;
}

private void rollOver() {
try {
final File file = getFile();
// first, close the original file (some OSes won't let you move/rename a file that is open)
setFile(null);
// next, rotate it
final Path target = Paths.get(file.getAbsolutePath() + nextSuffix);
Files.move(file.toPath(), target, StandardCopyOption.REPLACE_EXISTING);
suffixRotator.rotate(file.toPath(), nextSuffix);
// start new file
setFile(file);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.logging.ErrorManager;

import org.jboss.logmanager.ExtLogRecord;
Expand Down Expand Up @@ -156,7 +152,11 @@ public void setFile(final File file) throws FileNotFoundException {
// Check for a rotate
if (rotateOnBoot && maxBackupIndex > 0 && file != null && file.exists() && file.length() > 0L) {
try {
rotate(file);
final String suffix = getNextSuffix();
final SuffixRotator suffixRotator = getSuffixRotator();
if (suffixRotator != SuffixRotator.EMPTY && suffix != null) {
suffixRotator.rotate(file.toPath(), suffix, maxBackupIndex);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -229,25 +229,12 @@ protected void preWrite(final ExtLogRecord record) {
}
// close the old file.
setFile(null);
rotate(file);
getSuffixRotator().rotate(file.toPath(), getNextSuffix(), maxBackupIndex);
// start with new file.
setFile(file);
} catch (IOException e) {
reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
}
}
}

private void rotate(final File file) throws IOException {
final Path fileWithSuffix = Paths.get(file.getAbsolutePath() + getNextSuffix());
Files.deleteIfExists(Paths.get(fileWithSuffix + "." + maxBackupIndex));
for (int i = maxBackupIndex - 1; i >= 1; i--) {
final Path src = Paths.get(fileWithSuffix + "." + i);
if (Files.exists(src)) {
final Path target = Paths.get(fileWithSuffix + "." + (i + 1));
Files.move(src, target, StandardCopyOption.REPLACE_EXISTING);
}
}
Files.move(file.toPath(), Paths.get(fileWithSuffix + ".1"), StandardCopyOption.REPLACE_EXISTING);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@
import java.io.FileNotFoundException;
import org.jboss.logmanager.ExtLogRecord;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.ErrorManager;

public class SizeRotatingFileHandler extends FileHandler {
Expand All @@ -39,7 +33,7 @@ public class SizeRotatingFileHandler extends FileHandler {
private int maxBackupIndex = 1;
private CountingOutputStream outputStream;
private boolean rotateOnBoot;
private String suffix;
private SuffixRotator suffixRotator = SuffixRotator.EMPTY;

/**
* Construct a new instance with no formatter and no output file.
Expand Down Expand Up @@ -146,7 +140,7 @@ public void setFile(final File file) throws FileNotFoundException {
// Check for a rotate
if (rotateOnBoot && maxBackupIndex > 0 && file != null && file.exists() && file.length() > 0L) {
try {
rotate(file);
suffixRotator.rotate(file.toPath(), maxBackupIndex);
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -211,15 +205,22 @@ public void setMaxBackupIndex(final int maxBackupIndex) {
* @return the suffix or {@code null} if no suffix should be used
*/
public String getSuffix() {
return suffix;
if (suffixRotator == SuffixRotator.EMPTY) {
return null;
}
return suffixRotator.toString();
}

/**
* Sets the suffix to be appended to the file name during the file rotation. The suffix does not play a role in
* determining when the file should be rotated.
* <p/>
* The suffix must be a string understood by the {@link java.text.SimpleDateFormat}.
* The suffix must be a string understood by the {@link java.text.SimpleDateFormat}. Optionally the suffix can end
* with {@code .gz} or {@code .zip} which will compress the file on rotation.
* <p/>
* <p>
* If the suffix ends with {@code .gz} or {@code .zip} the file will be compressed on rotation.
* </p>
* <b>Note:</b> Any files rotated with the suffix appended will not be deleted. The {@link #setMaxBackupIndex(int)
* maxBackupIndex} is not used for files with a suffix.
*
Expand All @@ -228,7 +229,7 @@ public String getSuffix() {
public void setSuffix(final String suffix) {
checkAccess(this);
synchronized (outputLock) {
this.suffix = suffix;
this.suffixRotator = SuffixRotator.parse(suffix);
}
}

Expand All @@ -245,44 +246,12 @@ protected void preWrite(final ExtLogRecord record) {
}
// close the old file.
setFile(null);
rotate(file);
suffixRotator.rotate(file.toPath(), maxBackupIndex);
// start with new file.
setFile(file);
} catch (IOException e) {
reportError("Unable to rotate log file", e, ErrorManager.OPEN_FAILURE);
}
}
}

private void rotate(final File file) throws IOException {
if (suffix == null) {
// rotate. First, drop the max file (if any), then move each file to the next higher slot.
Files.deleteIfExists(Paths.get(file.getAbsolutePath() + "." + maxBackupIndex));
for (int i = maxBackupIndex - 1; i >= 1; i--) {
final Path src = Paths.get(file.getAbsolutePath() + "." + i);
if (Files.exists(src)) {
final Path target = Paths.get(file.getAbsolutePath() + "." + (i + 1));
Files.move(src, target, StandardCopyOption.REPLACE_EXISTING);
}
}
Files.move(file.toPath(), Paths.get(file.getAbsolutePath() + ".1"), StandardCopyOption.REPLACE_EXISTING);
} else {
// This is not efficient, but performance risks were noted on the setSuffix() method
final String suffix = new SimpleDateFormat(this.suffix).format(new Date());
// Create the file name
final String newBaseFilename = file.getAbsolutePath() + suffix;

// rotate. First, drop the max file (if any), then move each file to the next higher slot.
Files.deleteIfExists(Paths.get(newBaseFilename + "." + maxBackupIndex));
for (int i = maxBackupIndex - 1; i >= 1; i--) {
final Path src = Paths.get(newBaseFilename + "." + i);
if (Files.exists(src)) {
final Path target = Paths.get(newBaseFilename + "." + (i + 1));
Files.move(src, target, StandardCopyOption.REPLACE_EXISTING);
}
}
// Rename the current file
Files.move(file.toPath(), Paths.get(newBaseFilename + ".1"), StandardCopyOption.REPLACE_EXISTING);
}
}
}
Loading

0 comments on commit 042fe8d

Please sign in to comment.