Reputation: 5307
I thought this is a pretty basic requirement, although difficult to implement efficiently:
At one codebase, we log quite a bit, depending on user behavior. For the sake of argument say every click on a button creates a log message with the name of the clicked button.
Now, I don't care about each and every clicked button. I'm quite content having one message printed once every 5 minutes, regardless of the number of times the user clicked the button.
I can do this pretty easily in user code:
private static final Logger LOG = Logger.getLogger("buttons");
private static final long LOG_ONLY_EVERY = Duration.ofMinutes( 5 ).getSeconds();
private static final Map<String, Long> loggedViolations = new HashMap<>();
public static void logClick( String buttonName )
{
String msg = "Button " + buttonName + " has been clicked";
final long epochSecond = Instant.now( Clock.systemUTC() ).getEpochSecond();
if ( !loggedViolations.containsKey( msg ) )
{
loggedViolations.put( msg, epochSecond );
}
if ( loggedViolations.get( msg ) + LOG_ONLY_EVERY < epochSecond )
{
LOG.warn( msg );
loggedViolations.put( msg, epochSecond );
}
}
My question is: can SLF4J or Log4J do this for me? How?
And yes, I'm aware the above code is lacking synchronization. If the answer to the above question is "no, do it yourself" - would the above be safe in a multi-threaded environment (since I don't remove messages, anyway)?
Upvotes: 1
Views: 4430
Reputation: 11045
Use the BurstFilter and install it on the buttons
logger:
The BurstFilter provides a mechanism to control the rate at which LogEvents are processed by silently discarding events after the maximum limit has been reached.
For Logback use the DuplicateMessageFilter.
Upvotes: 2