From 3eec37ffffe558204b18aa29d32a46f781baa2bf Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Wed, 8 Jul 2020 10:57:47 +0200 Subject: [PATCH] Feature - clear logger providers except functions extension (#134) * Feature - clear logger providers except functions * pr-sug: update docs w/ created project --- .../guidance/use-with-dotnet-and-functions.md | 4 +- ...ervability.Telemetry.AzureFunctions.csproj | 32 +++++++++++++++ .../Extensions/ILoggerBuilderExtensions.cs | 39 +++++++++++++++++++ .../Arcus.Observability.Tests.Unit.csproj | 1 + .../Fixture/FunctionFileLoggerProvider.cs | 32 +++++++++++++++ .../Fixture/HostFileLoggerProvider.cs | 30 ++++++++++++++ .../Fixture/TestLoggerProvider.cs | 29 ++++++++++++++ .../ILoggerBuilderExtensionsTests.cs | 32 +++++++++++++++ src/Arcus.Observability.sln | 6 +++ 9 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 src/Arcus.Observability.Telemetry.AzureFunctions/Arcus.Observability.Telemetry.AzureFunctions.csproj create mode 100644 src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerBuilderExtensions.cs create mode 100644 src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/FunctionFileLoggerProvider.cs create mode 100644 src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/HostFileLoggerProvider.cs create mode 100644 src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/TestLoggerProvider.cs create mode 100644 src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/ILoggerBuilderExtensionsTests.cs diff --git a/docs/preview/guidance/use-with-dotnet-and-functions.md b/docs/preview/guidance/use-with-dotnet-and-functions.md index cb075030..a5b4b610 100644 --- a/docs/preview/guidance/use-with-dotnet-and-functions.md +++ b/docs/preview/guidance/use-with-dotnet-and-functions.md @@ -23,13 +23,13 @@ Using Serilog with Azure Functions requires some guidance and we've made it a bi Before we get started, install our NuGet package for Azure Functions: ``` -PM > TODO @stijnmoreels +PM > Install-Package -Name Arcus.Observability.Telemetry.AzureFunctions ``` Once that is done, you can configure Serilog during startup as following: ```csharp -using Arcus.TODO.@stijnmoreels; +using Microsoft.Extensions.Logging; [assembly: FunctionsStartup(typeof(Startup))] namespace Arcus.Samples.AzureFunction diff --git a/src/Arcus.Observability.Telemetry.AzureFunctions/Arcus.Observability.Telemetry.AzureFunctions.csproj b/src/Arcus.Observability.Telemetry.AzureFunctions/Arcus.Observability.Telemetry.AzureFunctions.csproj new file mode 100644 index 00000000..9e770459 --- /dev/null +++ b/src/Arcus.Observability.Telemetry.AzureFunctions/Arcus.Observability.Telemetry.AzureFunctions.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0;netcoreapp3.1 + Arcus + Arcus + Provides capability to improve telemetry with Serilog in Azure Functions applications + Copyright (c) Arcus + https://github.com/arcus-azure/arcus.observability/blob/master/LICENSE + https://github.com/arcus-azure/arcus.observability + https://raw.githubusercontent.com/arcus-azure/arcus/master/media/arcus.png + https://github.com/arcus-azure/arcus.observability + Git + Azure;Observability;Telemetry;Azure Functions + Arcus.Observability.Telemetry.AzureFunctions + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerBuilderExtensions.cs b/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerBuilderExtensions.cs new file mode 100644 index 00000000..37afd47e --- /dev/null +++ b/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerBuilderExtensions.cs @@ -0,0 +1,39 @@ +using GuardNet; +using Microsoft.Extensions.DependencyInjection; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.Logging +{ + /// + /// extensions related to Azure Functions projects. + /// + // ReSharper disable once InconsistentNaming + public static class ILoggingBuilderExtensions + { + /// + /// Clears the registrations from the given , + /// except the specific Azure Functions registrations. + /// + /// The builder containing the registrations. + public static ILoggingBuilder ClearProvidersExceptFunctionProviders(this ILoggingBuilder loggingBuilder) + { + Guard.NotNull(loggingBuilder, nameof(loggingBuilder)); + + // Kudos to katrash: https://stackoverflow.com/questions/45986517/remove-console-and-debug-loggers-in-asp-net-core-2-0-when-in-production-mode + foreach (ServiceDescriptor serviceDescriptor in loggingBuilder.Services) + { + if (serviceDescriptor.ServiceType == typeof(ILoggerProvider)) + { + if (serviceDescriptor.ImplementationType.FullName != "Microsoft.Azure.WebJobs.Script.Diagnostics.HostFileLoggerProvider" + && serviceDescriptor.ImplementationType.FullName != "Microsoft.Azure.WebJobs.Script.Diagnostics.FunctionFileLoggerProvider") + { + loggingBuilder.Services.Remove(serviceDescriptor); + break; + } + } + } + + return loggingBuilder; + } + } +} diff --git a/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj b/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj index 0ab86175..d34a8c88 100644 --- a/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj +++ b/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/FunctionFileLoggerProvider.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/FunctionFileLoggerProvider.cs new file mode 100644 index 00000000..e7910cd4 --- /dev/null +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/FunctionFileLoggerProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Extensions.Logging; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Azure.WebJobs.Script.Diagnostics +{ + /// + /// to verify if the surrogate of the real provider doesn't get removed. + /// + public class FunctionFileLoggerProvider : ILoggerProvider + { + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + throw new NotImplementedException(); + } + + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// The instance of that was created. + public ILogger CreateLogger(string categoryName) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/HostFileLoggerProvider.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/HostFileLoggerProvider.cs new file mode 100644 index 00000000..75908afa --- /dev/null +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/HostFileLoggerProvider.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.Extensions.Logging; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Azure.WebJobs.Script.Diagnostics +{ + /// + /// to verify if the surrogate of the real provider doesn't get removed. + /// + public class HostFileLoggerProvider : ILoggerProvider + { + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + throw new NotImplementedException(); + } + + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// The instance of that was created. + public ILogger CreateLogger(string categoryName) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/TestLoggerProvider.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/TestLoggerProvider.cs new file mode 100644 index 00000000..f8517a28 --- /dev/null +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/Fixture/TestLoggerProvider.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Extensions.Logging; + +namespace Arcus.Observability.Tests.Unit.Telemetry.AzureFunctions.Fixture +{ + /// + /// implementation to verify if the provider gets removed during the . + /// + public class TestLoggerProvider : ILoggerProvider + { + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + throw new NotImplementedException(); + } + + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// The instance of that was created. + public ILogger CreateLogger(string categoryName) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/ILoggerBuilderExtensionsTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/ILoggerBuilderExtensionsTests.cs new file mode 100644 index 00000000..c1910dae --- /dev/null +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/AzureFunctions/ILoggerBuilderExtensionsTests.cs @@ -0,0 +1,32 @@ +using Arcus.Observability.Tests.Unit.Telemetry.AzureFunctions.Fixture; +using Microsoft.Azure.WebJobs.Script.Diagnostics; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Arcus.Observability.Tests.Unit.Telemetry.AzureFunctions +{ + public class ILoggerBuilderExtensionsTests + { + [Fact] + public void ClearProvidersExceptFunctions_WithLoggerBuilderContainingProviders_RemovesNonFunctionProviders() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + var builder = new Mock(); + builder.Setup(b => b.Services).Returns(services); + + // Act + builder.Object.ClearProvidersExceptFunctionProviders(); + + // Assert + Assert.NotEmpty(services); + Assert.Equal(2, services.Count); + Assert.All(services, desc => Assert.NotEqual(typeof(TestLoggerProvider), desc.ImplementationType)); + } + } +} diff --git a/src/Arcus.Observability.sln b/src/Arcus.Observability.sln index 2dbdeab2..3a9c9f3b 100644 --- a/src/Arcus.Observability.sln +++ b/src/Arcus.Observability.sln @@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arcus.Observability.Tests.C EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arcus.Observability.Telemetry.IoT", "Arcus.Observability.Telemetry.IoT\Arcus.Observability.Telemetry.IoT.csproj", "{E4A6624B-C1A4-4956-9FC2-E77D6C634717}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arcus.Observability.Telemetry.AzureFunctions", "Arcus.Observability.Telemetry.AzureFunctions\Arcus.Observability.Telemetry.AzureFunctions.csproj", "{C6C0ED5D-94B4-4CD2-B17A-E72432AC4883}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -65,6 +67,10 @@ Global {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Debug|Any CPU.Build.0 = Debug|Any CPU {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Release|Any CPU.ActiveCfg = Release|Any CPU {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Release|Any CPU.Build.0 = Release|Any CPU + {C6C0ED5D-94B4-4CD2-B17A-E72432AC4883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6C0ED5D-94B4-4CD2-B17A-E72432AC4883}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6C0ED5D-94B4-4CD2-B17A-E72432AC4883}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6C0ED5D-94B4-4CD2-B17A-E72432AC4883}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE