Some conditions repeat thousands of times a minute - a peer resetting a connection, a tunnel failing to build - and each occurrence is individually uninteresting while the volume hides the messages that matter. At a few thousand lines a minute the log also stops being readable during an incident and starts costing real disk through rotation.
A caller passes a stable key identifying the condition and logs through Log.warnThrottled(String, String) and friends. The first occurrence is always written; after that, an occurrence is written when either enough repeats have accumulated (DEFAULT_BURST) or enough time has passed (DEFAULT_WINDOW_MS), whichever comes first, and the line states how many were collapsed. A condition that fires once an hour is never hidden; one that fires two thousand times a minute is reduced to a couple of lines a minute that still say how big it was.
Keys are scoped to the Log instance, which LogManager caches per class, so state is effectively per logging class and keys cannot collide across classes. The key table is bounded: entries whose window has long expired are pruned when it grows past MAX_KEYS, so a caller that keys on something unique per occurrence - a peer hash, say - cannot leak.
Instances are thread-safe.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classWhat the caller should do with one occurrence.Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intRepeats to accumulate before writing again, unless the window expires first.static final longLongest a repeat can stay hidden once the first occurrence has been written.(package private) static final intUpper bound on tracked keys.Constructor Summary
ConstructorsConstructorDescriptionCreate a suppressor with the default burst and window.LogSuppressor(int burst, long windowMs) Construct a suppressor with an explicit burst size and window.Method Summary
Modifier and TypeMethodDescription(package private) static booleanisDue(long occurrences, long lastReportCount, long lastReportMs, int burst, long windowMs, long nowMs) Decide whether one occurrence ofkeyshould be written.Record one occurrence ofkeyand say whether to write it.Record one occurrence at an explicit time.voidreset()Forget all bookkeeping, so every key starts counting from scratch again.intsize()How many distinct keys are being tracked.
Field Details
DEFAULT_BURST
public static final int DEFAULT_BURSTRepeats to accumulate before writing again, unless the window expires first.- See Also:
DEFAULT_WINDOW_MS
public static final long DEFAULT_WINDOW_MSLongest a repeat can stay hidden once the first occurrence has been written.- See Also:
MAX_KEYS
static final int MAX_KEYSUpper bound on tracked keys. Pruned down to the live window past this size, so a caller keying per-occurrence cannot grow the table without bound.- See Also:
Constructor Details
LogSuppressor
public LogSuppressor()Create a suppressor with the default burst and window.A suppressor allows
_burstmessages through before suppressing for_windowMs, so a repeated error is logged without flooding the log.LogSuppressor
public LogSuppressor(int burst, long windowMs) Construct a suppressor with an explicit burst size and window.- Parameters:
burst- repeats to accumulate before writing again, forced to at least 1windowMs- longest a repeat may stay hidden, in ms, forced to at least 1
Method Details
isDue
static boolean isDue(long occurrences, long lastReportCount, long lastReportMs, int burst, long windowMs, long nowMs) Decide whether one occurrence ofkeyshould be written.Pure, so the policy can be pinned by test without a clock or a logger. The first occurrence of a key always reports; afterwards a report is due once the repeats since the last one reach
burst, or oncewindowMshave passed - time as well as count, so a slow trickle stays visible.- Parameters:
occurrences- total occurrences of this key including this onelastReportCount- occurrence count at the previous report, zero if neverlastReportMs- wall-clock ms of the previous report, zero if neverburst- repeats to accumulate before reporting againwindowMs- longest a repeat may stay hiddennowMs- current wall-clock ms- Returns:
- true if this occurrence should be written
record
Record one occurrence ofkeyand say whether to write it.- Parameters:
key- stable identifier for the condition being repeated- Returns:
- whether to write, and how many occurrences were collapsed since the last write
record
Record one occurrence at an explicit time.- Parameters:
key- stable identifier for the condition being repeatednowMs- current wall-clock ms- Returns:
- whether to write, and how many occurrences were collapsed since the last write
reset
public void reset()Forget all bookkeeping, so every key starts counting from scratch again.size
public int size()How many distinct keys are being tracked.- Returns:
- current key count