Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions src/Logging/Logging.EventSource/test/EventSourceLoggerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ILoggerFactory>();
return _loggerFactory = LoggerFactory.Create(builder => builder.AddEventSourceLogger());
}

public void Dispose()
{
_serviceProvider?.Dispose();
_loggerFactory?.Dispose();
}

[Fact]
Expand Down
41 changes: 41 additions & 0 deletions src/Logging/Logging/src/LoggerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -43,6 +44,18 @@ public LoggerFactory(IEnumerable<ILoggerProvider> providers, IOptionsMonitor<Log
RefreshFilters(filterOption.CurrentValue);
}

/// <summary>
/// Creates new instance of <see cref="ILoggerFactory"/> configured using provided <paramref name="configure"/> delegate.
/// </summary>
public static ILoggerFactory Create(Action<ILoggingBuilder> configure)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(configure);
var serviceProvider = serviceCollection.BuildServiceProvider();
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
return new DisposingLoggerFactory(loggerFactory, serviceProvider);
}

private void RefreshFilters(LoggerFilterOptions filterOptions)
{
lock (_sync)
Expand Down Expand Up @@ -206,5 +219,33 @@ private struct ProviderRegistration
public ILoggerProvider Provider;
public bool ShouldDispose;
}

private class DisposingLoggerFactory: ILoggerFactory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that we need to hold onto the container means all of the sample code is sorta busted

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Busted how?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you’re saying we don’t need to dispose the service provider?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this wrapper exist to begin with?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To dispose ILoggerProviders created by DI

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn’t disposing the factory do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see it wouldn’t. That makes the current usage without this API leaky.

Copy link
Author

@pakrym pakrym Dec 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't dispose the service provider - yes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m taking about examples that you would use today (even in our samples)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a sample fix.

{
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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Compile Include="../../shared/*.cs" />

<Reference Include="Microsoft.Extensions.Configuration.Binder" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="Microsoft.Extensions.DependencyInjection" />
Copy link
Member

@davidfowl davidfowl Dec 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is slightly unfortunate. But not the end of the world I guess.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this change caused these failures in my PR build. It actually showed up in your PR check too, but as a warning instead of an error.

@natemcmaster 1. Is the proper solution here (assuming it is an approved breaking change) to edit this line? 2. Should this kind of change be a warning or an error?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanbrandenburg does your PR invoke build with --warnaserror?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what Arcade defaults to. We can certainly override that anywhere (or everywhere), but I thought I'd ask since this seems like the kind of thing we might want to fail a build (even if it's just so we can document that this was an intended break).

<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />
</ItemGroup>
Expand Down
119 changes: 51 additions & 68 deletions src/Logging/samples/SampleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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())
Expand All @@ -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<ILogger<Program>>();
}

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<Program>();

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");
}
}
}
}
5 changes: 1 addition & 4 deletions src/Logging/samples/SampleApp/SampleApp.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net461;netcoreapp3.0</TargetFrameworks>
Expand All @@ -19,9 +19,6 @@
<Reference Include="Microsoft.Extensions.Logging.AzureAppServices" />
<Reference Include="Microsoft.Extensions.Logging.Configuration" />
<Reference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="Microsoft.Extensions.Logging.EventLog" />
</ItemGroup>

Expand Down
14 changes: 14 additions & 0 deletions src/Logging/test/LoggerFactoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;

Expand Down Expand Up @@ -178,6 +179,19 @@ public void BeginScope_ReturnsCompositeToken_ForMultipleLoggers()
});
}

[Fact]
public void CreateDisposeDisposesInnerServiceProvider()
{
var disposed = false;
var provider = new Mock<ILoggerProvider>();
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();
Expand Down