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