Tracing vs Logging Performance in .NET 6

I was wondering what’s the overhead of using ILogger versus built-in tracing so I’ve made some measurements.

Despite the fact that using ILogger needs extra library and EventSource is part of the runtime, I wanted to compare what’s the performance like when using:

  • Just EventSource.
  • ILogger with no log sinks configured at all.
  • ILogger with the fastest sink available, which is EventSource (to be more honest).

Here are the results:

Method Mean Error StdDev Min Max Median Gen0 Allocated
EmptyILogger 40.828 ns 7.079 ns 0.3880 ns 40.468 ns 41.239 ns 40.776 ns 0.0076 32 B
EventSourceILogger 58.839 ns 11.665 ns 0.6394 ns 58.196 ns 59.475 ns 58.845 ns 0.0076 32 B
NativeEventSource 3.588 ns 1.077 ns 0.0590 ns 3.528 ns 3.645 ns 3.592 ns - -

So it seems like even an empty ILogger withing nothing configured at all is 11.3 times faster. Another interesting thing is EventSource has absolutely zero memory allocations, even when using message formatting, wow!

Adding a very fast EventSource logger to ILogger makes it 16.3 times slower than EventSource. Adding other sinks is apparently even worse.

Now, this is not a critique of ILogger in any way, because ES and IL serve completely different purposes. It’s a simple comparison for a piece of mind.

For completeness, including benchmarking code below:

#LINQPad optimize+

[EventSource(Name = "Perf")]
public class PerfEventSource : EventSource {

    public static PerfEventSource Log { get; } = new PerfEventSource();

    [Event(1, Message = "a simple {0}", Level = EventLevel.Informational)]
    public void PerfPing(string p) {
        WriteEvent(1, p);
    }
}

[ShortRunJob]
[MinColumn, MaxColumn, MeanColumn, MedianColumn]
[MemoryDiagnoser]
[MarkdownExporter]
public class TracingVsLoggingBenchmark {

    Microsoft.Extensions.Logging.ILogger emptyLogger;
    Microsoft.Extensions.Logging.ILogger esLogger;

    [GlobalSetup]
    public void Setup() {
        var emptyFactory = LoggerFactory.Create(builder => {
            
        });
        
        emptyLogger = emptyFactory.CreateLogger("empty");
        
        var tracingFactory = LoggerFactory.Create(builder => {
           builder.AddEventSourceLogger(); 
        });
        
        esLogger = tracingFactory.CreateLogger("es");
    }
    
    [Benchmark]
    public void EmptyILogger() {
        emptyLogger.LogInformation("a simple {0}", "message");
    }

    [Benchmark]
    public void EventSourceILogger() {
        esLogger.LogInformation("a simple {0}", "message");
    }


    [Benchmark]
    public void NativeEventSource() {
        PerfEventSource.Log.PerfPing("message");
    }
}


void Main() {
    Util.AutoScrollResults = true;
    BenchmarkRunner.Run<TracingVsLoggingBenchmark>();
    
    
}

Thanks! You can always email me or use contact form for more questions/comments etc.