Если это единственное, что вы хотите напечатать один раз, то лучшим вариантом будет использование сохраненного логического значения.Если вы хотели что-то, что вы могли бы использовать в своем проекте, я создал что-то, что может быть полезным.Я только что создал класс Java, который использует экземпляр log4j logger.Когда я хочу записать сообщение в журнал, я просто делаю что-то вроде этого:
LogConsolidated.log(logger, Level.WARN, 5000, "File: " + f + " not found.", e);
Вместо:
logger.warn("File: " + f + " not found.", e);
, что позволяет вести журнал максимум 1 раз каждые 5 секунд, ипечатает, сколько раз он должен был войти (например, | x53 |).Очевидно, вы можете сделать так, чтобы у вас не было столько параметров, или вытащить уровень, выполнив log.warn или что-то еще, но это работает для моего варианта использования.
Для вас (если вы хотите толькопечатать один раз, каждый раз) это излишне, но вы все равно можете сделать это, передав что-то вроде: Long.MAX_LONG в качестве 3-го параметра.Мне нравится гибкость, позволяющая определять частоту для каждого конкретного сообщения журнала (отсюда и параметр).Например, это выполнит то, что вы хотите:
LogConsolidated.log(logger, Level.WARN, Long.MAX_LONG, "File: " + f + " not found.", e);
Вот класс LogConsolidated:
import java.util.HashMap;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class LogConsolidated {
private static HashMap<String, TimeAndCount> lastLoggedTime = new HashMap<>();
/**
* Logs given <code>message</code> to given <code>logger</code> as long as:
* <ul>
* <li>A message (from same class and line number) has not already been logged within the past <code>timeBetweenLogs</code>.</li>
* <li>The given <code>level</code> is active for given <code>logger</code>.</li>
* </ul>
* Note: If messages are skipped, they are counted. When <code>timeBetweenLogs</code> has passed, and a repeat message is logged,
* the count will be displayed.
* @param logger Where to log.
* @param level Level to log.
* @param timeBetweenLogs Milliseconds to wait between similar log messages.
* @param message The actual message to log.
* @param t Can be null. Will log stack trace if not null.
*/
public static void log(Logger logger, Level level, long timeBetweenLogs, String message, Throwable t) {
if (logger.isEnabledFor(level)) {
String uniqueIdentifier = getFileAndLine();
TimeAndCount lastTimeAndCount = lastLoggedTime.get(uniqueIdentifier);
if (lastTimeAndCount != null) {
synchronized (lastTimeAndCount) {
long now = System.currentTimeMillis();
if (now - lastTimeAndCount.time < timeBetweenLogs) {
lastTimeAndCount.count++;
return;
} else {
log(logger, level, "|x" + lastTimeAndCount.count + "| " + message, t);
}
}
} else {
log(logger, level, message, t);
}
lastLoggedTime.put(uniqueIdentifier, new TimeAndCount());
}
}
private static String getFileAndLine() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
boolean enteredLogConsolidated = false;
for (StackTraceElement ste : stackTrace) {
if (ste.getClassName().equals(LogConsolidated.class.getName())) {
enteredLogConsolidated = true;
} else if (enteredLogConsolidated) {
// We have now file/line before entering LogConsolidated.
return ste.getFileName() + ":" + ste.getLineNumber();
}
}
return "?";
}
private static void log(Logger logger, Level level, String message, Throwable t) {
if (t == null) {
logger.log(level, message);
} else {
logger.log(level, message, t);
}
}
private static class TimeAndCount {
long time;
int count;
TimeAndCount() {
this.time = System.currentTimeMillis();
this.count = 0;
}
}
}