diff --git a/README.md b/README.md index efb5643..eb17258 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Serilog.Extensions.Hosting [![Build status](https://ci.appveyor.com/api/projects/status/ue4s7htjwj88fulh?svg=true)](https://ci.appveyor.com/project/serilog/serilog-extensions-hosting) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Extensions.Hosting.svg?style=flat)](https://www.nuget.org/packages/Serilog.Extensions.Hosting/) -Serilog logging for Microsoft.Extensions.Hosting . This package routes Microsoft.Extensions.Hosting log messages through Serilog, so you can get information about the framework's internal operations logged to the same Serilog sinks as your application events. +Serilog logging for _Microsoft.Extensions.Hosting_. This package routes framework log messages through Serilog, so you can get information about the framework's internal operations written to the same Serilog sinks as your application events. + +**ASP.NET Core** applications should consider [using _Serilog.AspNetCore_ instead](https://github.com/serilog/serilog-aspnetcore), which bundles this package and includes other ASP.NET Core-specific features. ### Instructions @@ -54,7 +56,7 @@ public class Program } ``` -**Finally**, clean up by removing the rema `"Logging"` section from _appsettings.json_ files (this can be replaced with [Serilog configuration](https://github.com/serilog/serilog-settings-configuration) as shown in [this example](https://github.com/serilog/serilog-hosting/blob/dev/samples/SimpleServiceSample/Program.cs), if required) +**Finally**, clean up by removing the remaining `"Logging"` section from _appsettings.json_ files (this can be replaced with [Serilog configuration](https://github.com/serilog/serilog-settings-configuration) as shown in [this example](https://github.com/serilog/serilog-extensions-hosting/blob/dev/samples/SimpleServiceSample/Program.cs), if required) That's it! You will see log output like: @@ -63,7 +65,7 @@ That's it! You will see log output like: [22:10:39 INF] The current time is: 12/05/2018 10:10:39 +00:00 ``` -A more complete example, showing _appsettings.json_ configuration, can be found in [the sample project here](https://github.com/serilog/serilog-hostinh/tree/dev/samples/SimpleServiceSample). +A more complete example, showing _appsettings.json_ configuration, can be found in [the sample project here](https://github.com/serilog/serilog-hosting/tree/dev/samples/SimpleServiceSample). ### Using the package @@ -78,39 +80,11 @@ You can alternatively configure Serilog using a delegate as shown below: ```csharp // dotnet add package Serilog.Settings.Configuration .UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration - .ReadFrom.Configuration(hostingContext.Configuration) - .Enrich.FromLogContext() - .WriteTo.Console()) + .ReadFrom.Configuration(hostingContext.Configuration) + .Enrich.FromLogContext() + .WriteTo.Console()) ``` This has the advantage of making the `hostingContext`'s `Configuration` object available for configuration of the logger, but at the expense of recording `Exception`s raised earlier in program startup. If this method is used, `Log.Logger` is assigned implicitly, and closed when the app is shut down. - -### Writing to the Azure Diagnostics Log Stream - -The Azure Diagnostic Log Stream ships events from any files in the `D:\home\LogFiles\` folder. To enable this for your app, first install the _Serilog.Sinks.File_ package: - -```powershell -Install-Package Serilog.Sinks.File -``` - -Then add a file sink to your `LoggerConfiguration`, taking care to set the `shared` and `flushToDiskInterval` parameters: - -```csharp - public static int Main(string[] args) - { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) - .Enrich.FromLogContext() - .WriteTo.Console() - // Add this line: - .WriteTo.File( - @"D:\home\LogFiles\Application\myapp.txt", - fileSizeLimitBytes: 1_000_000, - rollOnFileSizeLimit: true, - shared: true, - flushToDiskInterval: TimeSpan.FromSeconds(1)) - .CreateLogger(); -``` diff --git a/appveyor.yml b/appveyor.yml index 02761fd..9ca24f7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,10 +7,13 @@ build_script: - ps: ./Build.ps1 artifacts: - path: artifacts/Serilog.*.nupkg +skip_commits: + files: + - README.md deploy: - provider: NuGet api_key: - secure: bd9z4P73oltOXudAjPehwp9iDKsPtC+HbgshOrSgoyQKr5xVK+bxJQngrDJkHdY8 + secure: JAnOxPQMZRp8ousbAW4vYnVtd936AOMp4gDGucCQ1RZrDZW3J+X5QmbLO7OJKtBr skip_symbols: true on: branch: /^(master|dev)$/ diff --git a/global.json b/global.json index 6b51ddf..0a37afd 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.300-*" + "version": "2.2.105" } } diff --git a/samples/SimpleServiceSample/PrintTimeService.cs b/samples/SimpleServiceSample/PrintTimeService.cs index aa59fd0..513cace 100644 --- a/samples/SimpleServiceSample/PrintTimeService.cs +++ b/samples/SimpleServiceSample/PrintTimeService.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace SimpleWebSample +namespace SimpleServiceSample { public class PrintTimeService : IHostedService, IDisposable { diff --git a/samples/SimpleServiceSample/Program.cs b/samples/SimpleServiceSample/Program.cs index b357b10..4ff6e7e 100644 --- a/samples/SimpleServiceSample/Program.cs +++ b/samples/SimpleServiceSample/Program.cs @@ -1,11 +1,11 @@ using System; using System.IO; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; -using Serilog; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; -namespace SimpleWebSample +namespace SimpleServiceSample { public class Program { diff --git a/samples/SimpleServiceSample/SimpleServiceSample.csproj b/samples/SimpleServiceSample/SimpleServiceSample.csproj index aadac55..36bbcf2 100644 --- a/samples/SimpleServiceSample/SimpleServiceSample.csproj +++ b/samples/SimpleServiceSample/SimpleServiceSample.csproj @@ -13,12 +13,12 @@ - - - - - - + + + + + + diff --git a/serilog-extensions-hosting.sln.DotSettings b/serilog-extensions-hosting.sln.DotSettings new file mode 100644 index 0000000..87d9b7b --- /dev/null +++ b/serilog-extensions-hosting.sln.DotSettings @@ -0,0 +1,5 @@ + + True + True + True + True \ No newline at end of file diff --git a/src/Serilog.Extensions.Hosting/Extensions/Hosting/AmbientDiagnosticContextCollector.cs b/src/Serilog.Extensions.Hosting/Extensions/Hosting/AmbientDiagnosticContextCollector.cs new file mode 100644 index 0000000..68010ee --- /dev/null +++ b/src/Serilog.Extensions.Hosting/Extensions/Hosting/AmbientDiagnosticContextCollector.cs @@ -0,0 +1,46 @@ +// Copyright 2019 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Threading; + +namespace Serilog.Extensions.Hosting +{ + class AmbientDiagnosticContextCollector : IDisposable + { + static readonly AsyncLocal AmbientCollector = + new AsyncLocal(); + + // The indirection here ensures that completing collection cleans up the collector in all + // execution contexts. Via @benaadams' addition to `HttpContextAccessor` :-) + DiagnosticContextCollector _collector; + + public static DiagnosticContextCollector Current => AmbientCollector.Value?._collector; + + public static DiagnosticContextCollector Begin() + { + var value = new AmbientDiagnosticContextCollector(); + value._collector = new DiagnosticContextCollector(value); + AmbientCollector.Value = value; + return value._collector; + } + + public void Dispose() + { + _collector = null; + if (AmbientCollector.Value == this) + AmbientCollector.Value = null; + } + } +} diff --git a/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs b/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs new file mode 100644 index 0000000..7c12c19 --- /dev/null +++ b/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs @@ -0,0 +1,60 @@ +// Copyright 2019 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Threading; + +namespace Serilog.Extensions.Hosting +{ + /// + /// Implements an ambient diagnostic context using . + /// + /// Consumers should use to set context properties. + public sealed class DiagnosticContext : IDiagnosticContext + { + readonly ILogger _logger; + + /// + /// Construct a . + /// + /// A logger for binding properties in the context, or null to use . + public DiagnosticContext(ILogger logger) + { + _logger = logger; + } + + /// + /// Start collecting properties to associate with the current diagnostic context. This will replace + /// the active collector, if any. + /// + /// A collector that will receive properties added in the current diagnostic context. + public DiagnosticContextCollector BeginCollection() + { + return AmbientDiagnosticContextCollector.Begin(); + } + + /// + public void Set(string propertyName, object value, bool destructureObjects = false) + { + if (propertyName == null) throw new ArgumentNullException(nameof(propertyName)); + + var collector = AmbientDiagnosticContextCollector.Current; + if (collector != null && + (_logger ?? Log.Logger).BindProperty(propertyName, value, destructureObjects, out var property)) + { + collector.AddOrUpdate(property); + } + } + } +} diff --git a/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs b/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs new file mode 100644 index 0000000..d1aba65 --- /dev/null +++ b/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Serilog.Events; + +namespace Serilog.Extensions.Hosting +{ + /// + /// A container that receives properties added to a diagnostic context. + /// + public sealed class DiagnosticContextCollector : IDisposable + { + readonly IDisposable _chainedDisposable; + readonly object _propertiesLock = new object(); + Dictionary _properties = new Dictionary(); + + /// + /// Construct a . + /// + /// An object that will be disposed to signal completion/disposal of + /// the collector. + public DiagnosticContextCollector(IDisposable chainedDisposable) + { + _chainedDisposable = chainedDisposable ?? throw new ArgumentNullException(nameof(chainedDisposable)); + } + + /// + /// Add the property to the context. + /// + /// The property to add. + public void AddOrUpdate(LogEventProperty property) + { + if (property == null) throw new ArgumentNullException(nameof(property)); + + lock (_propertiesLock) + { + if (_properties == null) return; + _properties[property.Name] = property; + } + } + + /// + /// Complete the context and retrieve the properties added to it, if any. This will + /// stop collection and remove the collector from the original execution context and + /// any of its children. + /// + /// The collected properties, or null if no collection is active. + /// True if properties could be collected. + public bool TryComplete(out IEnumerable properties) + { + lock (_propertiesLock) + { + properties = _properties?.Values; + _properties = null; + Dispose(); + return properties != null; + } + } + + /// + public void Dispose() + { + _chainedDisposable.Dispose(); + } + } +} diff --git a/src/Serilog.Extensions.Hosting/Hosting/SerilogLoggerFactory.cs b/src/Serilog.Extensions.Hosting/Extensions/Hosting/SerilogLoggerFactory.cs similarity index 87% rename from src/Serilog.Extensions.Hosting/Hosting/SerilogLoggerFactory.cs rename to src/Serilog.Extensions.Hosting/Extensions/Hosting/SerilogLoggerFactory.cs index 1c91166..1b100b9 100644 --- a/src/Serilog.Extensions.Hosting/Hosting/SerilogLoggerFactory.cs +++ b/src/Serilog.Extensions.Hosting/Extensions/Hosting/SerilogLoggerFactory.cs @@ -12,18 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System; +using System.ComponentModel; using Microsoft.Extensions.Logging; using Serilog.Debugging; using Serilog.Extensions.Logging; +// To line up with the convention used elsewhere in the *.Extensions libraries, this +// should have been Serilog.Extensions.Hosting. +// ReSharper disable once CheckNamespace namespace Serilog.Hosting { /// /// Implements so that we can inject Serilog Logger. /// + [Obsolete("Replaced with Serilog.Extensions.Logging.SerilogLoggerFactory")] + [EditorBrowsable(EditorBrowsableState.Never)] public class SerilogLoggerFactory : ILoggerFactory { - private readonly SerilogLoggerProvider _provider; + readonly SerilogLoggerProvider _provider; /// /// Initializes a new instance of the class. diff --git a/src/Serilog.Extensions.Hosting/IDiagnosticContext.cs b/src/Serilog.Extensions.Hosting/IDiagnosticContext.cs new file mode 100644 index 0000000..468fa84 --- /dev/null +++ b/src/Serilog.Extensions.Hosting/IDiagnosticContext.cs @@ -0,0 +1,32 @@ +// Copyright 2019 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Serilog +{ + /// + /// Collects diagnostic information for packaging into wide events. + /// + public interface IDiagnosticContext + { + /// + /// Set the specified property on the current diagnostic context. The property will be collected + /// and attached to the event emitted at the completion of the context. + /// + /// The name of the property. Must be non-empty. + /// The property value. + /// If true, the value will be serialized as structured + /// data if possible; if false, the object will be recorded as a scalar or simple array. + void Set(string propertyName, object value, bool destructureObjects = false); + } +} diff --git a/src/Serilog.Extensions.Hosting/Serilog.Extensions.Hosting.csproj b/src/Serilog.Extensions.Hosting/Serilog.Extensions.Hosting.csproj index b72ded6..1c84fd6 100644 --- a/src/Serilog.Extensions.Hosting/Serilog.Extensions.Hosting.csproj +++ b/src/Serilog.Extensions.Hosting/Serilog.Extensions.Hosting.csproj @@ -1,8 +1,8 @@ - + Serilog support for .NET Core logging in hosted services - 2.0.0 + 3.0.0 Microsoft;Serilog Contributors netstandard2.0 true @@ -14,15 +14,17 @@ Serilog.Extensions.Hosting serilog;aspnet;aspnetcore;hosting http://serilog.net/images/serilog-extension-nuget.png - https://github.com/serilog/serilog-hosting + https://github.com/serilog/serilog-extensions-hosting http://www.apache.org/licenses/LICENSE-2.0 + https://github.com/serilog/serilog-extensions-hosting + git false Serilog - - + + diff --git a/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs b/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs index 804b8c3..306eadd 100644 --- a/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs +++ b/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs @@ -1,4 +1,4 @@ -// Copyright 2018 Serilog Contributors +// Copyright 2019 Serilog Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,9 @@ using System; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Serilog.Hosting; using Microsoft.Extensions.DependencyInjection; +using Serilog.Extensions.Hosting; +using Serilog.Extensions.Logging; namespace Serilog { @@ -33,48 +34,126 @@ public static class SerilogHostBuilderExtensions /// When true, dispose when the framework disposes the provider. If the /// logger is not specified but is true, the method will be /// called on the static class instead. - /// The (generic) host builder. - public static IHostBuilder UseSerilog(this IHostBuilder builder, Serilog.ILogger logger = null, bool dispose = false) + /// A registered in the Serilog pipeline using the + /// WriteTo.Providers() configuration method, enabling other s to receive events. By + /// default, only Serilog sinks will receive events. + /// The host builder. + public static IHostBuilder UseSerilog( + this IHostBuilder builder, + ILogger logger = null, + bool dispose = false, + LoggerProviderCollection providers = null) { if (builder == null) throw new ArgumentNullException(nameof(builder)); - builder.ConfigureServices((context, collection) => - collection.AddSingleton(services => new SerilogLoggerFactory(logger, dispose))); + + builder.ConfigureServices((_, collection) => + { + if (providers != null) + { + collection.AddSingleton(services => + { + var factory = new SerilogLoggerFactory(logger, dispose, providers); + + foreach (var provider in services.GetServices()) + factory.AddProvider(provider); + + return factory; + }); + } + else + { + collection.AddSingleton(services => new SerilogLoggerFactory(logger, dispose)); + } + + ConfigureServices(collection, logger); + }); + return builder; } - /// - /// Sets Serilog as the logging provider. - /// + /// Sets Serilog as the logging provider. /// /// A is supplied so that configuration and hosting information can be used. /// The logger will be shut down when application services are disposed. /// /// The host builder to configure. - /// The delegate for configuring the that will be used to construct a . + /// The delegate for configuring the that will be used to construct a . /// Indicates whether to preserve the value of . - /// The (generic) host builder. - public static IHostBuilder UseSerilog(this IHostBuilder builder, Action configureLogger, bool preserveStaticLogger = false) + /// By default, Serilog does not write events to s registered through + /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify + /// true to write events to all providers. + /// The host builder. + public static IHostBuilder UseSerilog( + this IHostBuilder builder, + Action configureLogger, + bool preserveStaticLogger = false, + bool writeToProviders = false) { if (builder == null) throw new ArgumentNullException(nameof(builder)); if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger)); + builder.ConfigureServices((context, collection) => { var loggerConfiguration = new LoggerConfiguration(); + + LoggerProviderCollection loggerProviders = null; + if (writeToProviders) + { + loggerProviders = new LoggerProviderCollection(); + loggerConfiguration.WriteTo.Providers(loggerProviders); + } + configureLogger(context, loggerConfiguration); var logger = loggerConfiguration.CreateLogger(); + + ILogger registeredLogger = null; if (preserveStaticLogger) { - collection.AddSingleton(services => new SerilogLoggerFactory(logger, true)); + registeredLogger = logger; } - else + else { // Passing a `null` logger to `SerilogLoggerFactory` results in disposal via // `Log.CloseAndFlush()`, which additionally replaces the static logger with a no-op. Log.Logger = logger; - collection.AddSingleton(services => new SerilogLoggerFactory(null, true)); } + + collection.AddSingleton(services => + { + var factory = new SerilogLoggerFactory(registeredLogger, true, loggerProviders); + + if (writeToProviders) + { + foreach (var provider in services.GetServices()) + factory.AddProvider(provider); + } + + return factory; + }); + + ConfigureServices(collection, logger); }); return builder; } + + static void ConfigureServices(IServiceCollection collection, ILogger logger) + { + if (collection == null) throw new ArgumentNullException(nameof(collection)); + + if (logger != null) + { + // This won't (and shouldn't) take ownership of the logger. + collection.AddSingleton(logger); + } + + // Registered to provide two services... + var diagnosticContext = new DiagnosticContext(logger); + + // Consumed by e.g. middleware + collection.AddSingleton(diagnosticContext); + + // Consumed by user code + collection.AddSingleton(diagnosticContext); + } } } diff --git a/test/Serilog.Extensions.Hosting.Tests/DiagnosticContextTests.cs b/test/Serilog.Extensions.Hosting.Tests/DiagnosticContextTests.cs new file mode 100644 index 0000000..c32f9ea --- /dev/null +++ b/test/Serilog.Extensions.Hosting.Tests/DiagnosticContextTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Serilog.Events; +using Serilog.Extensions.Hosting.Tests.Support; +using Xunit; + +// ReSharper disable PossibleNullReferenceException + +namespace Serilog.Extensions.Hosting.Tests +{ + public class DiagnosticContextTests + { + [Fact] + public void SetIsSafeWhenNoContextIsActive() + { + var dc = new DiagnosticContext(Some.Logger()); + dc.Set(Some.String("name"), Some.Int32()); + } + + [Fact] + public async Task PropertiesAreCollectedInAnActiveContext() + { + var dc = new DiagnosticContext(Some.Logger()); + + var collector = dc.BeginCollection(); + dc.Set(Some.String("first"), Some.Int32()); + await Task.Delay(TimeSpan.FromMilliseconds(10)); + dc.Set(Some.String("second"), Some.Int32()); + + Assert.True(collector.TryComplete(out var properties)); + Assert.Equal(2, properties.Count()); + + Assert.False(collector.TryComplete(out _)); + + collector.Dispose(); + + dc.Set(Some.String("third"), Some.Int32()); + Assert.False(collector.TryComplete(out _)); + } + + [Fact] + public void ExistingPropertiesCanBeUpdated() + { + var dc = new DiagnosticContext(Some.Logger()); + + var collector = dc.BeginCollection(); + dc.Set("name", 10); + dc.Set("name", 20); + + Assert.True(collector.TryComplete(out var properties)); + var prop = Assert.Single(properties); + var scalar = Assert.IsType(prop.Value); + Assert.Equal(20, scalar.Value); + } + } +} diff --git a/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj b/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj index bdbdbcc..bb9c750 100644 --- a/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj +++ b/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.1 + netcoreapp2.2 Serilog.Extensions.Hosting.Tests ../../assets/Serilog.snk true @@ -14,9 +14,12 @@ - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/test/Serilog.Extensions.Hosting.Tests/SerilogHostBuilderExtensionsTests.cs b/test/Serilog.Extensions.Hosting.Tests/SerilogHostBuilderExtensionsTests.cs deleted file mode 100644 index 3341f1d..0000000 --- a/test/Serilog.Extensions.Hosting.Tests/SerilogHostBuilderExtensionsTests.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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 Xunit; - -namespace Serilog.Extensions.Hosting.Tests -{ - public class SerilogHostBuilderExtensionsTests - { - [Fact] - public void Todo() - { - - } - } -} \ No newline at end of file diff --git a/test/Serilog.Extensions.Hosting.Tests/Support/Some.cs b/test/Serilog.Extensions.Hosting.Tests/Support/Some.cs new file mode 100644 index 0000000..5137cef --- /dev/null +++ b/test/Serilog.Extensions.Hosting.Tests/Support/Some.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Serilog.Events; + +namespace Serilog.Extensions.Hosting.Tests.Support +{ + static class Some + { + static int _next; + + public static int Int32() => Interlocked.Increment(ref _next); + + public static string String(string tag = null) => $"s_{tag}{Int32()}"; + + public static LogEventProperty LogEventProperty() => new LogEventProperty(String("name"), new ScalarValue(Int32())); + + public static ILogger Logger() => new LoggerConfiguration().CreateLogger(); + } +}