Skip to content

Commit 7d51e51

Browse files
committed
Supply services when configuring Serilog inline
1 parent 6a8e484 commit 7d51e51

File tree

4 files changed

+113
-26
lines changed

4 files changed

+113
-26
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "2.2.105"
3+
"version": "3.1.201"
44
}
55
}

serilog-extensions-hosting.sln.DotSettings

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
33
<s:Boolean x:Key="/Default/UserDictionary/Words/=benaadams/@EntryIndexedValue">True</s:Boolean>
44
<s:Boolean x:Key="/Default/UserDictionary/Words/=destructure/@EntryIndexedValue">True</s:Boolean>
5+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Enricher/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/UserDictionary/Words/=MEDI/@EntryIndexedValue">True</s:Boolean>
57
<s:Boolean x:Key="/Default/UserDictionary/Words/=Serilog/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2020 Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Serilog.Core;
16+
using Serilog.Events;
17+
18+
namespace Serilog.Extensions.Hosting
19+
{
20+
// Does nothing, but makes it easy to create an `ILogger` from a Serilog `Logger`
21+
// that will not dispose the underlying pipeline when disposed itself.
22+
class NullEnricher : ILogEventEnricher
23+
{
24+
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
25+
{
26+
}
27+
}
28+
}

src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 Serilog Contributors
1+
// Copyright 2020 Serilog Contributors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -13,9 +13,9 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using Microsoft.Extensions.DependencyInjection;
1617
using Microsoft.Extensions.Hosting;
1718
using Microsoft.Extensions.Logging;
18-
using Microsoft.Extensions.DependencyInjection;
1919
using Serilog.Extensions.Hosting;
2020
using Serilog.Extensions.Logging;
2121

