diff --git a/src/Logging/Logging.EventSource/test/EventSourceLoggerTest.cs b/src/Logging/Logging.EventSource/test/EventSourceLoggerTest.cs index 524a29a6fd7..e005e141fad 100644 --- a/src/Logging/Logging.EventSource/test/EventSourceLoggerTest.cs +++ b/src/Logging/Logging.EventSource/test/EventSourceLoggerTest.cs @@ -15,20 +15,16 @@ namespace Microsoft.Extensions.Logging.Test { public class EventSourceLoggerTest: IDisposable { - private ServiceProvider _serviceProvider; + private ILoggerFactory _loggerFactory; protected ILoggerFactory CreateLoggerFactory() { - _serviceProvider = new ServiceCollection() - .AddLogging(builder => builder.AddEventSourceLogger()) - .BuildServiceProvider(); - - return _serviceProvider.GetRequiredService(); + return _loggerFactory = LoggerFactory.Create(builder => builder.AddEventSourceLogger()); } public void Dispose() { - _serviceProvider?.Dispose(); + _loggerFactory?.Dispose(); } [Fact] diff --git a/src/Logging/Logging/src/LoggerFactory.cs b/src/Logging/Logging/src/LoggerFactory.cs index 76d87538f53..9fa2b359830 100644 --- a/src/Logging/Logging/src/LoggerFactory.cs +++ b/src/Logging/Logging/src/LoggerFactory.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging @@ -43,6 +44,18 @@ public LoggerFactory(IEnumerable providers, IOptionsMonitor + /// Creates new instance of configured using provided delegate. + /// + public static ILoggerFactory Create(Action configure) + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(configure); + var serviceProvider = serviceCollection.BuildServiceProvider(); + var loggerFactory = serviceProvider.GetService(); + return new DisposingLoggerFactory(loggerFactory, serviceProvider); + } + private void RefreshFilters(LoggerFilterOptions filterOptions) { lock (_sync) @@ -206,5 +219,33 @@ private struct ProviderRegistration public ILoggerProvider Provider; public bool ShouldDispose; } + + private class DisposingLoggerFactory: ILoggerFactory + { + private readonly ILoggerFactory _loggerFactory; + + private readonly ServiceProvider _serviceProvider; + + public DisposingLoggerFactory(ILoggerFactory loggerFactory, ServiceProvider serviceProvider) + { + _loggerFactory = loggerFactory; + _serviceProvider = serviceProvider; + } + + public void Dispose() + { + _serviceProvider.Dispose(); + } + + public ILogger CreateLogger(string categoryName) + { + return _loggerFactory.CreateLogger(categoryName); + } + + public void AddProvider(ILoggerProvider provider) + { + _loggerFactory.AddProvider(provider); + } + } } } diff --git a/src/Logging/Logging/src/Microsoft.Extensions.Logging.csproj b/src/Logging/Logging/src/Microsoft.Extensions.Logging.csproj index 54aa595329f..2c0555af1af 100644 --- a/src/Logging/Logging/src/Microsoft.Extensions.Logging.csproj +++ b/src/Logging/Logging/src/Microsoft.Extensions.Logging.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Logging/samples/SampleApp/Program.cs b/src/Logging/samples/SampleApp/Program.cs index cf5c1c708a2..fce09c8ab62 100644 --- a/src/Logging/samples/SampleApp/Program.cs +++ b/src/Logging/samples/SampleApp/Program.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -12,9 +12,7 @@ namespace SampleApp { public class Program { - private readonly ILogger _logger; - - public Program() + public static void Main(string[] args) { var loggingConfiguration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) @@ -23,82 +21,67 @@ public Program() // A Web App based program would configure logging via the WebHostBuilder. // Create a logger factory with filters that can be applied across all logger providers. - var serviceCollection = new ServiceCollection() - .AddLogging(builder => - { - builder - .AddConfiguration(loggingConfiguration.GetSection("Logging")) - .AddFilter("Microsoft", LogLevel.Warning) - .AddFilter("System", LogLevel.Warning) - .AddFilter("SampleApp.Program", LogLevel.Debug) - .AddConsole(); -#if NET461 - builder.AddEventLog(); -#elif NETCOREAPP3_0 -#else -#error Target framework needs to be updated -#endif - }); - - // providers may be added to a LoggerFactory before any loggers are created - - - var serviceProvider = serviceCollection.BuildServiceProvider(); - // getting the logger using the class's name is conventional - _logger = serviceProvider.GetRequiredService>(); - } - - public static void Main(string[] args) - { - new Program().Execute(args); - } + var loggerFactory = LoggerFactory.Create(builder => + { + builder + .AddConfiguration(loggingConfiguration.GetSection("Logging")) + .AddFilter("Microsoft", LogLevel.Warning) + .AddFilter("System", LogLevel.Warning) + .AddFilter("SampleApp.Program", LogLevel.Debug) + .AddConsole() + .AddEventLog(); + }); + + // Make sure to dispose ILoggerFactory + using (loggerFactory) + { + var logger = loggerFactory.CreateLogger(); - public void Execute(string[] args) - { - _logger.LogInformation("Starting"); + logger.LogInformation("Starting"); - var startTime = DateTimeOffset.Now; - _logger.LogInformation(1, "Started at '{StartTime}' and 0x{Hello:X} is hex of 42", startTime, 42); - // or - _logger.ProgramStarting(startTime, 42); + var startTime = DateTimeOffset.Now; + logger.LogInformation(1, "Started at '{StartTime}' and 0x{Hello:X} is hex of 42", startTime, 42); + // or + logger.ProgramStarting(startTime, 42); - using (_logger.PurchaseOrderScope("00655321")) - { - try - { - throw new Exception("Boom"); - } - catch (Exception ex) + using (logger.PurchaseOrderScope("00655321")) { - _logger.LogCritical(1, ex, "Unexpected critical error starting application"); - _logger.LogError(1, ex, "Unexpected error"); - _logger.LogWarning(1, ex, "Unexpected warning"); - } + try + { + throw new Exception("Boom"); + } + catch (Exception ex) + { + logger.LogCritical(1, ex, "Unexpected critical error starting application"); + logger.LogError(1, ex, "Unexpected error"); + logger.LogWarning(1, ex, "Unexpected warning"); + } - using (_logger.BeginScope("Main")) - { + using (logger.BeginScope("Main")) + { - _logger.LogInformation("Waiting for user input"); + logger.LogInformation("Waiting for user input"); - string input; - do - { - Console.WriteLine("Enter some test to log more, or 'quit' to exit."); - input = Console.ReadLine(); + string input; + do + { + Console.WriteLine("Enter some test to log more, or 'quit' to exit."); + input = Console.ReadLine(); - _logger.LogInformation("User typed '{input}' on the command line", input); - _logger.LogWarning("The time is now {Time}, it's getting late!", DateTimeOffset.Now); + logger.LogInformation("User typed '{input}' on the command line", input); + logger.LogWarning("The time is now {Time}, it's getting late!", DateTimeOffset.Now); + } + while (input != "quit"); } - while (input != "quit"); } - } - var endTime = DateTimeOffset.Now; - _logger.LogInformation(2, "Stopping at '{StopTime}'", endTime); - // or - _logger.ProgramStopping(endTime); + var endTime = DateTimeOffset.Now; + logger.LogInformation(2, "Stopping at '{StopTime}'", endTime); + // or + logger.ProgramStopping(endTime); - _logger.LogInformation("Stopping"); + logger.LogInformation("Stopping"); + } } } } diff --git a/src/Logging/samples/SampleApp/SampleApp.csproj b/src/Logging/samples/SampleApp/SampleApp.csproj index 3d6558ae20a..a47dbf96938 100644 --- a/src/Logging/samples/SampleApp/SampleApp.csproj +++ b/src/Logging/samples/SampleApp/SampleApp.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp3.0 @@ -19,9 +19,6 @@ - - - diff --git a/src/Logging/test/LoggerFactoryTest.cs b/src/Logging/test/LoggerFactoryTest.cs index e51ce70066d..242dad40b08 100644 --- a/src/Logging/test/LoggerFactoryTest.cs +++ b/src/Logging/test/LoggerFactoryTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -178,6 +179,19 @@ public void BeginScope_ReturnsCompositeToken_ForMultipleLoggers() }); } + [Fact] + public void CreateDisposeDisposesInnerServiceProvider() + { + var disposed = false; + var provider = new Mock(); + provider.Setup(p => p.Dispose()).Callback(() => disposed = true); + + var factory = LoggerFactory.Create(builder => builder.Services.AddSingleton(_=> provider.Object)); + factory.Dispose(); + + Assert.True(disposed); + } + private class InternalScopeLoggerProvider : ILoggerProvider, ILogger { private IExternalScopeProvider _scopeProvider = new LoggerExternalScopeProvider();