I have a component that is constantly reading a values from a device. Currently it updates every {n} seconds and logs a debug message with the value to an instance of ILog.
Every second is too frequent for me, I just don't care and it eats up too much log space. However, I would certainly be interested in capturing every 10th or 30th message from that component so I can get the general gist of what it is doing.
Does anyone know any way of doing this that does not involve me witting my own ILog implementation?
This is probably too late to help you, but you could implement a filter. http://www.mail-archive.com/log4net-user%40logging.apache.org/msg02517.html shows how to implement a filter for limiting how often an exception is logged (if exception type is same as last exception type and if less than some specified amount of time has passed).
Here is the actual filter source code from that link:
public class ExceptionThrottleFilter : FilterSkeleton
{
private DateTime lastException = DateTime.MinValue;
private Type exceptionType = typeof(Exception);
private int threshold = 5; // seconds
public override void ActivateOptions()
{
base.ActivateOptions();
}
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (loggingEvent.ExceptionObject != null && loggingEvent.ExceptionObject.GetType) == exceptionType)
{
if (loggingEvent.TimeStamp.Subtract(lastException).TotalSeconds > threshold)
{
lastException = loggingEvent.TimeStamp;
return FilterDecision.Accept;
}
else
{
return FilterDecision.Deny;
}
}
else
{
return FilterDecision.Neutral;
}
}
public Type ExceptionType
{
get { return exceptionType; }
set { exceptionType = value; }
}
public int Threshold
{
get { return threshold; }
set { threshold = value; }
}
}
It would be configured like this:
<filter type="Company.Project.Logging.ExceptionThrottleFilter">
<threshold value="2" />
<exceptionType value="System.ApplicationException" />
</filter>
It seems like it would be pretty straightforward to modify it to "throttle" messages that repeat. Maybe something like this (untested):
public class DuplicateMessageThrottleFilter : FilterSkeleton
{
private string lastMessage;
public override void ActivateOptions()
{
base.ActivateOptions();
}
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
string newMessage;
if (loggingEvent.MessageObject != null)
{
newMessage = loggingEvent.MessageObject.ToString();
}
if (newMessage.Equals(lastMessage))
{
return FilterDecision.Deny;
}
lastMessage = newMessage;
return FilterDecision.Accept;
}
}
It might be nice to annotate a logged message with how many times it was repeated, but how to do that is not obvious to me:
Some message.
Some message.
Some message.
Look, a new message.
Some message.
Some message.
Look, a new message.
Could generate something like this:
Some message. (3 times)
Look, a new message.
Some message. (2 times)
Look, a new message.
Probably some kind of ForwardingAppender or BufferingForwardingAppender. It would always be one message behind. A message comes in. The "RepeatedMessageAppender" would hold that message. The next message comes in. If it is different than last message, forward last message to the "real" Appender (if "repeated count" is > 0, append the number to the last message before forwarding - this is the part that I am not sure about because I think htat it is not easy to modify the LoggingEvent that is passed to the Appender). If it is the same as the last message, increment counter and do not forward. Since the "RepeatedMessageAppender" is one behind, it probably has to be a BufferingForwardingAppender and it must implement Flush.
Maybe you (or someone else) will find this information useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With