From 04ec9460774e9f8b9bfd5e47afc095f585f9c416 Mon Sep 17 00:00:00 2001 From: Cijo Thomas Date: Fri, 29 Mar 2019 16:35:48 -0700 Subject: [PATCH] Enable ILogger by default (#853) Enable ILogger by default when enabling application insights monitoring. --- CHANGELOG.md | 1 + Readme.md | 4 + .../ApplicationInsightsExtensions.cs | 38 ++++- ...licationInsightsLoggerFactoryExtensions.cs | 23 +-- .../ApplicationInsightsLoggerProvider.cs | 3 + ...soft.ApplicationInsights.AspNetCore.csproj | 17 +- .../TelemetryInitializerBase.cs | 2 + .../WebSessionTelemetryInitializer.cs | 1 + .../WebUserTelemetryInitializer.cs | 3 + test/FunctionalTestUtils20/InProcessServer.cs | 11 +- .../MVCFramework20.FunctionalTests20.csproj | 8 +- .../ApplicationInsightsExtensionsTests.cs | 4 +- ...pplicationInsights.AspNetCore.Tests.csproj | 13 +- .../Controllers/ValuesController.cs | 12 ++ .../FunctionalTest/LoggerTests.cs | 150 ++++++++++++++++++ .../WebApi20.FunctionalTests20.csproj | 2 +- 16 files changed, 253 insertions(+), 39 deletions(-) create mode 100644 test/WebApi20.FunctionalTests/FunctionalTest/LoggerTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7be240cc2d..866a2a6714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Version 2.7.0-beta3 +- [Enables Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider by default. If ApplicationInsightsLoggerProvider was enabled previously using ILoggerFactory extension method, please remove it to prevent duplicate logs.](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/854) - [Remove reference to Microsoft.Extensions.DiagnosticAdapter and use DiagnosticSource subscription APIs directly](https://github.com/Microsoft/ApplicationInsights-aspnetcore/pull/852) - [Fix: NullReferenceException in ApplicationInsightsLogger.Log when exception contains a Data entry with a null value](https://github.com/Microsoft/ApplicationInsights-aspnetcore/issues/848) diff --git a/Readme.md b/Readme.md index 97fc0ce2df..80c66a1e9c 100644 --- a/Readme.md +++ b/Readme.md @@ -3,6 +3,10 @@ - [Microsoft.ApplicationInsights.AspNetCore](https://www.nuget.org/packages/Microsoft.ApplicationInsights.AspNetCore/) [![Nuget](https://img.shields.io/nuget/vpre/Microsoft.ApplicationInsights.AspNetCore.svg)](https://nuget.org/packages/Microsoft.ApplicationInsights.AspNetCore) +Windows: [![Build Status](https://mseng.visualstudio.com/AppInsights/_apis/build/status/ChuckNorris/AI_ASPNETCore_Develop?branchName=develop)](https://mseng.visualstudio.com/AppInsights/_build/latest?definitionId=3717&branchName=develop) + +Linux :[![Build Status](https://mseng.visualstudio.com/AppInsights/_apis/build/status/ChuckNorris/AI-AspNetCoreSDK-develop-linux?branchName=develop)](https://mseng.visualstudio.com/AppInsights/_build/latest?definitionId=6273&branchName=develop) + Microsoft Application Insights for ASP.NET Core applications ============================================================= diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs index 9a32497f2e..a03f80ea4e 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Extensions/ApplicationInsightsExtensions.cs @@ -22,8 +22,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Memory; + using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; + using Microsoft.Extensions.Logging; /// /// Extension methods for that allow adding Application Insights services to application. @@ -190,8 +192,6 @@ public static IServiceCollection AddApplicationInsightsTelemetry(this IServiceCo services.AddSingleton(); - services.AddSingleton(); - services .TryAddSingleton, DefaultApplicationInsightsServiceConfigureOptions>(); @@ -201,12 +201,38 @@ public static IServiceCollection AddApplicationInsightsTelemetry(this IServiceCo // that requires IOptions infrastructure to run and initialize services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddOptions(); services.AddSingleton, TelemetryConfigurationOptions>(); services.AddSingleton, TelemetryConfigurationOptionsSetup>(); + + // NetStandard2.0 has a package reference to Microsoft.Extensions.Logging.ApplicationInsights, and + // enables ApplicationInsightsLoggerProvider by default. +#if NETSTANDARD2_0 + services.AddLogging(loggingBuilder => + { + loggingBuilder.AddApplicationInsights(); + + // The default behavior is to capture only logs above Warning level from all categories. + // This can achieved with this code level filter -> loggingBuilder.AddFilter("",LogLevel.Warning); + // However, this will make it impossible to override this behavior from Configuration like below using appsettings.json: + //"ApplicationInsights": { + // "LogLevel": { + // "": "Error" + // } + // }, + // The reason is as both rules will match the filter, the last one added wins. + // To ensure that the default filter is in the beginning of filter rules, so that user override from Configuration will always win, + // we add code filter rule to the 0th position as below. + + loggingBuilder.Services.Configure + (options => options.Rules.Insert(0, + new LoggerFilterRule( + "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider", null, + LogLevel.Warning, null))); + }); +#endif } return services; @@ -406,8 +432,8 @@ internal static void AddTelemetryConfiguration(IConfiguration config, private static bool IsApplicationInsightsAdded(IServiceCollection services) { - // We treat ApplicationInsightsDebugLogger as a marker that AI services were added to service collection - return services.Any(service => service.ServiceType == typeof(ApplicationInsightsDebugLogger)); + // We treat TelemetryClient as a marker that AI services were added to service collection + return services.Any(service => service.ServiceType == typeof(TelemetryClient)); } } } diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerFactoryExtensions.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerFactoryExtensions.cs index 298b4cdca2..3412418a4d 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerFactoryExtensions.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerFactoryExtensions.cs @@ -2,7 +2,7 @@ { using System; using ApplicationInsights; - using ApplicationInsights.AspNetCore.Logging; + using Microsoft.ApplicationInsights; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -16,7 +16,7 @@ public static class ApplicationInsightsLoggerFactoryExtensions /// /// /// The instance of to use for service resolution. - [Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")] + [Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")] public static ILoggerFactory AddApplicationInsights(this ILoggerFactory factory, IServiceProvider serviceProvider) { return factory.AddApplicationInsights(serviceProvider, LogLevel.Warning); @@ -28,7 +28,7 @@ public static ILoggerFactory AddApplicationInsights(this ILoggerFactory factory, /// /// The instance of to use for service resolution. /// The minimum to be logged - [Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")] + [Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")] public static ILoggerFactory AddApplicationInsights( this ILoggerFactory factory, IServiceProvider serviceProvider, @@ -44,7 +44,7 @@ public static ILoggerFactory AddApplicationInsights( /// /// /// The instance of to use for service resolution. - [Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")] + [Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")] public static ILoggerFactory AddApplicationInsights( this ILoggerFactory factory, IServiceProvider serviceProvider, @@ -60,20 +60,21 @@ public static ILoggerFactory AddApplicationInsights( /// /// The instance of to use for service resolution. /// The callback that gets executed when another ApplicationInsights logger is added. - [Obsolete("Use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package")] + [Obsolete("ApplicationInsightsLoggerProvider is now enabled by default when enabling ApplicationInsights monitoring using UseApplicationInsights extension method on IWebHostBuilder or AddApplicationInsightsTelemetry extension method on IServiceCollection. From 2.7.0-beta3 onwards, calling this method will result in double logging and filters applied will not get applied. If interested in using just logging provider, then please use Microsoft.Extensions.Logging.ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights from Microsoft.Extensions.Logging.ApplicationInsights package. Read more https://aka.ms/ApplicationInsightsILoggerFaq")] public static ILoggerFactory AddApplicationInsights( this ILoggerFactory factory, IServiceProvider serviceProvider, Func filter, Action loggerAddedCallback) - { + { + var client = serviceProvider.GetService(); - var debugLoggerControl = serviceProvider.GetService(); - var options = serviceProvider.GetService>(); + var debugLoggerControl = serviceProvider.GetService(); + var options = serviceProvider.GetService>(); if (options == null) { - options = Options.Create(new ApplicationInsightsLoggerOptions()); + options = Options.Create(new Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerOptions()); } if (debugLoggerControl != null) @@ -85,8 +86,8 @@ public static ILoggerFactory AddApplicationInsights( debugLoggerControl.LoggerAdded += loggerAddedCallback; } } - - factory.AddProvider(new ApplicationInsightsLoggerProvider(client, filter, options)); + factory.AddProvider(new Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerProvider(client, filter, options)); + return factory; } } diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerProvider.cs b/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerProvider.cs index fe247d8666..08ba8e9d5d 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerProvider.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Logging/Implementation/ApplicationInsightsLoggerProvider.cs @@ -7,7 +7,10 @@ /// /// implementation that creates returns instances of /// +#if !NETSTANDARD2_0 + // For NETSTANDARD2.0 We take dependency on Microsoft.Extensions.Logging.ApplicationInsights which has ApplicationInsightsProvider having the same ProviderAlias and don't want to clash with this ProviderAlias. [ProviderAlias("ApplicationInsights")] +#endif internal class ApplicationInsightsLoggerProvider : ILoggerProvider { private readonly TelemetryClient telemetryClient; diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj index 07f3488d3b..42c6953bd3 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj +++ b/src/Microsoft.ApplicationInsights.AspNetCore/Microsoft.ApplicationInsights.AspNetCore.csproj @@ -86,17 +86,18 @@ - - - - + - - - - + + + + + + + + diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/TelemetryInitializerBase.cs b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/TelemetryInitializerBase.cs index cd5fc6d8de..b089b40fec 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/TelemetryInitializerBase.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/TelemetryInitializerBase.cs @@ -13,11 +13,13 @@ public abstract class TelemetryInitializerBase : ITelemetryInitializer { private readonly IHttpContextAccessor httpContextAccessor; + /// public TelemetryInitializerBase(IHttpContextAccessor httpContextAccessor) { this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } + /// public void Initialize(ITelemetry telemetry) { var context = this.httpContextAccessor.HttpContext; diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebSessionTelemetryInitializer.cs b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebSessionTelemetryInitializer.cs index b7644b1d0b..debac65f4e 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebSessionTelemetryInitializer.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebSessionTelemetryInitializer.cs @@ -9,6 +9,7 @@ public class WebSessionTelemetryInitializer : TelemetryInitializerBase { private const string WebSessionCookieName = "ai_session"; + /// public WebSessionTelemetryInitializer(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor) { diff --git a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebUserTelemetryInitializer.cs b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebUserTelemetryInitializer.cs index eec4ae850a..37c051a776 100644 --- a/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebUserTelemetryInitializer.cs +++ b/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/WebUserTelemetryInitializer.cs @@ -5,15 +5,18 @@ using Microsoft.ApplicationInsights.DataContracts; using Microsoft.AspNetCore.Http; + /// public class WebUserTelemetryInitializer : TelemetryInitializerBase { private const string WebUserCookieName = "ai_user"; + /// public WebUserTelemetryInitializer(IHttpContextAccessor httpContextAccessor) : base(httpContextAccessor) { } + /// protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry) { if (!string.IsNullOrEmpty(telemetry.Context.User.Id)) diff --git a/test/FunctionalTestUtils20/InProcessServer.cs b/test/FunctionalTestUtils20/InProcessServer.cs index 8493a94e42..f8a9fe2fde 100644 --- a/test/FunctionalTestUtils20/InProcessServer.cs +++ b/test/FunctionalTestUtils20/InProcessServer.cs @@ -40,8 +40,9 @@ public class InProcessServer : IDisposable private TelemetryHttpListenerObservable listener; private readonly Func configureHost; + private readonly Action configureServices; - public InProcessServer(string assemblyName, ITestOutputHelper output, Func configureHost = null) + public InProcessServer(string assemblyName, ITestOutputHelper output, Func configureHost = null, Action configureServices = null) { this.output = output; @@ -49,6 +50,7 @@ public InProcessServer(string assemblyName, ITestOutputHelper output, Func this.configureServices(services)); + } + this.hostingEngine = builder.Build(); this.hostingEngine.Start(); diff --git a/test/MVCFramework20.FunctionalTests/MVCFramework20.FunctionalTests20.csproj b/test/MVCFramework20.FunctionalTests/MVCFramework20.FunctionalTests20.csproj index dbb25e622b..851b9cef19 100644 --- a/test/MVCFramework20.FunctionalTests/MVCFramework20.FunctionalTests20.csproj +++ b/test/MVCFramework20.FunctionalTests/MVCFramework20.FunctionalTests20.csproj @@ -1,4 +1,4 @@ - + 2.0.0 @@ -56,10 +56,10 @@ - - + + - + diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs index 22409f81c2..5c3b4f3f90 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Extensions/ApplicationInsightsExtensionsTests.cs @@ -145,10 +145,10 @@ public static void ConfigurationFactoryMethodUpdatesTheActiveConfigurationSingle /// /// We determine if Active telemtery needs to be configured based on the assumptions that 'default' configuration - // created by base SDK has single preset ITelemetryIntitializer. If it ever changes, change TelemetryConfigurationOptions.IsActiveConfigured method as well. + // created by base SDK has single preset ITelemetryInitializer. If it ever changes, change TelemetryConfigurationOptions.IsActiveConfigured method as well. /// [Fact] - public static void DefaultTelemetryconfigurationHasOneTelemetryInitializer() + public static void DefaultTelemetryConfigurationHasOneTelemetryInitializer() { // var defaultConfig = TelemetryConfiguration.CreateDefault(); diff --git a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Microsoft.ApplicationInsights.AspNetCore.Tests.csproj b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Microsoft.ApplicationInsights.AspNetCore.Tests.csproj index 415f277247..e62b415762 100644 --- a/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Microsoft.ApplicationInsights.AspNetCore.Tests.csproj +++ b/test/Microsoft.ApplicationInsights.AspNetCore.Tests/Microsoft.ApplicationInsights.AspNetCore.Tests.csproj @@ -35,15 +35,18 @@ - - - + + + + + + @@ -51,8 +54,8 @@ - - + + diff --git a/test/WebApi20.FunctionalTests/Controllers/ValuesController.cs b/test/WebApi20.FunctionalTests/Controllers/ValuesController.cs index 7dfe6c0ec7..626965abfe 100644 --- a/test/WebApi20.FunctionalTests/Controllers/ValuesController.cs +++ b/test/WebApi20.FunctionalTests/Controllers/ValuesController.cs @@ -3,12 +3,20 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; namespace WebApi20.FunctionalTests.Controllers { [Route("api/[controller]")] public class ValuesController : Controller { + ILogger logger; + + public ValuesController(ILogger logger) + { + this.logger = logger; + } + // GET api/values [HttpGet] public IEnumerable Get() @@ -20,6 +28,10 @@ public IEnumerable Get() [HttpGet("{id}")] public string Get(int id) { + logger.LogError("error logged"); + logger.LogWarning("warning logged"); + logger.LogInformation("information logged"); + logger.LogTrace("trace logged"); return "value"; } diff --git a/test/WebApi20.FunctionalTests/FunctionalTest/LoggerTests.cs b/test/WebApi20.FunctionalTests/FunctionalTest/LoggerTests.cs new file mode 100644 index 0000000000..9809af0461 --- /dev/null +++ b/test/WebApi20.FunctionalTests/FunctionalTest/LoggerTests.cs @@ -0,0 +1,150 @@ +namespace FunctionalTests +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Text.RegularExpressions; + + using FunctionalTestUtils; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.ApplicationInsights.DataContracts; + using Microsoft.ApplicationInsights.DependencyCollector; + using Xunit; + using Xunit.Abstractions; + using AI; + using Microsoft.Extensions.Logging; + + /// + /// These are Functional Tests validating E2E ILogger integration. Though filtering mechanism is done by the ILogger framework itself, we + /// are here testing that the integration is done in correct ways. + /// Specifically, + /// 1. By Default, Warning and above from All categories is expected to captured. + /// 2. Any overriding done by user is respected and will override default behaviour + /// + public class LoggerTests : TelemetryTestsBase, IDisposable + { + private const string assemblyName = "WebApi20.FunctionalTests20"; + public LoggerTests(ITestOutputHelper output) : base (output) + { + } + + [Fact] + public void TestIloggerWarningOrAboveIsCapturedByDefault() + { + +#if NETCOREAPP2_0 + using (var server = new InProcessServer(assemblyName, this.output)) + { + // Make request to this path, which sents one log of each severity Error, Warning, Information, Trace + this.ExecuteRequest(server.BaseHost + "/api/values/5"); + + // By default, AI is expected to capture Warning, Error + var actual = server.Listener.ReceiveItemsOfType>(2, TestListenerTimeoutInMs); + this.DebugTelemetryItems(actual); + + // Expect 2 items. + Assert.Equal(2, actual.Count()); + + ValidateMessage(actual[0], new string[] {"error", "warning" }); + ValidateMessage(actual[1], new string[] { "error", "warning" }); + } +#endif + } + + [Fact] + public void TestIloggerDefaultsCanBeOverridenByUserForAllCategories() + { + +#if NETCOREAPP2_0 + void ConfigureServices(IServiceCollection services) + { + // ARRANGE + // AddFilter to capture only Error. This is expected to override default behavior. + services.AddLogging(builder => builder.AddFilter("", LogLevel.Error)); + } + + using (var server = new InProcessServer(assemblyName, this.output,null, ConfigureServices)) + { + // Make request to this path, which sents one log of each severity Error, Warning, Information, Trace + this.ExecuteRequest(server.BaseHost + "/api/values/5"); + + // AI is now expected to capture only Error + var actual = server.Listener.ReceiveItemsOfType>(1, TestListenerTimeoutInMs); + this.DebugTelemetryItems(actual); + + // Expect 1 item1. + Assert.Equal(1, actual.Count()); + + ValidateMessage(actual[0], new string[] { "error"}); + } +#endif + } + + [Fact] + public void TestIloggerDefaultsCanBeOverridenByUserForSpecificCategory() + { + +#if NETCOREAPP2_0 + void ConfigureServices(IServiceCollection services) + { + // ARRANGE + // AddFilter to capture Trace or above for user category. This is expected to override default behavior. + services.AddLogging(builder => builder.AddFilter("WebApi20.FunctionalTests.Controllers", LogLevel.Trace)); + } + + using (var server = new InProcessServer(assemblyName, this.output, null, ConfigureServices)) + { + // Make request to this path, which sents one log of each severity Error, Warning, Information, Trace + this.ExecuteRequest(server.BaseHost + "/api/values/5"); + + // AI is now expected to capture Warning or above for all categories (default behavior), except 'WebApi20.FunctionalTests.Controllers' category where Trace of above + // is captured. (overridden behavior) + var actual = server.Listener.ReceiveItemsOfType>(4, TestListenerTimeoutInMs); + this.DebugTelemetryItems(actual); + + // Expect 4 items. + Assert.Equal(4, actual.Count()); + + ValidateMessage(actual[0], new string[] { "error" }); + ValidateMessage(actual[1], new string[] { "warning" }); + ValidateMessage(actual[2], new string[] { "information" }); + ValidateMessage(actual[3], new string[] { "trace" }); + } +#endif + } + + + private bool ValidateMessage(Envelope item, string[] expectedMessages) + { + if (!(item is TelemetryItem trace)) + { + return false; + } + + var actualMessage = trace.data.baseData.message; + + bool foundMessage = false; + foreach (var msg in expectedMessages) + { + if(actualMessage.Contains(msg)) + { + foundMessage = true; + break; + } + } + + return foundMessage; + } + + public void Dispose() + { + while (Activity.Current != null) + { + Activity.Current.Stop(); + } + } + } +} + diff --git a/test/WebApi20.FunctionalTests/WebApi20.FunctionalTests20.csproj b/test/WebApi20.FunctionalTests/WebApi20.FunctionalTests20.csproj index 3997872038..ea69a78927 100644 --- a/test/WebApi20.FunctionalTests/WebApi20.FunctionalTests20.csproj +++ b/test/WebApi20.FunctionalTests/WebApi20.FunctionalTests20.csproj @@ -35,7 +35,7 @@ - +