// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 using BenchmarkDotNet.Attributes; using Microsoft.Extensions.Logging; using OpenTelemetry; using OpenTelemetry.Logs; /* BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3) 11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores .NET SDK 8.0.107 [Host] : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2 DefaultJob : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2 | Method | Mean | Error | StdDev | Median | Gen0 | Gen1 | Allocated | |------------------------------ |-----------:|----------:|-----------:|-----------:|-------:|-------:|----------:| | NoListenerStringInterpolation | 135.503 ns | 2.7458 ns | 4.5114 ns | 135.391 ns | 0.0114 | - | 72 B | | NoListenerExtensionMethod | 40.218 ns | 0.8249 ns | 2.2581 ns | 39.809 ns | 0.0102 | - | 64 B | | NoListener | 1.930 ns | 0.0626 ns | 0.1264 ns | 1.889 ns | - | - | - | | UnnecessaryIsEnabledCheck | 1.531 ns | 0.0542 ns | 0.1267 ns | 1.518 ns | - | - | - | | CreateLoggerRepeatedly | 53.797 ns | 1.0927 ns | 1.7331 ns | 53.401 ns | 0.0038 | - | 24 B | | OneProcessor | 111.558 ns | 2.9821 ns | 8.5082 ns | 109.311 ns | 0.0063 | - | 40 B | | BatchProcessor | 263.650 ns | 5.2908 ns | 14.1223 ns | 258.984 ns | 0.0200 | 0.0043 | 128 B | | TwoProcessors | 108.701 ns | 2.1964 ns | 4.3355 ns | 108.025 ns | 0.0063 | - | 40 B | | ThreeProcessors | 105.099 ns | 1.8106 ns | 2.1554 ns | 105.796 ns | 0.0063 | - | 40 B | */ namespace Benchmarks.Logs; public class LogBenchmarks { private const double FoodPrice = 2.99; private const string FoodName = "tomato"; private readonly ILogger loggerWithNoListener; private readonly ILogger loggerWithOneProcessor; private readonly ILogger loggerWithBatchProcessor; private readonly ILogger loggerWithTwoProcessors; private readonly ILogger loggerWithThreeProcessors; private readonly ILoggerFactory loggerFactoryWithNoListener; private readonly ILoggerFactory loggerFactoryWithOneProcessor; private readonly ILoggerFactory loggerFactoryWithBatchProcessor; private readonly ILoggerFactory loggerFactoryWithTwoProcessor; private readonly ILoggerFactory loggerFactoryWithThreeProcessor; public LogBenchmarks() { this.loggerFactoryWithNoListener = LoggerFactory.Create(builder => { }); this.loggerWithNoListener = this.loggerFactoryWithNoListener.CreateLogger(); this.loggerFactoryWithOneProcessor = LoggerFactory.Create(builder => { builder.UseOpenTelemetry(logging => logging .AddProcessor(new NoopLogProcessor())); }); this.loggerWithOneProcessor = this.loggerFactoryWithOneProcessor.CreateLogger(); this.loggerFactoryWithBatchProcessor = LoggerFactory.Create(builder => { builder.UseOpenTelemetry(logging => logging .AddProcessor(new BatchLogRecordExportProcessor(new NoopExporter()))); }); this.loggerWithBatchProcessor = this.loggerFactoryWithBatchProcessor.CreateLogger(); this.loggerFactoryWithTwoProcessor = LoggerFactory.Create(builder => { builder.UseOpenTelemetry(logging => logging .AddProcessor(new NoopLogProcessor()) .AddProcessor(new NoopLogProcessor())); }); this.loggerWithTwoProcessors = this.loggerFactoryWithTwoProcessor.CreateLogger(); this.loggerFactoryWithThreeProcessor = LoggerFactory.Create(builder => { builder.UseOpenTelemetry(logging => logging .AddProcessor(new NoopLogProcessor()) .AddProcessor(new NoopLogProcessor()) .AddProcessor(new NoopLogProcessor())); }); this.loggerWithThreeProcessors = this.loggerFactoryWithThreeProcessor.CreateLogger(); } [GlobalCleanup] public void GlobalCleanup() { this.loggerFactoryWithNoListener.Dispose(); this.loggerFactoryWithOneProcessor.Dispose(); this.loggerFactoryWithTwoProcessor.Dispose(); this.loggerFactoryWithThreeProcessor.Dispose(); } [Benchmark] public void NoListenerStringInterpolation() #pragma warning disable CA2254 // Template should be a static expression #pragma warning disable CA1848 // Use the LoggerMessage delegates => this.loggerWithNoListener.LogInformation($"Hello from {FoodName} {FoodPrice}."); #pragma warning restore CA1848 // Use the LoggerMessage delegates #pragma warning restore CA2254 // Template should be a static expression [Benchmark] public void NoListenerExtensionMethod() #pragma warning disable CA1848 // Use the LoggerMessage delegates #pragma warning disable CA1873 // Avoid potentially expensive logging => this.loggerWithNoListener.LogInformation("Hello from {Name} {Price}.", FoodName, FoodPrice); #pragma warning restore CA1873 // Avoid potentially expensive logging #pragma warning restore CA1848 // Use the LoggerMessage delegates [Benchmark] public void NoListener() => this.loggerWithNoListener.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); [Benchmark] public void UnnecessaryIsEnabledCheck() { if (this.loggerWithNoListener.IsEnabled(LogLevel.Information)) { this.loggerWithNoListener.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); } } [Benchmark] public void CreateLoggerRepeatedly() { var logger = this.loggerFactoryWithNoListener.CreateLogger(); logger.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); } [Benchmark] public void OneProcessor() => this.loggerWithOneProcessor.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); [Benchmark] public void BatchProcessor() => this.loggerWithBatchProcessor.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); [Benchmark] public void TwoProcessors() => this.loggerWithTwoProcessors.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); [Benchmark] public void ThreeProcessors() => this.loggerWithThreeProcessors.FoodRecallNotice( brandName: "Contoso", productDescription: "Salads", productType: "Food & Beverages", recallReasonDescription: "due to a possible health risk from Listeria monocytogenes", companyName: "Contoso Fresh Vegetables, Inc."); internal sealed class NoopLogProcessor : BaseProcessor; internal sealed class NoopExporter : BaseExporter { public override ExportResult Export(in Batch batch) => ExportResult.Success; } }