#java #log4j
#java #log4j
Вопрос:
Я использовал rolling policy log4j для сжатия файлов, размер которых достигает определенного размера. Приведенные ниже свойства log4j работают должным образом.
log4j.appender.FILE=org.apache.log4j.rolling.RollingFileAppender
log4j.appender.FILE.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy
log4j.appender.FILE.rollingPolicy.maxIndex=13
log4j.appender.FILE.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy
log4j.appender.FILE.triggeringPolicy.MaxFileSize=80
log4j.appender.FILE.rollingPolicy.FileNamePattern=log/projectlog_${current.date.time}.%i.log.gz
log4j.appender.FILE.rollingPolicy.ActiveFileName=log/project_log_${current.date.time}.log
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%m%n
Но проблема здесь в том, что после создания сжатого файла он также переименовывает файл, который присутствует в сжатом файле gz, с именем файла gz.
В моем сценарии я не хочу, чтобы log4j переименовывал файл, который присутствует в сжатом архиве gz. Есть ли какой-либо способ, с помощью которого мы можем ограничить log4j, чтобы не изменять имена файлов, которые он сжимает.
Ответ №1:
Вы не можете с помощью кода, предоставленного log4j @UmarTahir.
Как вы можете видеть в исходном коде FixedWindowRollingPolicy
класса, в методе, который фактически обрабатывает rollover
, они сначала инструктируют RollingFileAppender
синхронно переименовать файл, а затем при необходимости асинхронно сжать его:
public RolloverDescription rollover(final String currentFileName) {
if (maxIndex >= 0) {
int purgeStart = minIndex;
if (!explicitActiveFile) {
purgeStart ;
}
if (!purge(purgeStart, maxIndex)) {
return null;
}
StringBuffer buf = new StringBuffer();
formatFileName(new Integer(purgeStart), buf);
String renameTo = buf.toString();
String compressedName = renameTo;
Action compressAction = null;
if (renameTo.endsWith(".gz")) {
renameTo = renameTo.substring(0, renameTo.length() - 3);
compressAction =
new GZCompressAction(
new File(renameTo), new File(compressedName), true);
} else if (renameTo.endsWith(".zip")) {
renameTo = renameTo.substring(0, renameTo.length() - 4);
compressAction =
new ZipCompressAction(
new File(renameTo), new File(compressedName), true);
}
FileRenameAction renameAction =
new FileRenameAction(
new File(currentFileName), new File(renameTo), false);
return new RolloverDescriptionImpl(
currentFileName, false, renameAction, compressAction);
}
return null;
}
Возвращенное значение RolloverDescription
будет использоваться в RollingFileAppender
rollover
методе для обработки фактического процесса ролловера:
public boolean rollover() {
//
// can't roll without a policy
//
if (rollingPolicy != null) {
Exception exception = null;
synchronized (this) {
//
// if a previous async task is still running
//}
if (lastRolloverAsyncAction != null) {
//
// block until complete
//
lastRolloverAsyncAction.close();
//
// or don't block and return to rollover later
//
//if (!lastRolloverAsyncAction.isComplete()) return false;
}
try {
RolloverDescription rollover = rollingPolicy.rollover(getFile());
if (rollover != null) {
if (rollover.getActiveFileName().equals(getFile())) {
closeWriter();
boolean success = true;
if (rollover.getSynchronous() != null) {
success = false;
try {
success = rollover.getSynchronous().execute();
} catch (Exception ex) {
exception = ex;
}
}
if (success) {
if (rollover.getAppend()) {
fileLength = new File(rollover.getActiveFileName()).length();
} else {
fileLength = 0;
}
if (rollover.getAsynchronous() != null) {
lastRolloverAsyncAction = rollover.getAsynchronous();
new Thread(lastRolloverAsyncAction).start();
}
setFile(
rollover.getActiveFileName(), rollover.getAppend(),
bufferedIO, bufferSize);
} else {
setFile(
rollover.getActiveFileName(), true, bufferedIO, bufferSize);
if (exception == null) {
LogLog.warn("Failure in post-close rollover action");
} else {
LogLog.warn(
"Exception in post-close rollover action", exception);
}
}
} else {
Writer newWriter =
createWriter(
createFileOutputStream(
rollover.getActiveFileName(), rollover.getAppend()));
closeWriter();
setFile(rollover.getActiveFileName());
this.qw = createQuietWriter(newWriter);
boolean success = true;
if (rollover.getSynchronous() != null) {
success = false;
try {
success = rollover.getSynchronous().execute();
} catch (Exception ex) {
exception = ex;
}
}
if (success) {
if (rollover.getAppend()) {
fileLength = new File(rollover.getActiveFileName()).length();
} else {
fileLength = 0;
}
if (rollover.getAsynchronous() != null) {
lastRolloverAsyncAction = rollover.getAsynchronous();
new Thread(lastRolloverAsyncAction).start();
}
}
writeHeader();
}
return true;
}
} catch (Exception ex) {
exception = ex;
}
}
if (exception != null) {
LogLog.warn(
"Exception during rollover, rollover deferred.", exception);
}
}
return false;
}
Если вам нужно это особое поведение, возможно, вы можете создать свою собственную политику перехода и попытаться реализовать что-то похожее на то, что сделано в FixedWindowRollingPolicy
, способом, наилучшим образом соответствующим вашим требованиям, и настроить log4j на использование этой новой политики перехода.
Как уже было сказано, имейте в виду, что gzip означает просто сжатие ваших данных, фактическое имя файла или запись файла отсутствуют, просто данные сжаты. Если вы используете gzip
инструмент, он использует имя архива для сжатия, сжимает данные и сохраняет результат в новом файле с суффиксом, обычно .gz
. Это поведение log4j пытается имитировать в своем коде.
Комментарии:
1. Большое вам спасибо за ваш ответ и за то, что поделились ссылкой на кодовую базу. Я удивлен, что они пытались сделать это таким образом.
2. Добро пожаловать @UmarTahir. Вы правы, хотя, если вы хорошенько подумаете, это имеет смысл: сначала синхронно выполняется операция переименования, которая должна быть быстрой операцией, а затем асинхронно выполняется операция сжатия, которая с точки зрения времени и использования ресурсов может быть более дорогостоящей и с риском блокирования нормальной работы регистраторов.
3. Да, вы правы. Также в моем сценарии, поскольку мой продукт должен возвращать результат за 20 мс, log4j не приносит нам пользы, поскольку у нас много потоков. Вчера я провел несколько тестов на log4j / log4j2, чтобы узнать, сколько времени требуется потоку 30, чтобы вернуться после выполнения log.info . В основном результаты были за 20 мс.
4. Я думаю, было бы здорово, если бы было действительно небольшое количество потоков-потребителей, работающих в базовой функциональности ведения журнала. Таким образом, избегая основных потоков для выполнения чего-то еще.
5. Добро пожаловать @UmarTahir. На самом деле, спасибо, я действительно ценю, когда people заботится о коде на таком глубоком уровне, молодец.