@@ -26,16 +26,27 @@ namespace Serilog
2626
/// </summary>
2727
public static class SerilogHostBuilderExtensions
2828
{
29+
// Used internally to pass information through the container.
30+
class RegisteredLogger
31+
{
32+
public RegisteredLogger(ILogger logger)
33+
{
34+
Logger = logger;
35+
}
36+
37+
public ILogger Logger { get; }
38+
}
39+
2940
/// <summary>
3041
/// Sets Serilog as the logging provider.
3142
/// </summary>
3243
/// <param name="builder">The host builder to configure.</param>
3344
/// <param name="logger">The Serilog logger; if not supplied, the static <see cref="Serilog.Log"/> will be used.</param>
3445
/// <param name="dispose">When <c>true</c>, dispose <paramref name="logger"/> when the framework disposes the provider. If the
35-
/// logger is not specified but <paramref name="dispose"/> is <c>true</c>, the <see cref="Log.CloseAndFlush()"/> method will be
36-
/// called on the static <see cref="Log"/> class instead.</param>
46+
/// logger is not specified but <paramref name="dispose"/> is <c>true</c>, the <see cref="Serilog.Log.CloseAndFlush()"/> method will be
47+
/// called on the static <see cref="Serilog.Log"/> class instead.</param>
3748
/// <param name="providers">A <see cref="LoggerProviderCollection"/> registered in the Serilog pipeline using the
38-
/// <c>WriteTo.Providers()</c> configuration method, enabling other <see cref="ILoggerProvider"/>s to receive events. By
49+
/// <c>WriteTo.Providers()</c> configuration method, enabling other <see cref="Microsoft.Extensions.Logging.ILoggerProvider"/>s to receive events. By
3950
/// default, only Serilog sinks will receive events.</param>
4051
/// <returns>The host builder.</returns>
4152
public static IHostBuilder UseSerilog(
@@ -71,14 +82,15 @@ public static IHostBuilder UseSerilog(
7182
return builder;
7283
}
7384

85+
7486
/// <summary>Sets Serilog as the logging provider.</summary>
7587
/// <remarks>
7688
/// A <see cref="HostBuilderContext"/> is supplied so that configuration and hosting information can be used.
7789
/// The logger will be shut down when application services are disposed.
7890
/// </remarks>
7991
/// <param name="builder">The host builder to configure.</param>
80-
/// <param name="configureLogger">The delegate for configuring the <see cref="LoggerConfiguration" /> that will be used to construct a <see cref="Microsoft.Extensions.Logging.Logger" />.</param>
81-
/// <param name="preserveStaticLogger">Indicates whether to preserve the value of <see cref="Log.Logger"/>.</param>
92+
/// <param name="configureLogger">The delegate for configuring the <see cref="Serilog.LoggerConfiguration" /> that will be used to construct a <see cref="Serilog.Core.Logger" />.</param>
93+
/// <param name="preserveStaticLogger">Indicates whether to preserve the value of <see cref="Serilog.Log.Logger"/>.</param>
8294
/// <param name="writeToProviders">By default, Serilog does not write events to <see cref="ILoggerProvider"/>s registered through
8395
/// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
8496
/// <c>true</c> to write events to all providers.</param>
@@ -91,35 +103,80 @@ public static IHostBuilder UseSerilog(
91103
{
92104
if (builder == null) throw new ArgumentNullException(nameof(builder));
93105
if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
106+
return UseSerilog(
107+
builder,
108+
(hostBuilderContext, services, loggerConfiguration) =>
109+
configureLogger(hostBuilderContext, loggerConfiguration),
110+
preserveStaticLogger: preserveStaticLogger,
111+
writeToProviders: writeToProviders);
112+
}
113+
114+
/// <summary>Sets Serilog as the logging provider.</summary>
115+
/// <remarks>
116+
/// A <see cref="HostBuilderContext"/> is supplied so that configuration and hosting information can be used.
117+
/// The logger will be shut down when application services are disposed.
118+
/// </remarks>
119+
/// <param name="builder">The host builder to configure.</param>
120+
/// <param name="configureLogger">The delegate for configuring the <see cref="Serilog.LoggerConfiguration" /> that will be used to construct a <see cref="Serilog.Core.Logger" />.</param>
121+
/// <param name="preserveStaticLogger">Indicates whether to preserve the value of <see cref="Serilog.Log.Logger"/>.</param>
122+
/// <param name="writeToProviders">By default, Serilog does not write events to <see cref="ILoggerProvider"/>s registered through
123+
/// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
124+
/// <c>true</c> to write events to all providers.</param>
125+
/// <returns>The host builder.</returns>
126+
public static IHostBuilder UseSerilog(
127+
this IHostBuilder builder,
128+
Action<HostBuilderContext, IServiceProvider, LoggerConfiguration> configureLogger,
129+
bool preserveStaticLogger = false,
130+
bool writeToProviders = false)
131+
{
132+
if (builder == null) throw new ArgumentNullException(nameof(builder));
133+
if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
94134

95135
builder.ConfigureServices((context, collection) =>
96136
{
97-
var loggerConfiguration = new LoggerConfiguration();
98-
99137
LoggerProviderCollection loggerProviders = null;
100138
if (writeToProviders)
101139
{
102140
loggerProviders = new LoggerProviderCollection();
103-
loggerConfiguration.WriteTo.Providers(loggerProviders);
104141
}
105-
106-
configureLogger(context, loggerConfiguration);
107-
var logger = loggerConfiguration.CreateLogger();
108142

109-
ILogger registeredLogger = null;
110-
if (preserveStaticLogger)
111-
{
112-
registeredLogger = logger;
113-
}
114-
else
143+
collection.AddSingleton(services =>
115144
{
116-
// Passing a `null` logger to `SerilogLoggerFactory` results in disposal via
117-
// `Log.CloseAndFlush()`, which additionally replaces the static logger with a no-op.
118-
Log.Logger = logger;
119-
}
145+
var loggerConfiguration = new LoggerConfiguration();
146+
147+
if (loggerProviders != null)
148+
loggerConfiguration.WriteTo.Providers(loggerProviders);
149+
150+
configureLogger(context, services, loggerConfiguration);
151+
var logger = loggerConfiguration.CreateLogger();
152+
153+
return new RegisteredLogger(logger);
154+
});
120155

156+
collection.AddSingleton(services =>
157+
{
158+
// How can we register the logger, here, but not have MEDI dispose it?
159+
// Using the `NullEnricher` hack to prevent disposal.
160+
var logger = services.GetRequiredService<RegisteredLogger>().Logger;
161+
return logger.ForContext(new NullEnricher());
162+
});
163+
121164
collection.AddSingleton<ILoggerFactory>(services =>
122165
{
166+
var logger = services.GetRequiredService<RegisteredLogger>().Logger;
167+
168+
ILogger registeredLogger = null;
169+
if (preserveStaticLogger)
170+
{
171+
registeredLogger = logger;
172+
}
173+
else
174+
{
175+
// Passing a `null` logger to `SerilogLoggerFactory` results in disposal via
176+
// `Log.CloseAndFlush()`, which additionally replaces the static logger with a no-op.
177+
Log.Logger = logger;
178+
}
179+
123180
var factory = new SerilogLoggerFactory(registeredLogger, true, loggerProviders);
124181

125182
if (writeToProviders)
@@ -130,8 +187,8 @@ public static IHostBuilder UseSerilog(
130187

131188
return factory;
132189
});
133-
134-
ConfigureServices(collection, logger);
190+
191+
ConfigureServices(collection, null);
135192
});
136193
return builder;
137194
}

0 commit comments

Comments
 (0)