diff --git a/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.csproj b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.csproj index 429136ba..bb4a1e1d 100644 --- a/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.csproj +++ b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.csproj @@ -25,6 +25,8 @@ + + diff --git a/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Extensions/ILoggingBuilderExtensions.cs b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Extensions/ILoggingBuilderExtensions.cs new file mode 100644 index 00000000..0c83be41 --- /dev/null +++ b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Extensions/ILoggingBuilderExtensions.cs @@ -0,0 +1,36 @@ +using System; +using GuardNet; +using Microsoft.Extensions.DependencyInjection; +using Serilog.Extensions.Logging; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.Logging +{ + /// + /// Extensions on the + /// + // ReSharper disable once InconsistentNaming + public static class ILoggingBuilderExtensions + { + /// + /// Add Serilog to the logging pipeline. + /// + /// The to add logging provider to. + /// The factory function to create an Serilog logger implementation. + /// Thrown when the or is null. + public static ILoggingBuilder AddSerilog( + this ILoggingBuilder builder, + Func implementationFactory) + { + Guard.NotNull(builder, nameof(builder), "Requires a logging builder instance to add the Serilog logger provider"); + Guard.NotNull(implementationFactory, nameof(implementationFactory), "Requires an implementation factory to build up the Serilog logger"); + + builder.Services.AddSingleton(provider => + { + return new SerilogLoggerProvider(implementationFactory(provider), dispose: true); + }); + + return builder; + } + } +} diff --git a/src/Arcus.Observability.Tests.Unit/Serilog/ILoggingBuilderExtensionsTests.cs b/src/Arcus.Observability.Tests.Unit/Serilog/ILoggingBuilderExtensionsTests.cs new file mode 100644 index 00000000..6c961a19 --- /dev/null +++ b/src/Arcus.Observability.Tests.Unit/Serilog/ILoggingBuilderExtensionsTests.cs @@ -0,0 +1,51 @@ +using System; +using Arcus.Observability.Correlation; +using Arcus.Observability.Tests.Unit.Telemetry.AzureFunctions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Extensions.Logging; +using Xunit; + +namespace Arcus.Observability.Tests.Unit.Serilog +{ + // ReSharper disable once InconsistentNaming + public class ILoggingBuilderExtensionsTests + { + [Fact] + public void AddSerilog_WithImplementationFactory_IncludesSerilogLogger() + { + // Arrange + var services = new ServiceCollection(); + services.AddCorrelation(); + + // Act + services.AddLogging(builder => builder.AddSerilog(provider => + { + var accessor = provider.GetRequiredService(); + return new LoggerConfiguration() + .Enrich.WithCorrelationInfo(accessor) + .WriteTo.Console() + .CreateLogger(); + })); + + // Assert + IServiceProvider serviceProvider = services.BuildServiceProvider(); + var loggerProvider = serviceProvider.GetService(); + Assert.NotNull(loggerProvider); + Assert.IsType(loggerProvider); + Assert.NotNull(serviceProvider.GetService>()); + } + + [Fact] + public void AddSerilog_WithoutImplementationFactory_Fails() + { + // Arrange + var services = new ServiceCollection(); + + // Act / Assert + Assert.ThrowsAny( + () => services.AddLogging(builder => builder.AddSerilog(implementationFactory: null))); + } + } +}