Monthly Archives: February 2019

Buffering a TraceListener

TraceEventArgs.cs:

using System;

public class TraceEventArgs : EventArgs
{
    public string Message { get; private set; }

    public TraceEventArgs(string message)
    {
        Message = message;
    }
}

BufferedTraceListener.cs:

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;

public class BufferedTraceListener : TraceListener
{
    private SynchronizationContext context;
    private StringBuilder buffer;
    private object bufferLock;
    private Timer timer;
    private TimeSpan delay;

    public BufferedTraceListener(TimeSpan delay)
    {
        context = SynchronizationContext.Current;
        buffer = new StringBuilder();
        bufferLock = new object();
        timer = new Timer(Tick);
        this.delay = delay;
    }

    public BufferedTraceListener()
        : this(TimeSpan.FromSeconds(0.1)) { }

    public event EventHandler<TraceEventArgs> Written;
    private void OnWritten(TraceEventArgs e)
    {
        if (context == null)
        {
            Written?.Invoke(this, e);
        }
        else
        {
            context.Post(state => Written?.Invoke(this, e), null);
        }
    }
    private void OnWritten(string message)
    {
        OnWritten(new TraceEventArgs(message));
    }

    private void Tick(object state)
    {
        lock (bufferLock)
        {
            OnWritten(buffer.ToString());
            buffer.Clear();
        }
    }

    public override void Write(string message)
    {
        lock (bufferLock)
        {
            buffer.Append(message);
            timer.Change(delay, Timeout.InfiniteTimeSpan);
        }
    }

    public override void WriteLine(string message)
    {
        Write(message + Environment.NewLine);
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (disposing)
        {
            timer.Dispose();
        }
    }
}