Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't my log4net appender buffering?

I've created a custom log4net appender. It descends from log4net.Appender.SmtpAppender which descends from log4net.Appender.BufferingAppenderSkeleton.

I programatically setup the following parameters in its constructor:

this.Lossy = false;  //don't drop any messages
this.BufferSize = 3; //buffer up to 3 messages
this.Threshold = log4net.Core.Level.Error; //append messages of Error or higher
this.Evaluator = new log4net.Core.LevelEvaluator(Level.Off); //don't flush the buffer for any message, regardless of level

I expect this would buffer 3 events of level Error or higher and deliver those events when the buffer is filled. However, I'm finding that the events are not buffered at all; instead, SendBuffer() is called immediately every time an error is logged.

Is there a mistake in my configuration?

Thanks

like image 899
Eric Avatar asked Mar 16 '10 21:03

Eric


2 Answers

This line:

this.Evaluator = new log4net.Core.LevelEvaluator(Level.Off);

tells the appender to flush the buffer when a message with level equal or above the evaluator is received. Level.Off will therefore block all events.

Update: after tracing over the log4net source once more I cannot see why buffering is not working for you.

Update2: I was stumped, but again, I found myself forgetting about log4net appenders need for the ActivateOptions to be called after settings have been changed. Until ActivateOptions is called, the internal cyclic buffer is not created and buffering will not happen.

So, making a quick test appender:

    public sealed class MyBufferingAppender: BufferingAppenderSkeleton
    {
        public MyBufferingAppender()
        {
            BufferSize = 3;
            ActivateOptions();
        }

        public readonly List<LoggingEvent> SentEvents = new List<LoggingEvent>();
        protected override void SendBuffer(LoggingEvent[] events)
        {
            SentEvents.AddRange(events);
        }
    }

...and a quick test:

    [Test]
    public void DoAppend_BuffersEvents()
    {
        var appender = new MyBufferingAppender();

        appender.DoAppend(new LoggingEvent(
           new LoggingEventData {Level = Level.Error, Message = "Hello world"}));

        Assert.That(appender.SentEvents, Has.Count(0));
    }

The test passes (on my machine at least :).

like image 127
Peter Lillevold Avatar answered Nov 04 '22 06:11

Peter Lillevold


What you want to do can be done with the following configuration:

<bufferSize value="3" />
<lossy value="false" />
<filter type="log4net.Filter.LevelRangeFilter">
    <levelMin value="ERROR" />
    <levelMax value="FATAL" />
</filter>

My understanding is that Threshold tells log4net when to flush the buffer (it would also flush if you reach the buffer size). If you want to exclude messages from the log you need to use a filter. In code this works as follows:

this.BufferSize = 3;
this.Lossy = false;

var filter = new log4net.Filter.LevelRangeFilter();
filter.LevelMin = log4net.Core.Level.Error;           
this.AddFilter(filter);

Btw. the buffer is filled and on the 4th error message the messages are sent. So if you want 3 messages only in the email you have to set the buffer size to 2...

like image 3
Stefan Egli Avatar answered Nov 04 '22 05:11

Stefan Egli