diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..112f424 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf + +[*.{csproj,json,config,yml,props}] +indent_size = 2 + +[*.sh] +end_of_line = lf + +[*.{cmd, bat}] +end_of_line = crlf + +# C# formatting settings - Namespace options +csharp_style_namespace_declarations = file_scoped:suggestion + +csharp_style_prefer_switch_expression = true:suggestion \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..3883932 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,13 @@ + + + + latest + True + true + $(MSBuildThisFileDirectory)assets/Serilog.snk + true + enable + enable + + + \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..faf2349 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,3 @@ + + + diff --git a/global.json b/global.json deleted file mode 100644 index e3bbb00..0000000 --- a/global.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "sdk": { - "allowPrerelease": false, - "version": "3.1.100", - "rollForward": "latestFeature" - } -} diff --git a/samples/Sample/Program.cs b/samples/Sample/Program.cs index 03014b7..9ba6bf0 100644 --- a/samples/Sample/Program.cs +++ b/samples/Sample/Program.cs @@ -1,79 +1,77 @@ -using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Extensions.Logging; -namespace Sample +namespace Sample; + +public class Program { - public class Program + public static void Main(string[] args) { - public static void Main(string[] args) + // Creating a `LoggerProviderCollection` lets Serilog optionally write + // events through other dynamically-added MEL ILoggerProviders. + var providers = new LoggerProviderCollection(); + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .WriteTo.Console() + .WriteTo.Providers(providers) + .CreateLogger(); + + var services = new ServiceCollection(); + + services.AddSingleton(providers); + services.AddSingleton(sc => + { + var providerCollection = sc.GetService(); + var factory = new SerilogLoggerFactory(null, true, providerCollection); + + foreach (var provider in sc.GetServices()) + factory.AddProvider(provider); + + return factory; + }); + + services.AddLogging(l => l.AddConsole()); + + var serviceProvider = services.BuildServiceProvider(); + var logger = serviceProvider.GetRequiredService>(); + + var startTime = DateTimeOffset.UtcNow; + logger.LogInformation(1, "Started at {StartTime} and 0x{Hello:X} is hex of 42", startTime, 42); + + try + { + throw new Exception("Boom!"); + } + catch (Exception ex) + { + logger.LogCritical("Unexpected critical error starting application", ex); + logger.Log(LogLevel.Critical, 0, "Unexpected critical error", ex, null!); + // This write should not log anything + logger.Log(LogLevel.Critical, 0, null!, null, null!); + logger.LogError("Unexpected error", ex); + logger.LogWarning("Unexpected warning", ex); + } + + using (logger.BeginScope("Main")) { - // Creating a `LoggerProviderCollection` lets Serilog optionally write - // events through other dynamically-added MEL ILoggerProviders. - var providers = new LoggerProviderCollection(); - - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .WriteTo.Console() - .WriteTo.Providers(providers) - .CreateLogger(); - - var services = new ServiceCollection(); - - services.AddSingleton(providers); - services.AddSingleton(sc => - { - var providerCollection = sc.GetService(); - var factory = new SerilogLoggerFactory(null, true, providerCollection); - - foreach (var provider in sc.GetServices()) - factory.AddProvider(provider); - - return factory; - }); - - services.AddLogging(l => l.AddConsole()); - - var serviceProvider = services.BuildServiceProvider(); - var logger = serviceProvider.GetRequiredService>(); - - var startTime = DateTimeOffset.UtcNow; - logger.LogInformation(1, "Started at {StartTime} and 0x{Hello:X} is hex of 42", startTime, 42); - - try - { - throw new Exception("Boom!"); - } - catch (Exception ex) - { - logger.LogCritical("Unexpected critical error starting application", ex); - logger.Log(LogLevel.Critical, 0, "Unexpected critical error", ex, null); - // This write should not log anything - logger.Log(LogLevel.Critical, 0, null, null, null); - logger.LogError("Unexpected error", ex); - logger.LogWarning("Unexpected warning", ex); - } - - using (logger.BeginScope("Main")) - { - logger.LogInformation("Waiting for user input"); - var key = Console.Read(); - logger.LogInformation("User pressed {@KeyInfo}", new { Key = key, KeyChar = (char)key }); - } - - var endTime = DateTimeOffset.UtcNow; - logger.LogInformation(2, "Stopping at {StopTime}", endTime); - - logger.LogInformation("Stopping"); - - logger.LogInformation(Environment.NewLine); - logger.LogInformation("{Result,-10:l}{StartTime,15:l}{EndTime,15:l}{Duration,15:l}", "RESULT", "START TIME", "END TIME", "DURATION(ms)"); - logger.LogInformation("{Result,-10:l}{StartTime,15:l}{EndTime,15:l}{Duration,15:l}", "------", "----- ----", "--- ----", "------------"); - logger.LogInformation("{Result,-10:l}{StartTime,15:mm:s tt}{EndTime,15:mm:s tt}{Duration,15}", "SUCCESS", startTime, endTime, (endTime - startTime).TotalMilliseconds); - - serviceProvider.Dispose(); + logger.LogInformation("Waiting for user input"); + var key = Console.Read(); + logger.LogInformation("User pressed {@KeyInfo}", new { Key = key, KeyChar = (char)key }); } + + var endTime = DateTimeOffset.UtcNow; + logger.LogInformation(2, "Stopping at {StopTime}", endTime); + + logger.LogInformation("Stopping"); + + logger.LogInformation(Environment.NewLine); + logger.LogInformation("{Result,-10:l}{StartTime,15:l}{EndTime,15:l}{Duration,15:l}", "RESULT", "START TIME", "END TIME", "DURATION(ms)"); + logger.LogInformation("{Result,-10:l}{StartTime,15:l}{EndTime,15:l}{Duration,15:l}", "------", "----- ----", "--- ----", "------------"); + logger.LogInformation("{Result,-10:l}{StartTime,15:mm:s tt}{EndTime,15:mm:s tt}{Duration,15}", "SUCCESS", startTime, endTime, (endTime - startTime).TotalMilliseconds); + + serviceProvider.Dispose(); } } diff --git a/samples/Sample/Sample.csproj b/samples/Sample/Sample.csproj index 8b1487b..44ba8e2 100644 --- a/samples/Sample/Sample.csproj +++ b/samples/Sample/Sample.csproj @@ -1,10 +1,9 @@  - netcoreapp2.0 + net7 Sample Exe - Sample @@ -12,9 +11,9 @@ - - - + + + \ No newline at end of file diff --git a/serilog-extensions-logging.sln b/serilog-extensions-logging.sln index c53414c..9e91f73 100644 --- a/serilog-extensions-logging.sln +++ b/serilog-extensions-logging.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29209.62 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33424.131 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A1893BD1-333D-4DFE-A0F0-DDBB2FE526E0}" EndProject @@ -17,9 +17,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "samples\Sample\Sa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{9C21B9DF-AEDD-4AA6-BEA4-912DEF3E5B8E}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig appveyor.yml = appveyor.yml Build.ps1 = Build.ps1 - global.json = global.json + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets README.md = README.md assets\Serilog.snk = assets\Serilog.snk EndProjectSection diff --git a/serilog-extensions-logging.sln.DotSettings b/serilog-extensions-logging.sln.DotSettings deleted file mode 100644 index c2fd9da..0000000 --- a/serilog-extensions-logging.sln.DotSettings +++ /dev/null @@ -1,12 +0,0 @@ - - True - True - True - True - True - True - True - True - True - True - True \ No newline at end of file diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/CachingMessageTemplateParser.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/CachingMessageTemplateParser.cs index ca3c254..294f201 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/CachingMessageTemplateParser.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/CachingMessageTemplateParser.cs @@ -1,4 +1,4 @@ -// Copyright (c) Serilog Contributors +// Copyright (c) Serilog Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,55 +13,53 @@ // limitations under the License. -using System; using Serilog.Events; using Serilog.Parsing; using System.Collections; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +class CachingMessageTemplateParser { - class CachingMessageTemplateParser - { - readonly MessageTemplateParser _innerParser = new MessageTemplateParser(); + readonly MessageTemplateParser _innerParser = new(); - readonly object _templatesLock = new object(); - readonly Hashtable _templates = new Hashtable(); + readonly object _templatesLock = new(); + readonly Hashtable _templates = new(); - const int MaxCacheItems = 1000; - const int MaxCachedTemplateLength = 1024; + const int MaxCacheItems = 1000; + const int MaxCachedTemplateLength = 1024; - public MessageTemplate Parse(string messageTemplate) - { - if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate)); - - if (messageTemplate.Length > MaxCachedTemplateLength) - return _innerParser.Parse(messageTemplate); + public MessageTemplate Parse(string messageTemplate) + { + if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate)); - // ReSharper disable once InconsistentlySynchronizedField - // ignored warning because this is by design - var result = (MessageTemplate)_templates[messageTemplate]; - if (result != null) - return result; + if (messageTemplate.Length > MaxCachedTemplateLength) + return _innerParser.Parse(messageTemplate); - result = _innerParser.Parse(messageTemplate); + // ReSharper disable once InconsistentlySynchronizedField + // ignored warning because this is by design + var result = (MessageTemplate)_templates[messageTemplate]; + if (result != null) + return result; - lock (_templatesLock) - { - // Exceeding MaxCacheItems is *not* the sunny day scenario; all we're doing here is preventing out-of-memory - // conditions when the library is used incorrectly. Correct use (templates, rather than - // direct message strings) should barely, if ever, overflow this cache. + result = _innerParser.Parse(messageTemplate); - // Changing workloads through the lifecycle of an app instance mean we can gain some ground by - // potentially dropping templates generated only in startup, or only during specific infrequent - // activities. + lock (_templatesLock) + { + // Exceeding MaxCacheItems is *not* the sunny day scenario; all we're doing here is preventing out-of-memory + // conditions when the library is used incorrectly. Correct use (templates, rather than + // direct message strings) should barely, if ever, overflow this cache. - if (_templates.Count == MaxCacheItems) - _templates.Clear(); + // Changing workloads through the lifecycle of an app instance mean we can gain some ground by + // potentially dropping templates generated only in startup, or only during specific infrequent + // activities. - _templates[messageTemplate] = result; - } + if (_templates.Count == MaxCacheItems) + _templates.Clear(); - return result; + _templates[messageTemplate] = result; } + + return result; } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/LevelConvert.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/LevelConvert.cs index 58354e0..7f1923d 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/LevelConvert.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/LevelConvert.cs @@ -17,65 +17,64 @@ // ReSharper disable RedundantCaseLabel -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +/// +/// Converts between Serilog and Microsoft.Extensions.Logging level enum values. +/// +public static class LevelConvert { /// - /// Converts between Serilog and Microsoft.Extensions.Logging level enum values. + /// Convert to the equivalent Serilog . /// - public static class LevelConvert + /// A Microsoft.Extensions.Logging . + /// The Serilog equivalent of . + /// The value has no Serilog equivalent. It is mapped to + /// as the closest approximation, but this has entirely + /// different semantics. + public static LogEventLevel ToSerilogLevel(LogLevel logLevel) { - /// - /// Convert to the equivalent Serilog . - /// - /// A Microsoft.Extensions.Logging . - /// The Serilog equivalent of . - /// The value has no Serilog equivalent. It is mapped to - /// as the closest approximation, but this has entirely - /// different semantics. - public static LogEventLevel ToSerilogLevel(LogLevel logLevel) + switch (logLevel) { - switch (logLevel) - { - case LogLevel.None: - case LogLevel.Critical: - return LogEventLevel.Fatal; - case LogLevel.Error: - return LogEventLevel.Error; - case LogLevel.Warning: - return LogEventLevel.Warning; - case LogLevel.Information: - return LogEventLevel.Information; - case LogLevel.Debug: - return LogEventLevel.Debug; - case LogLevel.Trace: - default: - return LogEventLevel.Verbose; - } + case LogLevel.None: + case LogLevel.Critical: + return LogEventLevel.Fatal; + case LogLevel.Error: + return LogEventLevel.Error; + case LogLevel.Warning: + return LogEventLevel.Warning; + case LogLevel.Information: + return LogEventLevel.Information; + case LogLevel.Debug: + return LogEventLevel.Debug; + case LogLevel.Trace: + default: + return LogEventLevel.Verbose; } + } - /// - /// Convert to the equivalent Microsoft.Extensions.Logging . - /// - /// A Serilog . - /// The Microsoft.Extensions.Logging equivalent of . - public static LogLevel ToExtensionsLevel(LogEventLevel logEventLevel) + /// + /// Convert to the equivalent Microsoft.Extensions.Logging . + /// + /// A Serilog . + /// The Microsoft.Extensions.Logging equivalent of . + public static LogLevel ToExtensionsLevel(LogEventLevel logEventLevel) + { + switch (logEventLevel) { - switch (logEventLevel) - { - case LogEventLevel.Fatal: - return LogLevel.Critical; - case LogEventLevel.Error: - return LogLevel.Error; - case LogEventLevel.Warning: - return LogLevel.Warning; - case LogEventLevel.Information: - return LogLevel.Information; - case LogEventLevel.Debug: - return LogLevel.Debug; - case LogEventLevel.Verbose: - default: - return LogLevel.Trace; - } + case LogEventLevel.Fatal: + return LogLevel.Critical; + case LogEventLevel.Error: + return LogLevel.Error; + case LogEventLevel.Warning: + return LogLevel.Warning; + case LogEventLevel.Information: + return LogLevel.Information; + case LogEventLevel.Debug: + return LogLevel.Debug; + case LogEventLevel.Verbose: + default: + return LogLevel.Trace; } } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollection.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollection.cs index 7a0e08b..b944040 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollection.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollection.cs @@ -13,55 +13,50 @@ // limitations under the License. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; using Microsoft.Extensions.Logging; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +/// +/// A dynamically-modifiable collection of s. +/// +public class LoggerProviderCollection : IDisposable { + volatile ILoggerProvider[] _providers = Array.Empty(); + /// - /// A dynamically-modifiable collection of s. + /// Add to the collection. /// - public class LoggerProviderCollection : IDisposable + /// A logger provider. + public void AddProvider(ILoggerProvider provider) { - volatile ILoggerProvider[] _providers = Array.Empty(); - - /// - /// Add to the collection. - /// - /// A logger provider. - public void AddProvider(ILoggerProvider provider) - { - if (provider == null) throw new ArgumentNullException(nameof(provider)); + if (provider == null) throw new ArgumentNullException(nameof(provider)); - ILoggerProvider[] existing, added; + ILoggerProvider[] existing, added; - do - { - existing = _providers; - added = existing.Concat(new[] { provider }).ToArray(); - } + do + { + existing = _providers; + added = existing.Concat(new[] { provider }).ToArray(); + } #pragma warning disable 420 // ref to a volatile field - while (Interlocked.CompareExchange(ref _providers, added, existing) != existing); + while (Interlocked.CompareExchange(ref _providers, added, existing) != existing); #pragma warning restore 420 - } - - /// - /// Get the currently-active providers. - /// - /// - /// If the collection has been disposed, we'll leave the individual - /// providers with the job of throwing . - /// - public IEnumerable Providers => _providers; + } - /// - public void Dispose() - { - foreach (var provider in _providers) - provider.Dispose(); - } + /// + /// Get the currently-active providers. + /// + /// + /// If the collection has been disposed, we'll leave the individual + /// providers with the job of throwing . + /// + public IEnumerable Providers => _providers; + + /// + public void Dispose() + { + foreach (var provider in _providers) + provider.Dispose(); } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollectionSink.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollectionSink.cs index afe4a29..2a3a586 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollectionSink.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/LoggerProviderCollectionSink.cs @@ -1,4 +1,4 @@ -// Copyright 2019 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. @@ -12,65 +12,63 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using Microsoft.Extensions.Logging; using Serilog.Core; using Serilog.Events; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +class LoggerProviderCollectionSink : ILogEventSink, IDisposable { - class LoggerProviderCollectionSink : ILogEventSink, IDisposable + readonly LoggerProviderCollection _providers; + + public LoggerProviderCollectionSink(LoggerProviderCollection providers) + { + _providers = providers ?? throw new ArgumentNullException(nameof(providers)); + } + + public void Emit(LogEvent logEvent) { - readonly LoggerProviderCollection _providers; + string? categoryName = null; + EventId eventId = default; - public LoggerProviderCollectionSink(LoggerProviderCollection providers) + if (logEvent.Properties.TryGetValue("SourceContext", out var sourceContextProperty) && + sourceContextProperty is ScalarValue sourceContextValue && + sourceContextValue.Value is string sourceContext) { - _providers = providers ?? throw new ArgumentNullException(nameof(providers)); + categoryName = sourceContext; } - - public void Emit(LogEvent logEvent) + if (logEvent.Properties.TryGetValue("EventId", out var eventIdPropertyValue) && eventIdPropertyValue is StructureValue structuredEventId) { - string categoryName = null; - EventId eventId = default; - - if (logEvent.Properties.TryGetValue("SourceContext", out var sourceContextProperty) && - sourceContextProperty is ScalarValue sourceContextValue && - sourceContextValue.Value is string sourceContext) + string? name = null; + var id = 0; + foreach (var item in structuredEventId.Properties) { - categoryName = sourceContext; + if (item.Name == "Id" && item.Value is ScalarValue sv && sv.Value is int i) id = i; + if (item.Name == "Name" && item.Value is ScalarValue sv2 && sv2.Value is string s) name = s; } - if (logEvent.Properties.TryGetValue("EventId", out var eventIdPropertyValue) && eventIdPropertyValue is StructureValue structuredEventId) - { - string name = null; - var id = 0; - foreach (var item in structuredEventId.Properties) - { - if (item.Name == "Id" && item.Value is ScalarValue sv && sv.Value is int i) id = i; - if (item.Name == "Name" && item.Value is ScalarValue sv2 && sv2.Value is string s) name = s; - } - eventId = new EventId(id, name); - } + eventId = new EventId(id, name); + } - var level = LevelConvert.ToExtensionsLevel(logEvent.Level); - var slv = new SerilogLogValues(logEvent.MessageTemplate, logEvent.Properties); + var level = LevelConvert.ToExtensionsLevel(logEvent.Level); + var slv = new SerilogLogValues(logEvent.MessageTemplate, logEvent.Properties); - foreach (var provider in _providers.Providers) - { - var logger = provider.CreateLogger(categoryName); + foreach (var provider in _providers.Providers) + { + var logger = provider.CreateLogger(categoryName); - logger.Log( - level, - eventId, - slv, - logEvent.Exception, - (s, e) => s.ToString()); - } + logger.Log( + level, + eventId, + slv, + logEvent.Exception, + (s, e) => s.ToString()); } + } - public void Dispose() - { - _providers.Dispose(); - } + public void Dispose() + { + _providers.Dispose(); } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogValues.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogValues.cs index c6f8058..930f457 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogValues.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogValues.cs @@ -13,50 +13,47 @@ // limitations under the License. using Serilog.Events; -using System; using System.Collections; -using System.Collections.Generic; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +readonly struct SerilogLogValues : IReadOnlyList> { - readonly struct SerilogLogValues : IReadOnlyList> + // Note, this struct is only used in a very limited context internally, so we ignore + // the possibility of fields being null via the default struct initialization. + + private readonly MessageTemplate _messageTemplate; + private readonly IReadOnlyDictionary _properties; + private readonly KeyValuePair[] _values; + + public SerilogLogValues(MessageTemplate messageTemplate, IReadOnlyDictionary properties) { - // Note, this struct is only used in a very limited context internally, so we ignore - // the possibility of fields being null via the default struct initialization. + _messageTemplate = messageTemplate ?? throw new ArgumentNullException(nameof(messageTemplate)); - private readonly MessageTemplate _messageTemplate; - private readonly IReadOnlyDictionary _properties; - private readonly KeyValuePair[] _values; + // The dictionary is needed for rendering through the message template + _properties = properties ?? throw new ArgumentNullException(nameof(properties)); - public SerilogLogValues(MessageTemplate messageTemplate, IReadOnlyDictionary properties) + // The array is needed because the IReadOnlyList interface expects indexed access + _values = new KeyValuePair[_properties.Count + 1]; + var i = 0; + foreach (var p in properties) { - _messageTemplate = messageTemplate ?? throw new ArgumentNullException(nameof(messageTemplate)); - - // The dictionary is needed for rendering through the message template - _properties = properties ?? throw new ArgumentNullException(nameof(properties)); - - // The array is needed because the IReadOnlyList interface expects indexed access - _values = new KeyValuePair[_properties.Count + 1]; - var i = 0; - foreach (var p in properties) - { - _values[i] = new KeyValuePair(p.Key, (p.Value is ScalarValue sv) ? sv.Value : p.Value); - ++i; - } - _values[i] = new KeyValuePair("{OriginalFormat}", _messageTemplate.Text); + _values[i] = new KeyValuePair(p.Key, (p.Value is ScalarValue sv) ? sv.Value : p.Value); + ++i; } + _values[i] = new KeyValuePair("{OriginalFormat}", _messageTemplate.Text); + } - public KeyValuePair this[int index] - { - get => _values[index]; - } + public KeyValuePair this[int index] + { + get => _values[index]; + } - public int Count => _properties.Count + 1; + public int Count => _properties.Count + 1; - public IEnumerator> GetEnumerator() => ((IEnumerable>)_values).GetEnumerator(); + public IEnumerator> GetEnumerator() => ((IEnumerable>)_values).GetEnumerator(); - public override string ToString() => _messageTemplate.Render(_properties); + public override string ToString() => _messageTemplate.Render(_properties); - IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => _values.GetEnumerator(); } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs index 78d72dd..f76e75c 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs @@ -2,177 +2,173 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; using Serilog.Core; using Serilog.Events; using FrameworkLogger = Microsoft.Extensions.Logging.ILogger; using System.Reflection; using Serilog.Debugging; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +class SerilogLogger : FrameworkLogger { - class SerilogLogger : FrameworkLogger - { - readonly SerilogLoggerProvider _provider; - readonly ILogger _logger; + readonly SerilogLoggerProvider _provider; + readonly ILogger _logger; - static readonly CachingMessageTemplateParser MessageTemplateParser = new CachingMessageTemplateParser(); + static readonly CachingMessageTemplateParser MessageTemplateParser = new(); - // It's rare to see large event ids, as they are category-specific - static readonly LogEventProperty[] LowEventIdValues = Enumerable.Range(0, 48) - .Select(n => new LogEventProperty("Id", new ScalarValue(n))) - .ToArray(); + // It's rare to see large event ids, as they are category-specific + static readonly LogEventProperty[] LowEventIdValues = Enumerable.Range(0, 48) + .Select(n => new LogEventProperty("Id", new ScalarValue(n))) + .ToArray(); - public SerilogLogger( - SerilogLoggerProvider provider, - ILogger logger = null, - string name = null) - { - _provider = provider ?? throw new ArgumentNullException(nameof(provider)); - _logger = logger; + public SerilogLogger( + SerilogLoggerProvider provider, + ILogger? logger = null, + string? name = null) + { + _provider = provider ?? throw new ArgumentNullException(nameof(provider)); + _logger = logger!; - // If a logger was passed, the provider has already added itself as an enricher - _logger = _logger ?? Serilog.Log.Logger.ForContext(new[] { provider }); + // If a logger was passed, the provider has already added itself as an enricher + _logger ??= Serilog.Log.Logger.ForContext(new[] { provider }); - if (name != null) - { - _logger = _logger.ForContext(Constants.SourceContextPropertyName, name); - } + if (name != null) + { + _logger = _logger.ForContext(Constants.SourceContextPropertyName, name); } + } - public bool IsEnabled(LogLevel logLevel) + public bool IsEnabled(LogLevel logLevel) + { + return logLevel != LogLevel.None && _logger.IsEnabled(LevelConvert.ToSerilogLevel(logLevel)); + } + + public IDisposable BeginScope(TState state) + { + return _provider.BeginScope(state); + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (logLevel == LogLevel.None) { - return logLevel != LogLevel.None && _logger.IsEnabled(LevelConvert.ToSerilogLevel(logLevel)); + return; } - - public IDisposable BeginScope(TState state) + var level = LevelConvert.ToSerilogLevel(logLevel); + if (!_logger.IsEnabled(level)) { - return _provider.BeginScope(state); + return; } - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + try { - if (logLevel == LogLevel.None) - { - return; - } - var level = LevelConvert.ToSerilogLevel(logLevel); - if (!_logger.IsEnabled(level)) - { - return; - } - - try - { - Write(level, eventId, state, exception, formatter); - } - catch (Exception ex) - { - SelfLog.WriteLine($"Failed to write event through {typeof(SerilogLogger).Name}: {ex}"); - } + Write(level, eventId, state, exception, formatter); } - - void Write(LogEventLevel level, EventId eventId, TState state, Exception exception, Func formatter) + catch (Exception ex) { - var logger = _logger; - string messageTemplate = null; + SelfLog.WriteLine($"Failed to write event through {typeof(SerilogLogger).Name}: {ex}"); + } + } - var properties = new List(); + void Write(LogEventLevel level, EventId eventId, TState state, Exception exception, Func formatter) + { + var logger = _logger; + string? messageTemplate = null; - if (state is IEnumerable> structure) - { - foreach (var property in structure) - { - if (property.Key == SerilogLoggerProvider.OriginalFormatPropertyName && property.Value is string value) - { - messageTemplate = value; - } - else if (property.Key.StartsWith("@")) - { - if (logger.BindProperty(property.Key.Substring(1), property.Value, true, out var destructured)) - properties.Add(destructured); - } - else if (property.Key.StartsWith("$")) - { - if (logger.BindProperty(property.Key.Substring(1), property.Value?.ToString(), true, out var stringified)) - properties.Add(stringified); - } - else - { - if (logger.BindProperty(property.Key, property.Value, false, out var bound)) - properties.Add(bound); - } - } + var properties = new List(); - var stateType = state.GetType(); - var stateTypeInfo = stateType.GetTypeInfo(); - // Imperfect, but at least eliminates `1 names - if (messageTemplate == null && !stateTypeInfo.IsGenericType) + if (state is IEnumerable> structure) + { + foreach (var property in structure) + { + if (property.Key == SerilogLoggerProvider.OriginalFormatPropertyName && property.Value is string value) { - messageTemplate = "{" + stateType.Name + ":l}"; - if (logger.BindProperty(stateType.Name, AsLoggableValue(state, formatter), false, out var stateTypeProperty)) - properties.Add(stateTypeProperty); + messageTemplate = value; } - } - - if (messageTemplate == null) - { - string propertyName = null; - if (state != null) + else if (property.Key.StartsWith("@")) { - propertyName = "State"; - messageTemplate = "{State:l}"; + if (logger.BindProperty(property.Key.Substring(1), property.Value, true, out var destructured)) + properties.Add(destructured); } - else if (formatter != null) + else if (property.Key.StartsWith("$")) { - propertyName = "Message"; - messageTemplate = "{Message:l}"; + if (logger.BindProperty(property.Key.Substring(1), property.Value?.ToString(), true, out var stringified)) + properties.Add(stringified); } - - if (propertyName != null) + else { - if (logger.BindProperty(propertyName, AsLoggableValue(state, formatter), false, out var property)) - properties.Add(property); + if (logger.BindProperty(property.Key, property.Value, false, out var bound)) + properties.Add(bound); } } - if (eventId.Id != 0 || eventId.Name != null) - properties.Add(CreateEventIdProperty(eventId)); - - var parsedTemplate = MessageTemplateParser.Parse(messageTemplate ?? ""); - var evt = new LogEvent(DateTimeOffset.Now, level, exception, parsedTemplate, properties); - logger.Write(evt); - } - - static object AsLoggableValue(TState state, Func formatter) - { - object sobj = state; - if (formatter != null) - sobj = formatter(state, null); - return sobj; + var stateType = state.GetType(); + var stateTypeInfo = stateType.GetTypeInfo(); + // Imperfect, but at least eliminates `1 names + if (messageTemplate == null && !stateTypeInfo.IsGenericType) + { + messageTemplate = "{" + stateType.Name + ":l}"; + if (logger.BindProperty(stateType.Name, AsLoggableValue(state, formatter), false, out var stateTypeProperty)) + properties.Add(stateTypeProperty); + } } - internal static LogEventProperty CreateEventIdProperty(EventId eventId) + if (messageTemplate == null) { - var properties = new List(2); - - if (eventId.Id != 0) + string? propertyName = null; + if (state != null) { - if (eventId.Id >= 0 && eventId.Id < LowEventIdValues.Length) - // Avoid some allocations - properties.Add(LowEventIdValues[eventId.Id]); - else - properties.Add(new LogEventProperty("Id", new ScalarValue(eventId.Id))); + propertyName = "State"; + messageTemplate = "{State:l}"; + } + else if (formatter != null) + { + propertyName = "Message"; + messageTemplate = "{Message:l}"; } - if (eventId.Name != null) + if (propertyName != null) { - properties.Add(new LogEventProperty("Name", new ScalarValue(eventId.Name))); + if (logger.BindProperty(propertyName, AsLoggableValue(state, formatter!), false, out var property)) + properties.Add(property); } + } + + if (eventId.Id != 0 || eventId.Name != null) + properties.Add(CreateEventIdProperty(eventId)); + + var parsedTemplate = MessageTemplateParser.Parse(messageTemplate ?? ""); + var evt = new LogEvent(DateTimeOffset.Now, level, exception, parsedTemplate, properties); + logger.Write(evt); + } + + static object? AsLoggableValue(TState state, Func formatter) + { + object? sobj = state; + if (formatter != null) + sobj = formatter(state, null!); + return sobj; + } - return new LogEventProperty("EventId", new StructureValue(properties)); + internal static LogEventProperty CreateEventIdProperty(EventId eventId) + { + var properties = new List(2); + + if (eventId.Id != 0) + { + if (eventId.Id >= 0 && eventId.Id < LowEventIdValues.Length) + // Avoid some allocations + properties.Add(LowEventIdValues[eventId.Id]); + else + properties.Add(new LogEventProperty("Id", new ScalarValue(eventId.Id))); } + + if (eventId.Name != null) + { + properties.Add(new LogEventProperty("Name", new ScalarValue(eventId.Name))); + } + + return new LogEventProperty("EventId", new StructureValue(properties)); } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerFactory.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerFactory.cs index 3ee0760..b85dbcb 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerFactory.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerFactory.cs @@ -1,4 +1,4 @@ -// Copyright 2019 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. @@ -12,65 +12,63 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using Microsoft.Extensions.Logging; using Serilog.Debugging; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +/// +/// A complete Serilog-backed implementation of the .NET Core logging infrastructure. +/// +public class SerilogLoggerFactory : ILoggerFactory { + readonly LoggerProviderCollection? _providerCollection; + readonly SerilogLoggerProvider _provider; + /// - /// A complete Serilog-backed implementation of the .NET Core logging infrastructure. + /// Initializes a new instance of the class. /// - public class SerilogLoggerFactory : ILoggerFactory + /// The Serilog logger; if not supplied, the static will be used. + /// 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. + /// A , for use with WriteTo.Providers(). + public SerilogLoggerFactory(ILogger? logger = null, bool dispose = false, LoggerProviderCollection? providerCollection = null) { - readonly LoggerProviderCollection _providerCollection; - readonly SerilogLoggerProvider _provider; - - /// - /// Initializes a new instance of the class. - /// - /// The Serilog logger; if not supplied, the static will be used. - /// 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. - /// A , for use with WriteTo.Providers(). - public SerilogLoggerFactory(ILogger logger = null, bool dispose = false, LoggerProviderCollection providerCollection = null) - { - _provider = new SerilogLoggerProvider(logger, dispose); - _providerCollection = providerCollection; - } + _provider = new SerilogLoggerProvider(logger, dispose); + _providerCollection = providerCollection; + } - /// - /// Disposes the provider. - /// - public void Dispose() - { - _provider.Dispose(); - } + /// + /// Disposes the provider. + /// + public void Dispose() + { + _provider.Dispose(); + } - /// - /// Creates a new instance. - /// - /// The category name for messages produced by the logger. - /// - /// The . - /// - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) - { - return _provider.CreateLogger(categoryName); - } + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// + /// The . + /// + public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) + { + return _provider.CreateLogger(categoryName); + } - /// - /// Adds an to the logging system. - /// - /// The . - public void AddProvider(ILoggerProvider provider) - { - if (provider == null) throw new ArgumentNullException(nameof(provider)); - if (_providerCollection != null) - _providerCollection.AddProvider(provider); - else - SelfLog.WriteLine("Ignoring added logger provider {0}", provider); - } + /// + /// Adds an to the logging system. + /// + /// The . + public void AddProvider(ILoggerProvider provider) + { + if (provider == null) throw new ArgumentNullException(nameof(provider)); + if (_providerCollection != null) + _providerCollection.AddProvider(provider); + else + SelfLog.WriteLine("Ignoring added logger provider {0}", provider); } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs index d51c2c0..2a46739 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerProvider.cs @@ -1,102 +1,98 @@ // 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; using Microsoft.Extensions.Logging; using Serilog.Core; using Serilog.Events; using FrameworkLogger = Microsoft.Extensions.Logging.ILogger; -using System.Collections.Generic; -using System.Threading; using Serilog.Context; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +/// +/// An that pipes events through Serilog. +/// +[ProviderAlias("Serilog")] +public class SerilogLoggerProvider : ILoggerProvider, ILogEventEnricher { + internal const string OriginalFormatPropertyName = "{OriginalFormat}"; + internal const string ScopePropertyName = "Scope"; + + // May be null; if it is, Log.Logger will be lazily used + readonly ILogger? _logger; + readonly Action? _dispose; + /// - /// An that pipes events through Serilog. + /// Construct a . /// - [ProviderAlias("Serilog")] - public class SerilogLoggerProvider : ILoggerProvider, ILogEventEnricher + /// A Serilog logger to pipe events through; if null, the static class will be used. + /// If true, the provided logger or static log class will be disposed/closed when the provider is disposed. + public SerilogLoggerProvider(ILogger? logger = null, bool dispose = false) { - internal const string OriginalFormatPropertyName = "{OriginalFormat}"; - internal const string ScopePropertyName = "Scope"; - - // May be null; if it is, Log.Logger will be lazily used - readonly ILogger _logger; - readonly Action _dispose; + if (logger != null) + _logger = logger.ForContext(new[] { this }); - /// - /// Construct a . - /// - /// A Serilog logger to pipe events through; if null, the static class will be used. - /// If true, the provided logger or static log class will be disposed/closed when the provider is disposed. - public SerilogLoggerProvider(ILogger logger = null, bool dispose = false) + if (dispose) { if (logger != null) - _logger = logger.ForContext(new[] { this }); - - if (dispose) - { - if (logger != null) - _dispose = () => (logger as IDisposable)?.Dispose(); - else - _dispose = Log.CloseAndFlush; - } + _dispose = () => (logger as IDisposable)?.Dispose(); + else + _dispose = Log.CloseAndFlush; } + } - /// - public FrameworkLogger CreateLogger(string name) - { - return new SerilogLogger(this, _logger, name); - } + /// + public FrameworkLogger CreateLogger(string name) + { + return new SerilogLogger(this, _logger, name); + } - /// - public IDisposable BeginScope(T state) - { - if (CurrentScope != null) - return new SerilogLoggerScope(this, state); + /// + public IDisposable BeginScope(T state) + { + if (CurrentScope != null) + return new SerilogLoggerScope(this, state); - // The outermost scope pushes and pops the Serilog `LogContext` - once - // this enricher is on the stack, the `CurrentScope` property takes care - // of the rest of the `BeginScope()` stack. - var popSerilogContext = LogContext.Push(this); - return new SerilogLoggerScope(this, state, popSerilogContext); - } + // The outermost scope pushes and pops the Serilog `LogContext` - once + // this enricher is on the stack, the `CurrentScope` property takes care + // of the rest of the `BeginScope()` stack. + var popSerilogContext = LogContext.Push(this); + return new SerilogLoggerScope(this, state, popSerilogContext); + } - /// - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + /// + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + { + List? scopeItems = null; + for (var scope = CurrentScope; scope != null; scope = scope.Parent) { - List scopeItems = null; - for (var scope = CurrentScope; scope != null; scope = scope.Parent) - { - scope.EnrichAndCreateScopeItem(logEvent, propertyFactory, out LogEventPropertyValue scopeItem); + scope.EnrichAndCreateScopeItem(logEvent, propertyFactory, out LogEventPropertyValue? scopeItem); - if (scopeItem != null) - { - scopeItems = scopeItems ?? new List(); - scopeItems.Add(scopeItem); - } - } - - if (scopeItems != null) + if (scopeItem != null) { - scopeItems.Reverse(); - logEvent.AddPropertyIfAbsent(new LogEventProperty(ScopePropertyName, new SequenceValue(scopeItems))); + scopeItems ??= new List(); + scopeItems.Add(scopeItem); } } - readonly AsyncLocal _value = new AsyncLocal(); - - internal SerilogLoggerScope CurrentScope + if (scopeItems != null) { - get => _value.Value; - set => _value.Value = value; + scopeItems.Reverse(); + logEvent.AddPropertyIfAbsent(new LogEventProperty(ScopePropertyName, new SequenceValue(scopeItems))); } + } - /// - public void Dispose() - { - _dispose?.Invoke(); - } + readonly AsyncLocal _value = new(); + + internal SerilogLoggerScope CurrentScope + { + get => _value.Value; + set => _value.Value = value; + } + + /// + public void Dispose() + { + _dispose?.Invoke(); } } diff --git a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerScope.cs b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerScope.cs index deb8ace..6d6621f 100644 --- a/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerScope.cs +++ b/src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLoggerScope.cs @@ -1,113 +1,110 @@ // 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; -using System.Collections.Generic; using Serilog.Core; using Serilog.Events; -namespace Serilog.Extensions.Logging +namespace Serilog.Extensions.Logging; + +class SerilogLoggerScope : IDisposable { - class SerilogLoggerScope : IDisposable - { - const string NoName = "None"; + const string NoName = "None"; - readonly SerilogLoggerProvider _provider; - readonly object _state; - readonly IDisposable _chainedDisposable; + readonly SerilogLoggerProvider _provider; + readonly object? _state; + readonly IDisposable? _chainedDisposable; - // An optimization only, no problem if there are data races on this. - bool _disposed; + // An optimization only, no problem if there are data races on this. + bool _disposed; - public SerilogLoggerScope(SerilogLoggerProvider provider, object state, IDisposable chainedDisposable = null) - { - _provider = provider; - _state = state; + public SerilogLoggerScope(SerilogLoggerProvider provider, object? state, IDisposable? chainedDisposable = null) + { + _provider = provider; + _state = state; - Parent = _provider.CurrentScope; - _provider.CurrentScope = this; - _chainedDisposable = chainedDisposable; - } + Parent = _provider.CurrentScope; + _provider.CurrentScope = this; + _chainedDisposable = chainedDisposable; + } - public SerilogLoggerScope Parent { get; } + public SerilogLoggerScope Parent { get; } - public void Dispose() + public void Dispose() + { + if (!_disposed) { - if (!_disposed) - { - _disposed = true; - - // In case one of the parent scopes has been disposed out-of-order, don't - // just blindly reinstate our own parent. - for (var scan = _provider.CurrentScope; scan != null; scan = scan.Parent) - { - if (ReferenceEquals(scan, this)) - _provider.CurrentScope = Parent; - } + _disposed = true; - _chainedDisposable?.Dispose(); + // In case one of the parent scopes has been disposed out-of-order, don't + // just blindly reinstate our own parent. + for (var scan = _provider.CurrentScope; scan != null; scan = scan.Parent) + { + if (ReferenceEquals(scan, this)) + _provider.CurrentScope = Parent; } + + _chainedDisposable?.Dispose(); } + } - public void EnrichAndCreateScopeItem(LogEvent logEvent, ILogEventPropertyFactory propertyFactory, out LogEventPropertyValue scopeItem) + public void EnrichAndCreateScopeItem(LogEvent logEvent, ILogEventPropertyFactory propertyFactory, out LogEventPropertyValue? scopeItem) + { + void AddProperty(KeyValuePair stateProperty) { - void AddProperty(KeyValuePair stateProperty) - { - var key = stateProperty.Key; - var destructureObject = false; - var value = stateProperty.Value; - - if (key.StartsWith("@")) - { - key = key.Substring(1); - destructureObject = true; - } - - if (key.StartsWith("$")) - { - key = key.Substring(1); - value = value?.ToString(); - } - - var property = propertyFactory.CreateProperty(key, value, destructureObject); - logEvent.AddPropertyIfAbsent(property); - } + var key = stateProperty.Key; + var destructureObject = false; + var value = stateProperty.Value; - if (_state == null) + if (key.StartsWith("@")) { - scopeItem = null; - return; + key = key.Substring(1); + destructureObject = true; } - // Eliminates boxing of Dictionary.Enumerator for the most common use case - if (_state is Dictionary dictionary) + if (key.StartsWith("$")) { - scopeItem = null; // Unless it's `FormattedLogValues`, these are treated as property bags rather than scope items. - - foreach (var stateProperty in dictionary) - { - if (stateProperty.Key == SerilogLoggerProvider.OriginalFormatPropertyName && stateProperty.Value is string) - scopeItem = new ScalarValue(_state.ToString()); - else - AddProperty(stateProperty); - } + key = key.Substring(1); + value = value?.ToString(); } - else if (_state is IEnumerable> stateProperties) + + var property = propertyFactory.CreateProperty(key, value, destructureObject); + logEvent.AddPropertyIfAbsent(property); + } + + if (_state == null) + { + scopeItem = null; + return; + } + + // Eliminates boxing of Dictionary.Enumerator for the most common use case + if (_state is Dictionary dictionary) + { + scopeItem = null; // Unless it's `FormattedLogValues`, these are treated as property bags rather than scope items. + + foreach (var stateProperty in dictionary) { - scopeItem = null; // Unless it's `FormattedLogValues`, these are treated as property bags rather than scope items. - - foreach (var stateProperty in stateProperties) - { - if (stateProperty.Key == SerilogLoggerProvider.OriginalFormatPropertyName && stateProperty.Value is string) - scopeItem = new ScalarValue(_state.ToString()); - else - AddProperty(stateProperty); - } + if (stateProperty.Key == SerilogLoggerProvider.OriginalFormatPropertyName && stateProperty.Value is string) + scopeItem = new ScalarValue(_state.ToString()); + else + AddProperty(stateProperty); } - else + } + else if (_state is IEnumerable> stateProperties) + { + scopeItem = null; // Unless it's `FormattedLogValues`, these are treated as property bags rather than scope items. + + foreach (var stateProperty in stateProperties) { - scopeItem = propertyFactory.CreateProperty(NoName, _state).Value; + if (stateProperty.Key == SerilogLoggerProvider.OriginalFormatPropertyName && stateProperty.Value is string) + scopeItem = new ScalarValue(_state.ToString()); + else + AddProperty(stateProperty); } } + else + { + scopeItem = propertyFactory.CreateProperty(NoName, _state).Value; + } } } diff --git a/src/Serilog.Extensions.Logging/LoggerSinkConfigurationExtensions.cs b/src/Serilog.Extensions.Logging/LoggerSinkConfigurationExtensions.cs index 9e78511..afbea79 100644 --- a/src/Serilog.Extensions.Logging/LoggerSinkConfigurationExtensions.cs +++ b/src/Serilog.Extensions.Logging/LoggerSinkConfigurationExtensions.cs @@ -1,4 +1,4 @@ -// Copyright 2019 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. @@ -12,38 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using Serilog.Configuration; using Serilog.Core; using Serilog.Events; using Serilog.Extensions.Logging; -namespace Serilog +namespace Serilog; + +/// +/// Extensions for . +/// +public static class LoggerSinkConfigurationExtensions { /// - /// Extensions for . + /// Write Serilog events to the providers in . /// - public static class LoggerSinkConfigurationExtensions + /// The `WriteTo` object. + /// A to write events to. + /// The minimum level for + /// events passed through the sink. Ignored when is specified. + /// A switch allowing the pass-through minimum level + /// to be changed at runtime. + /// A to allow method chaining. + public static LoggerConfiguration Providers( + this LoggerSinkConfiguration configuration, + LoggerProviderCollection providers, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch? levelSwitch = null) { - /// - /// Write Serilog events to the providers in . - /// - /// The `WriteTo` object. - /// A to write events to. - /// The minimum level for - /// events passed through the sink. Ignored when is specified. - /// A switch allowing the pass-through minimum level - /// to be changed at runtime. - /// A to allow method chaining. - public static LoggerConfiguration Providers( - this LoggerSinkConfiguration configuration, - LoggerProviderCollection providers, - LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - LoggingLevelSwitch levelSwitch = null) - { - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - if (providers == null) throw new ArgumentNullException(nameof(providers)); - return configuration.Sink(new LoggerProviderCollectionSink(providers), restrictedToMinimumLevel, levelSwitch); - } + if (configuration == null) throw new ArgumentNullException(nameof(configuration)); + if (providers == null) throw new ArgumentNullException(nameof(providers)); + return configuration.Sink(new LoggerProviderCollectionSink(providers), restrictedToMinimumLevel, levelSwitch); } } diff --git a/src/Serilog.Extensions.Logging/Serilog.Extensions.Logging.csproj b/src/Serilog.Extensions.Logging/Serilog.Extensions.Logging.csproj index 8ec5392..27d593b 100644 --- a/src/Serilog.Extensions.Logging/Serilog.Extensions.Logging.csproj +++ b/src/Serilog.Extensions.Logging/Serilog.Extensions.Logging.csproj @@ -4,29 +4,26 @@ Low-level Serilog provider for Microsoft.Extensions.Logging 3.1.1 Microsoft;Serilog Contributors - netstandard2.0 - true + netstandard2.0 true - Serilog.Extensions.Logging - ../../assets/Serilog.snk - true - true - Serilog.Extensions.Logging serilog;Microsoft.Extensions.Logging serilog-extension-nuget.png https://github.com/serilog/serilog-extensions-logging Apache-2.0 - https://github.com/serilog/serilog-extensions-logging - git false Serilog + git + embedded + true + true + True + README.md - - - + + diff --git a/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs b/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs index 5292603..b9eb557 100644 --- a/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs +++ b/src/Serilog.Extensions.Logging/SerilogLoggerFactoryExtensions.cs @@ -1,36 +1,34 @@ // 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; using Microsoft.Extensions.Logging; using Serilog.Extensions.Logging; -namespace Serilog +namespace Serilog; + +/// +/// Extends with Serilog configuration methods. +/// +public static class SerilogLoggerFactoryExtensions { /// - /// Extends with Serilog configuration methods. + /// Add Serilog to the logging pipeline. /// - public static class SerilogLoggerFactoryExtensions + /// The logger factory to configure. + /// The Serilog logger; if not supplied, the static will be used. + /// 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. + /// Reference to the supplied . + public static ILoggerFactory AddSerilog( + this ILoggerFactory factory, + ILogger? logger = null, + bool dispose = false) { - /// - /// Add Serilog to the logging pipeline. - /// - /// The logger factory to configure. - /// The Serilog logger; if not supplied, the static will be used. - /// 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. - /// Reference to the supplied . - public static ILoggerFactory AddSerilog( - this ILoggerFactory factory, - ILogger logger = null, - bool dispose = false) - { - if (factory == null) throw new ArgumentNullException(nameof(factory)); + if (factory == null) throw new ArgumentNullException(nameof(factory)); - factory.AddProvider(new SerilogLoggerProvider(logger, dispose)); + factory.AddProvider(new SerilogLoggerProvider(logger, dispose)); - return factory; - } + return factory; } -} \ No newline at end of file +} diff --git a/src/Serilog.Extensions.Logging/SerilogLoggingBuilderExtensions.cs b/src/Serilog.Extensions.Logging/SerilogLoggingBuilderExtensions.cs index 2cf0008..1757de0 100644 --- a/src/Serilog.Extensions.Logging/SerilogLoggingBuilderExtensions.cs +++ b/src/Serilog.Extensions.Logging/SerilogLoggingBuilderExtensions.cs @@ -1,4 +1,4 @@ -// Copyright 2017 Serilog Contributors +// Copyright 2017 Serilog Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,43 +12,41 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog.Extensions.Logging; -namespace Serilog +namespace Serilog; + +/// +/// Extends with Serilog configuration methods. +/// +public static class SerilogLoggingBuilderExtensions { /// - /// Extends with Serilog configuration methods. + /// Add Serilog to the logging pipeline. /// - public static class SerilogLoggingBuilderExtensions + /// The to add logging provider to. + /// The Serilog logger; if not supplied, the static will be used. + /// 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. + /// Reference to the supplied . + public static ILoggingBuilder AddSerilog(this ILoggingBuilder builder, ILogger? logger = null, bool dispose = false) { - /// - /// Add Serilog to the logging pipeline. - /// - /// The to add logging provider to. - /// The Serilog logger; if not supplied, the static will be used. - /// 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. - /// Reference to the supplied . - public static ILoggingBuilder AddSerilog(this ILoggingBuilder builder, ILogger logger = null, bool dispose = false) - { - if (builder == null) throw new ArgumentNullException(nameof(builder)); + if (builder == null) throw new ArgumentNullException(nameof(builder)); - if (dispose) - { - builder.Services.AddSingleton(services => new SerilogLoggerProvider(logger, true)); - } - else - { - builder.AddProvider(new SerilogLoggerProvider(logger)); - } + if (dispose) + { + builder.Services.AddSingleton(services => new SerilogLoggerProvider(logger, true)); + } + else + { + builder.AddProvider(new SerilogLoggerProvider(logger)); + } - builder.AddFilter(null, LogLevel.Trace); + builder.AddFilter(null, LogLevel.Trace); - return builder; - } + return builder; } } diff --git a/test/Serilog.Extensions.Logging.Benchmarks/LogEventConstructionBenchmark.cs b/test/Serilog.Extensions.Logging.Benchmarks/LogEventConstructionBenchmark.cs index 51cae2e..415867a 100644 --- a/test/Serilog.Extensions.Logging.Benchmarks/LogEventConstructionBenchmark.cs +++ b/test/Serilog.Extensions.Logging.Benchmarks/LogEventConstructionBenchmark.cs @@ -1,4 +1,4 @@ -// Copyright 2019 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. @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using Microsoft.Extensions.Logging; @@ -21,83 +20,82 @@ using Serilog.Extensions.Logging.Benchmarks.Support; using Xunit; -namespace Serilog.Extensions.Logging.Benchmarks +namespace Serilog.Extensions.Logging.Benchmarks; + +[MemoryDiagnoser] +public class LogEventConstructionBenchmark { - [MemoryDiagnoser] - public class LogEventConstructionBenchmark + readonly IMelLogger _melLogger; + readonly ILogger _serilogContextualLogger; + readonly CapturingSink _sink; + const int LowId = 10, HighId = 101; + const string Template = "This is an event"; + + public LogEventConstructionBenchmark() { - readonly IMelLogger _melLogger; - readonly ILogger _serilogContextualLogger; - readonly CapturingSink _sink; - const int LowId = 10, HighId = 101; - const string Template = "This is an event"; + _sink = new CapturingSink(); + var underlyingLogger = new LoggerConfiguration().WriteTo.Sink(_sink).CreateLogger(); + _serilogContextualLogger = underlyingLogger.ForContext(); + _melLogger = new SerilogLoggerProvider(underlyingLogger).CreateLogger(GetType().FullName!); + } - public LogEventConstructionBenchmark() + static void VerifyEventId(LogEvent? evt, int? expectedId) + { + if (evt == null) throw new ArgumentNullException(nameof(evt)); + if (expectedId == null) { - _sink = new CapturingSink(); - var underlyingLogger = new LoggerConfiguration().WriteTo.Sink(_sink).CreateLogger(); - _serilogContextualLogger = underlyingLogger.ForContext(); - _melLogger = new SerilogLoggerProvider(underlyingLogger).CreateLogger(GetType().FullName); + Assert.False(evt.Properties.TryGetValue("EventId", out _)); } - - static void VerifyEventId(LogEvent evt, int? expectedId) + else { - if (evt == null) throw new ArgumentNullException(nameof(evt)); - if (expectedId == null) - { - Assert.False(evt.Properties.TryGetValue("EventId", out _)); - } - else - { - Assert.True(evt.Properties.TryGetValue("EventId", out var eventIdValue)); - var structure = Assert.IsType(eventIdValue); - var idValue = Assert.Single(structure.Properties, p => p.Name == "Id")?.Value; - var scalar = Assert.IsType(idValue); - Assert.Equal(expectedId.Value, scalar.Value); - } + Assert.True(evt.Properties.TryGetValue("EventId", out var eventIdValue)); + var structure = Assert.IsType(eventIdValue); + var idValue = Assert.Single(structure.Properties, p => p.Name == "Id")?.Value; + var scalar = Assert.IsType(idValue); + Assert.Equal(expectedId.Value, scalar.Value); } + } - [Fact] - public void Verify() - { - VerifyEventId(Native(), null); - VerifyEventId(NoId(), null); - VerifyEventId(LowNumbered(), LowId); - VerifyEventId(HighNumbered(), HighId); - } + [Fact] + public void Verify() + { + VerifyEventId(Native(), null); + VerifyEventId(NoId(), null); + VerifyEventId(LowNumbered(), LowId); + VerifyEventId(HighNumbered(), HighId); + } - [Fact] - public void Benchmark() - { - BenchmarkRunner.Run(); - } + [Fact] + public void Benchmark() + { + BenchmarkRunner.Run(); + } - [Benchmark(Baseline = true)] - public LogEvent Native() - { - _serilogContextualLogger.Information(Template); - return _sink.Collect(); - } + [Benchmark(Baseline = true)] + public LogEvent? Native() + { + _serilogContextualLogger.Information(Template); + return _sink.Collect(); + } - [Benchmark] - public LogEvent NoId() - { - _melLogger.LogInformation(Template); - return _sink.Collect(); - } + [Benchmark] + public LogEvent? NoId() + { + _melLogger.LogInformation(Template); + return _sink.Collect(); + } - [Benchmark] - public LogEvent LowNumbered() - { - _melLogger.LogInformation(LowId, Template); - return _sink.Collect(); - } + [Benchmark] + public LogEvent? LowNumbered() + { + _melLogger.LogInformation(LowId, Template); + return _sink.Collect(); + } - [Benchmark] - public LogEvent HighNumbered() - { - _melLogger.LogInformation(HighId, Template); - return _sink.Collect(); - } + [Benchmark] + public LogEvent? HighNumbered() + { + _melLogger.LogInformation(HighId, Template); + return _sink.Collect(); } } diff --git a/test/Serilog.Extensions.Logging.Benchmarks/Serilog.Extensions.Logging.Benchmarks.csproj b/test/Serilog.Extensions.Logging.Benchmarks/Serilog.Extensions.Logging.Benchmarks.csproj index 7840f21..30050c0 100644 --- a/test/Serilog.Extensions.Logging.Benchmarks/Serilog.Extensions.Logging.Benchmarks.csproj +++ b/test/Serilog.Extensions.Logging.Benchmarks/Serilog.Extensions.Logging.Benchmarks.csproj @@ -1,8 +1,7 @@ - + - netcoreapp2.2 - true + net7 @@ -10,17 +9,13 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - + + diff --git a/test/Serilog.Extensions.Logging.Benchmarks/Support/CapturingSink.cs b/test/Serilog.Extensions.Logging.Benchmarks/Support/CapturingSink.cs index 3913561..555ea88 100644 --- a/test/Serilog.Extensions.Logging.Benchmarks/Support/CapturingSink.cs +++ b/test/Serilog.Extensions.Logging.Benchmarks/Support/CapturingSink.cs @@ -1,4 +1,4 @@ -// Copyright 2019 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,22 +15,21 @@ using Serilog.Core; using Serilog.Events; -namespace Serilog.Extensions.Logging.Benchmarks.Support +namespace Serilog.Extensions.Logging.Benchmarks.Support; + +class CapturingSink : ILogEventSink { - class CapturingSink : ILogEventSink - { - LogEvent _emitted; + LogEvent? _emitted; - public void Emit(LogEvent logEvent) - { - _emitted = logEvent; - } + public void Emit(LogEvent logEvent) + { + _emitted = logEvent; + } - public LogEvent Collect() - { - var collected = _emitted; - _emitted = null; - return collected; - } + public LogEvent? Collect() + { + var collected = _emitted; + _emitted = null; + return collected; } } diff --git a/test/Serilog.Extensions.Logging.Tests/LoggerProviderCollectionSinkTests.cs b/test/Serilog.Extensions.Logging.Tests/LoggerProviderCollectionSinkTests.cs index 0be1b4c..dad17b5 100644 --- a/test/Serilog.Extensions.Logging.Tests/LoggerProviderCollectionSinkTests.cs +++ b/test/Serilog.Extensions.Logging.Tests/LoggerProviderCollectionSinkTests.cs @@ -1,85 +1,83 @@ // 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; using Microsoft.Extensions.Logging; using Serilog.Extensions.Logging.Tests.Support; using Xunit; -namespace Serilog.Extensions.Logging.Tests +namespace Serilog.Extensions.Logging.Tests; + +public class LoggerProviderCollectionSinkTests { - public class LoggerProviderCollectionSinkTests + const string Name = "test"; + const string TestMessage = "This is a test"; + + static Tuple SetUp(LogLevel logLevel) + { + var providers = new LoggerProviderCollection(); + var provider = new ExtensionsProvider(logLevel); + providers.AddProvider(provider); + var serilogLogger = new LoggerConfiguration() + .WriteTo.Providers(providers) + .MinimumLevel.Is(LevelConvert.ToSerilogLevel(logLevel)) + .CreateLogger(); + + var logger = (SerilogLogger)new SerilogLoggerProvider(serilogLogger).CreateLogger(Name); + + return new Tuple(logger, provider); + } + + [Fact] + public void LogsCorrectLevel() + { + var (logger, sink) = SetUp(LogLevel.Trace); + + logger.Log(LogLevel.Trace, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Debug, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Warning, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Error, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Critical, 0, TestMessage, null!, null!); + + Assert.Equal(6, sink.Writes.Count); + Assert.Equal(LogLevel.Trace, sink.Writes[0].logLevel); + Assert.Equal(LogLevel.Debug, sink.Writes[1].logLevel); + Assert.Equal(LogLevel.Information, sink.Writes[2].logLevel); + Assert.Equal(LogLevel.Warning, sink.Writes[3].logLevel); + Assert.Equal(LogLevel.Error, sink.Writes[4].logLevel); + Assert.Equal(LogLevel.Critical, sink.Writes[5].logLevel); + } + + [Fact] + public void LogsCorrectEventId() { - const string Name = "test"; - const string TestMessage = "This is a test"; - - static Tuple SetUp(LogLevel logLevel) - { - var providers = new LoggerProviderCollection(); - var provider = new ExtensionsProvider(logLevel); - providers.AddProvider(provider); - var serilogLogger = new LoggerConfiguration() - .WriteTo.Providers(providers) - .MinimumLevel.Is(LevelConvert.ToSerilogLevel(logLevel)) - .CreateLogger(); - - var logger = (SerilogLogger)new SerilogLoggerProvider(serilogLogger).CreateLogger(Name); - - return new Tuple(logger, provider); - } - - [Fact] - public void LogsCorrectLevel() - { - var (logger, sink) = SetUp(LogLevel.Trace); - - logger.Log(LogLevel.Trace, 0, TestMessage, null, null); - logger.Log(LogLevel.Debug, 0, TestMessage, null, null); - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - logger.Log(LogLevel.Warning, 0, TestMessage, null, null); - logger.Log(LogLevel.Error, 0, TestMessage, null, null); - logger.Log(LogLevel.Critical, 0, TestMessage, null, null); - - Assert.Equal(6, sink.Writes.Count); - Assert.Equal(LogLevel.Trace, sink.Writes[0].logLevel); - Assert.Equal(LogLevel.Debug, sink.Writes[1].logLevel); - Assert.Equal(LogLevel.Information, sink.Writes[2].logLevel); - Assert.Equal(LogLevel.Warning, sink.Writes[3].logLevel); - Assert.Equal(LogLevel.Error, sink.Writes[4].logLevel); - Assert.Equal(LogLevel.Critical, sink.Writes[5].logLevel); - } - - [Fact] - public void LogsCorrectEventId() - { - var (logger, sink) = SetUp(LogLevel.Trace); - - logger.Log(LogLevel.Trace, new EventId(1, nameof(LogLevel.Trace)), TestMessage, null, null); - logger.Log(LogLevel.Debug, new EventId(2, nameof(LogLevel.Debug)), TestMessage, null, null); - logger.Log(LogLevel.Information, new EventId(3, nameof(LogLevel.Information)), TestMessage, null, null); - logger.Log(LogLevel.Warning, new EventId(4, nameof(LogLevel.Warning)), TestMessage, null, null); - logger.Log(LogLevel.Error, new EventId(5, nameof(LogLevel.Error)), TestMessage, null, null); - logger.Log(LogLevel.Critical, new EventId(6, nameof(LogLevel.Critical)), TestMessage, null, null); - - Assert.Equal(6, sink.Writes.Count); - - Assert.Equal(1, sink.Writes[0].eventId.Id); - Assert.Equal(nameof(LogLevel.Trace), sink.Writes[0].eventId.Name); - - Assert.Equal(2, sink.Writes[1].eventId.Id); - Assert.Equal(nameof(LogLevel.Debug), sink.Writes[1].eventId.Name); - - Assert.Equal(3, sink.Writes[2].eventId.Id); - Assert.Equal(nameof(LogLevel.Information), sink.Writes[2].eventId.Name); - - Assert.Equal(4, sink.Writes[3].eventId.Id); - Assert.Equal(nameof(LogLevel.Warning), sink.Writes[3].eventId.Name); - - Assert.Equal(5, sink.Writes[4].eventId.Id); - Assert.Equal(nameof(LogLevel.Error), sink.Writes[4].eventId.Name); - - Assert.Equal(6, sink.Writes[5].eventId.Id); - Assert.Equal(nameof(LogLevel.Critical), sink.Writes[5].eventId.Name); - } + var (logger, sink) = SetUp(LogLevel.Trace); + + logger.Log(LogLevel.Trace, new EventId(1, nameof(LogLevel.Trace)), TestMessage, null!, null!); + logger.Log(LogLevel.Debug, new EventId(2, nameof(LogLevel.Debug)), TestMessage, null!, null!); + logger.Log(LogLevel.Information, new EventId(3, nameof(LogLevel.Information)), TestMessage, null!, null!); + logger.Log(LogLevel.Warning, new EventId(4, nameof(LogLevel.Warning)), TestMessage, null!, null!); + logger.Log(LogLevel.Error, new EventId(5, nameof(LogLevel.Error)), TestMessage, null!, null!); + logger.Log(LogLevel.Critical, new EventId(6, nameof(LogLevel.Critical)), TestMessage, null!, null!); + + Assert.Equal(6, sink.Writes.Count); + + Assert.Equal(1, sink.Writes[0].eventId.Id); + Assert.Equal(nameof(LogLevel.Trace), sink.Writes[0].eventId.Name); + + Assert.Equal(2, sink.Writes[1].eventId.Id); + Assert.Equal(nameof(LogLevel.Debug), sink.Writes[1].eventId.Name); + + Assert.Equal(3, sink.Writes[2].eventId.Id); + Assert.Equal(nameof(LogLevel.Information), sink.Writes[2].eventId.Name); + + Assert.Equal(4, sink.Writes[3].eventId.Id); + Assert.Equal(nameof(LogLevel.Warning), sink.Writes[3].eventId.Name); + + Assert.Equal(5, sink.Writes[4].eventId.Id); + Assert.Equal(nameof(LogLevel.Error), sink.Writes[4].eventId.Name); + + Assert.Equal(6, sink.Writes[5].eventId.Id); + Assert.Equal(nameof(LogLevel.Critical), sink.Writes[5].eventId.Name); } } diff --git a/test/Serilog.Extensions.Logging.Tests/Serilog.Extensions.Logging.Tests.csproj b/test/Serilog.Extensions.Logging.Tests/Serilog.Extensions.Logging.Tests.csproj index e1a144a..0680497 100644 --- a/test/Serilog.Extensions.Logging.Tests/Serilog.Extensions.Logging.Tests.csproj +++ b/test/Serilog.Extensions.Logging.Tests/Serilog.Extensions.Logging.Tests.csproj @@ -1,13 +1,7 @@ - netcoreapp2.0;net472 - Serilog.Extensions.Logging.Tests - ../../assets/Serilog.snk - true - true - Serilog.Extensions.Logging.Tests - true + net7;net472 @@ -15,9 +9,12 @@ - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/test/Serilog.Extensions.Logging.Tests/SerilogLogValuesTests.cs b/test/Serilog.Extensions.Logging.Tests/SerilogLogValuesTests.cs index d5a777e..a1f3025 100644 --- a/test/Serilog.Extensions.Logging.Tests/SerilogLogValuesTests.cs +++ b/test/Serilog.Extensions.Logging.Tests/SerilogLogValuesTests.cs @@ -1,53 +1,50 @@ using Serilog.Events; using Serilog.Parsing; -using System.Collections.Generic; -using System.Linq; using Xunit; -namespace Serilog.Extensions.Logging.Tests +namespace Serilog.Extensions.Logging.Tests; + +public class SerilogLogValuesTests { - public class SerilogLogValuesTests + [Fact] + public void OriginalFormatIsExposed() { - [Fact] - public void OriginalFormatIsExposed() - { - const string format = "Hello, {Name}!"; - var mt = new MessageTemplateParser().Parse(format); - var lv = new SerilogLogValues(mt, new Dictionary()); - var kvp = lv.Single(); - Assert.Equal("{OriginalFormat}", kvp.Key); - Assert.Equal(format, kvp.Value); - } + const string format = "Hello, {Name}!"; + var mt = new MessageTemplateParser().Parse(format); + var lv = new SerilogLogValues(mt, new Dictionary()); + var kvp = lv.Single(); + Assert.Equal("{OriginalFormat}", kvp.Key); + Assert.Equal(format, kvp.Value); + } - [Fact] - public void ScalarPropertiesAreSimplified() - { - const string name = "Scalar"; - var scalar = 15; - var lv = new SerilogLogValues(MessageTemplate.Empty, new Dictionary { [name] = new ScalarValue(scalar) }); - var kvp = lv.Single(p => p.Key == name); - var sv = Assert.IsType(kvp.Value); - Assert.Equal(scalar, sv); - } + [Fact] + public void ScalarPropertiesAreSimplified() + { + const string name = "Scalar"; + var scalar = 15; + var lv = new SerilogLogValues(MessageTemplate.Empty, new Dictionary { [name] = new ScalarValue(scalar) }); + var kvp = lv.Single(p => p.Key == name); + var sv = Assert.IsType(kvp.Value); + Assert.Equal(scalar, sv); + } - [Fact] - public void NonscalarPropertiesAreWrapped() - { - const string name = "Sequence"; - var seq = new SequenceValue(Enumerable.Empty()); - var lv = new SerilogLogValues(MessageTemplate.Empty, new Dictionary { [name] = seq }); - var kvp = lv.Single(p => p.Key == name); - var sv = Assert.IsType(kvp.Value); - Assert.Equal(seq, sv); - } + [Fact] + public void NonscalarPropertiesAreWrapped() + { + const string name = "Sequence"; + var seq = new SequenceValue(Enumerable.Empty()); + var lv = new SerilogLogValues(MessageTemplate.Empty, new Dictionary { [name] = seq }); + var kvp = lv.Single(p => p.Key == name); + var sv = Assert.IsType(kvp.Value); + Assert.Equal(seq, sv); + } - [Fact] - public void MessageTemplatesAreRendered() - { - const string format = "Hello, {Name}!"; - var mt = new MessageTemplateParser().Parse(format); - var lv = new SerilogLogValues(mt, new Dictionary { ["Name"] = new ScalarValue("World") }); - Assert.Equal("Hello, \"World\"!", lv.ToString()); - } + [Fact] + public void MessageTemplatesAreRendered() + { + const string format = "Hello, {Name}!"; + var mt = new MessageTemplateParser().Parse(format); + var lv = new SerilogLogValues(mt, new Dictionary { ["Name"] = new ScalarValue("World") }); + Assert.Equal("Hello, \"World\"!", lv.ToString()); } } diff --git a/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs b/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs index d3a0eb5..fcaf1f8 100644 --- a/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs +++ b/test/Serilog.Extensions.Logging.Tests/SerilogLoggerTests.cs @@ -1,477 +1,472 @@ -// 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; using System.Collections; using Serilog.Events; using Microsoft.Extensions.Logging; -using System.Collections.Generic; -using System.IO; -using System.Linq; using Serilog.Debugging; using Serilog.Extensions.Logging.Tests.Support; using Xunit; -namespace Serilog.Extensions.Logging.Tests +namespace Serilog.Extensions.Logging.Tests; + +public class SerilogLoggerTest { - public class SerilogLoggerTest + const string Name = "test"; + const string TestMessage = "This is a test"; + + static Tuple SetUp(LogLevel logLevel) { - const string Name = "test"; - const string TestMessage = "This is a test"; + var sink = new SerilogSink(); - static Tuple SetUp(LogLevel logLevel) - { - var sink = new SerilogSink(); + var serilogLogger = new LoggerConfiguration() + .WriteTo.Sink(sink) + .MinimumLevel.Is(LevelConvert.ToSerilogLevel(logLevel)) + .CreateLogger(); - var serilogLogger = new LoggerConfiguration() - .WriteTo.Sink(sink) - .MinimumLevel.Is(LevelConvert.ToSerilogLevel(logLevel)) - .CreateLogger(); + var provider = new SerilogLoggerProvider(serilogLogger); + var logger = (SerilogLogger)provider.CreateLogger(Name); - var provider = new SerilogLoggerProvider(serilogLogger); - var logger = (SerilogLogger)provider.CreateLogger(Name); + return new Tuple(logger, sink); + } - return new Tuple(logger, sink); - } + [Fact] + public void LogsWhenNullFilterGiven() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void LogsWhenNullFilterGiven() - { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); - logger.Log(LogLevel.Information, 0, TestMessage, null, null); + Assert.Single(sink.Writes); + } - Assert.Equal(1, sink.Writes.Count); - } + [Fact] + public void LogsCorrectLevel() + { + var (logger, sink) = SetUp(LogLevel.Trace); + + logger.Log(LogLevel.Trace, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Debug, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Warning, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Error, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Critical, 0, TestMessage, null!, null!); + logger.Log(LogLevel.None, 0, TestMessage, null!, null!); + + Assert.Equal(6, sink.Writes.Count); + Assert.Equal(LogEventLevel.Verbose, sink.Writes[0].Level); + Assert.Equal(LogEventLevel.Debug, sink.Writes[1].Level); + Assert.Equal(LogEventLevel.Information, sink.Writes[2].Level); + Assert.Equal(LogEventLevel.Warning, sink.Writes[3].Level); + Assert.Equal(LogEventLevel.Error, sink.Writes[4].Level); + Assert.Equal(LogEventLevel.Fatal, sink.Writes[5].Level); + } - [Fact] - public void LogsCorrectLevel() - { - var (logger, sink) = SetUp(LogLevel.Trace); - - logger.Log(LogLevel.Trace, 0, TestMessage, null, null); - logger.Log(LogLevel.Debug, 0, TestMessage, null, null); - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - logger.Log(LogLevel.Warning, 0, TestMessage, null, null); - logger.Log(LogLevel.Error, 0, TestMessage, null, null); - logger.Log(LogLevel.Critical, 0, TestMessage, null, null); - logger.Log(LogLevel.None, 0, TestMessage, null, null); - - Assert.Equal(6, sink.Writes.Count); - Assert.Equal(LogEventLevel.Verbose, sink.Writes[0].Level); - Assert.Equal(LogEventLevel.Debug, sink.Writes[1].Level); - Assert.Equal(LogEventLevel.Information, sink.Writes[2].Level); - Assert.Equal(LogEventLevel.Warning, sink.Writes[3].Level); - Assert.Equal(LogEventLevel.Error, sink.Writes[4].Level); - Assert.Equal(LogEventLevel.Fatal, sink.Writes[5].Level); - } + [Theory] + [InlineData(LogLevel.Trace, true)] + [InlineData(LogLevel.Debug, true)] + [InlineData(LogLevel.Information, true)] + [InlineData(LogLevel.Warning, true)] + [InlineData(LogLevel.Error, true)] + [InlineData(LogLevel.Critical, true)] + [InlineData(LogLevel.None, false)] + public void IsEnabledCorrect(LogLevel logLevel, bool isEnabled) + { + var (logger, _) = SetUp(LogLevel.Trace); - [Theory] - [InlineData(LogLevel.Trace, true)] - [InlineData(LogLevel.Debug, true)] - [InlineData(LogLevel.Information, true)] - [InlineData(LogLevel.Warning, true)] - [InlineData(LogLevel.Error, true)] - [InlineData(LogLevel.Critical, true)] - [InlineData(LogLevel.None, false)] - public void IsEnabledCorrect(LogLevel logLevel, bool isEnabled) - { - var (logger, _) = SetUp(LogLevel.Trace); + Assert.Equal(isEnabled, logger.IsEnabled(logLevel)); + } - Assert.Equal(isEnabled, logger.IsEnabled(logLevel)); - } + [Theory] + [InlineData(LogLevel.Trace, LogLevel.Trace, 1)] + [InlineData(LogLevel.Trace, LogLevel.Debug, 1)] + [InlineData(LogLevel.Trace, LogLevel.Information, 1)] + [InlineData(LogLevel.Trace, LogLevel.Warning, 1)] + [InlineData(LogLevel.Trace, LogLevel.Error, 1)] + [InlineData(LogLevel.Trace, LogLevel.Critical, 1)] + [InlineData(LogLevel.Trace, LogLevel.None, 0)] + [InlineData(LogLevel.Debug, LogLevel.Trace, 0)] + [InlineData(LogLevel.Debug, LogLevel.Debug, 1)] + [InlineData(LogLevel.Debug, LogLevel.Information, 1)] + [InlineData(LogLevel.Debug, LogLevel.Warning, 1)] + [InlineData(LogLevel.Debug, LogLevel.Error, 1)] + [InlineData(LogLevel.Debug, LogLevel.Critical, 1)] + [InlineData(LogLevel.Debug, LogLevel.None, 0)] + [InlineData(LogLevel.Information, LogLevel.Trace, 0)] + [InlineData(LogLevel.Information, LogLevel.Debug, 0)] + [InlineData(LogLevel.Information, LogLevel.Information, 1)] + [InlineData(LogLevel.Information, LogLevel.Warning, 1)] + [InlineData(LogLevel.Information, LogLevel.Error, 1)] + [InlineData(LogLevel.Information, LogLevel.Critical, 1)] + [InlineData(LogLevel.Information, LogLevel.None, 0)] + [InlineData(LogLevel.Warning, LogLevel.Trace, 0)] + [InlineData(LogLevel.Warning, LogLevel.Debug, 0)] + [InlineData(LogLevel.Warning, LogLevel.Information, 0)] + [InlineData(LogLevel.Warning, LogLevel.Warning, 1)] + [InlineData(LogLevel.Warning, LogLevel.Error, 1)] + [InlineData(LogLevel.Warning, LogLevel.Critical, 1)] + [InlineData(LogLevel.Warning, LogLevel.None, 0)] + [InlineData(LogLevel.Error, LogLevel.Trace, 0)] + [InlineData(LogLevel.Error, LogLevel.Debug, 0)] + [InlineData(LogLevel.Error, LogLevel.Information, 0)] + [InlineData(LogLevel.Error, LogLevel.Warning, 0)] + [InlineData(LogLevel.Error, LogLevel.Error, 1)] + [InlineData(LogLevel.Error, LogLevel.Critical, 1)] + [InlineData(LogLevel.Error, LogLevel.None, 0)] + [InlineData(LogLevel.Critical, LogLevel.Trace, 0)] + [InlineData(LogLevel.Critical, LogLevel.Debug, 0)] + [InlineData(LogLevel.Critical, LogLevel.Information, 0)] + [InlineData(LogLevel.Critical, LogLevel.Warning, 0)] + [InlineData(LogLevel.Critical, LogLevel.Error, 0)] + [InlineData(LogLevel.Critical, LogLevel.Critical, 1)] + [InlineData(LogLevel.Critical, LogLevel.None, 0)] + public void LogsWhenEnabled(LogLevel minLevel, LogLevel logLevel, int expected) + { + var (logger, sink) = SetUp(minLevel); - [Theory] - [InlineData(LogLevel.Trace, LogLevel.Trace, 1)] - [InlineData(LogLevel.Trace, LogLevel.Debug, 1)] - [InlineData(LogLevel.Trace, LogLevel.Information, 1)] - [InlineData(LogLevel.Trace, LogLevel.Warning, 1)] - [InlineData(LogLevel.Trace, LogLevel.Error, 1)] - [InlineData(LogLevel.Trace, LogLevel.Critical, 1)] - [InlineData(LogLevel.Trace, LogLevel.None, 0)] - [InlineData(LogLevel.Debug, LogLevel.Trace, 0)] - [InlineData(LogLevel.Debug, LogLevel.Debug, 1)] - [InlineData(LogLevel.Debug, LogLevel.Information, 1)] - [InlineData(LogLevel.Debug, LogLevel.Warning, 1)] - [InlineData(LogLevel.Debug, LogLevel.Error, 1)] - [InlineData(LogLevel.Debug, LogLevel.Critical, 1)] - [InlineData(LogLevel.Debug, LogLevel.None, 0)] - [InlineData(LogLevel.Information, LogLevel.Trace, 0)] - [InlineData(LogLevel.Information, LogLevel.Debug, 0)] - [InlineData(LogLevel.Information, LogLevel.Information, 1)] - [InlineData(LogLevel.Information, LogLevel.Warning, 1)] - [InlineData(LogLevel.Information, LogLevel.Error, 1)] - [InlineData(LogLevel.Information, LogLevel.Critical, 1)] - [InlineData(LogLevel.Information, LogLevel.None, 0)] - [InlineData(LogLevel.Warning, LogLevel.Trace, 0)] - [InlineData(LogLevel.Warning, LogLevel.Debug, 0)] - [InlineData(LogLevel.Warning, LogLevel.Information, 0)] - [InlineData(LogLevel.Warning, LogLevel.Warning, 1)] - [InlineData(LogLevel.Warning, LogLevel.Error, 1)] - [InlineData(LogLevel.Warning, LogLevel.Critical, 1)] - [InlineData(LogLevel.Warning, LogLevel.None, 0)] - [InlineData(LogLevel.Error, LogLevel.Trace, 0)] - [InlineData(LogLevel.Error, LogLevel.Debug, 0)] - [InlineData(LogLevel.Error, LogLevel.Information, 0)] - [InlineData(LogLevel.Error, LogLevel.Warning, 0)] - [InlineData(LogLevel.Error, LogLevel.Error, 1)] - [InlineData(LogLevel.Error, LogLevel.Critical, 1)] - [InlineData(LogLevel.Error, LogLevel.None, 0)] - [InlineData(LogLevel.Critical, LogLevel.Trace, 0)] - [InlineData(LogLevel.Critical, LogLevel.Debug, 0)] - [InlineData(LogLevel.Critical, LogLevel.Information, 0)] - [InlineData(LogLevel.Critical, LogLevel.Warning, 0)] - [InlineData(LogLevel.Critical, LogLevel.Error, 0)] - [InlineData(LogLevel.Critical, LogLevel.Critical, 1)] - [InlineData(LogLevel.Critical, LogLevel.None, 0)] - public void LogsWhenEnabled(LogLevel minLevel, LogLevel logLevel, int expected) - { - var (logger, sink) = SetUp(minLevel); + logger.Log(logLevel, 0, TestMessage, null!, null!); - logger.Log(logLevel, 0, TestMessage, null, null); + Assert.Equal(expected, sink.Writes.Count); + } - Assert.Equal(expected, sink.Writes.Count); - } + [Fact] + public void LogsCorrectMessage() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void LogsCorrectMessage() - { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, null!, null!, null!); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + logger.Log(LogLevel.Information, 0, null!, null!, (_, __) => TestMessage); - logger.Log(LogLevel.Information, 0, null, null, null); - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - logger.Log(LogLevel.Information, 0, null, null, (_, __) => TestMessage); + Assert.Equal(3, sink.Writes.Count); - Assert.Equal(3, sink.Writes.Count); + Assert.Equal(1, sink.Writes[0].Properties.Count); + Assert.Empty(sink.Writes[0].RenderMessage()); - Assert.Equal(1, sink.Writes[0].Properties.Count); - Assert.Empty(sink.Writes[0].RenderMessage()); + Assert.Equal(2, sink.Writes[1].Properties.Count); + Assert.True(sink.Writes[1].Properties.ContainsKey("State")); + Assert.Equal(TestMessage, sink.Writes[1].RenderMessage()); - Assert.Equal(2, sink.Writes[1].Properties.Count); - Assert.True(sink.Writes[1].Properties.ContainsKey("State")); - Assert.Equal(TestMessage, sink.Writes[1].RenderMessage()); + Assert.Equal(2, sink.Writes[2].Properties.Count); + Assert.True(sink.Writes[2].Properties.ContainsKey("Message")); + Assert.Equal(TestMessage, sink.Writes[2].RenderMessage()); + } - Assert.Equal(2, sink.Writes[2].Properties.Count); - Assert.True(sink.Writes[2].Properties.ContainsKey("Message")); - Assert.Equal(TestMessage, sink.Writes[2].RenderMessage()); - } + [Fact] + public void CarriesException() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void CarriesException() - { - var (logger, sink) = SetUp(LogLevel.Trace); + var exception = new Exception(); - var exception = new Exception(); + logger.Log(LogLevel.Information, 0, "Test", exception, null!); - logger.Log(LogLevel.Information, 0, "Test", exception, null); + Assert.Single(sink.Writes); + Assert.Same(exception, sink.Writes[0].Exception); + } - Assert.Equal(1, sink.Writes.Count); - Assert.Same(exception, sink.Writes[0].Exception); - } + [Fact] + public void SingleScopeProperty() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void SingleScopeProperty() + using (logger.BeginScope(new FoodScope("pizza"))) { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + } - using (logger.BeginScope(new FoodScope("pizza"))) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); + Assert.Equal("\"pizza\"", sink.Writes[0].Properties["Name"].ToString()); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); - Assert.Equal("\"pizza\"", sink.Writes[0].Properties["Name"].ToString()); - } + [Fact] + public void StringifyScopeProperty() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void StringifyScopeProperty() + using (logger.BeginScope("{$values}", new [] { 1, 2, 3, 4 })) { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + } - using (logger.BeginScope("{$values}", new [] { 1, 2, 3, 4 })) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("values")); + Assert.Equal("\"System.Int32[]\"", sink.Writes[0].Properties["values"].ToString()); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("values")); - Assert.Equal("\"System.Int32[]\"", sink.Writes[0].Properties["values"].ToString()); - } + [Fact] + public void NestedScopeSameProperty() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void NestedScopeSameProperty() + using (logger.BeginScope(new FoodScope("avocado"))) { - var (logger, sink) = SetUp(LogLevel.Trace); - - using (logger.BeginScope(new FoodScope("avocado"))) + using (logger.BeginScope(new FoodScope("bacon"))) { - using (logger.BeginScope(new FoodScope("bacon"))) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); } - - // Should retain the property of the most specific scope - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); - Assert.Equal("\"bacon\"", sink.Writes[0].Properties["Name"].ToString()); } - [Fact] - public void NestedScopesDifferentProperties() - { - var (logger, sink) = SetUp(LogLevel.Trace); + // Should retain the property of the most specific scope + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); + Assert.Equal("\"bacon\"", sink.Writes[0].Properties["Name"].ToString()); + } + + [Fact] + public void NestedScopesDifferentProperties() + { + var (logger, sink) = SetUp(LogLevel.Trace); - using (logger.BeginScope(new FoodScope("spaghetti"))) + using (logger.BeginScope(new FoodScope("spaghetti"))) + { + using (logger.BeginScope(new LuckyScope(7))) { - using (logger.BeginScope(new LuckyScope(7))) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); } - - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); - Assert.Equal("\"spaghetti\"", sink.Writes[0].Properties["Name"].ToString()); - Assert.True(sink.Writes[0].Properties.ContainsKey("LuckyNumber")); - Assert.Equal("7", sink.Writes[0].Properties["LuckyNumber"].ToString()); } - [Fact] - public void CarriesMessageTemplateProperties() - { - var selfLog = new StringWriter(); - SelfLog.Enable(selfLog); - - var (logger, sink) = SetUp(LogLevel.Trace); + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("Name")); + Assert.Equal("\"spaghetti\"", sink.Writes[0].Properties["Name"].ToString()); + Assert.True(sink.Writes[0].Properties.ContainsKey("LuckyNumber")); + Assert.Equal("7", sink.Writes[0].Properties["LuckyNumber"].ToString()); + } - logger.LogInformation("Hello, {Recipient}", "World"); + [Fact] + public void CarriesMessageTemplateProperties() + { + var selfLog = new StringWriter(); + SelfLog.Enable(selfLog); - Assert.True(sink.Writes[0].Properties.ContainsKey("Recipient")); - Assert.Equal("\"World\"", sink.Writes[0].Properties["Recipient"].ToString()); - Assert.Equal("Hello, {Recipient}", sink.Writes[0].MessageTemplate.Text); + var (logger, sink) = SetUp(LogLevel.Trace); - SelfLog.Disable(); - Assert.Empty(selfLog.ToString()); - } + logger.LogInformation("Hello, {Recipient}", "World"); - [Fact] - public void CarriesMessageTemplatePropertiesWhenStringificationIsUsed() - { - var selfLog = new StringWriter(); - SelfLog.Enable(selfLog); - var (logger, sink) = SetUp(LogLevel.Trace); - var array = new[] { 1, 2, 3, 4 }; + Assert.True(sink.Writes[0].Properties.ContainsKey("Recipient")); + Assert.Equal("\"World\"", sink.Writes[0].Properties["Recipient"].ToString()); + Assert.Equal("Hello, {Recipient}", sink.Writes[0].MessageTemplate.Text); - logger.LogInformation("{$array}", array); + SelfLog.Disable(); + Assert.Empty(selfLog.ToString()); + } - Assert.True(sink.Writes[0].Properties.ContainsKey("array")); - Assert.Equal("\"System.Int32[]\"", sink.Writes[0].Properties["array"].ToString()); - Assert.Equal("{$array}", sink.Writes[0].MessageTemplate.Text); + [Fact] + public void CarriesMessageTemplatePropertiesWhenStringificationIsUsed() + { + var selfLog = new StringWriter(); + SelfLog.Enable(selfLog); + var (logger, sink) = SetUp(LogLevel.Trace); + var array = new[] { 1, 2, 3, 4 }; - SelfLog.Disable(); - Assert.Empty(selfLog.ToString()); - } + logger.LogInformation("{$array}", array); - [Fact] - public void CarriesEventIdIfNonzero() - { - var (logger, sink) = SetUp(LogLevel.Trace); + Assert.True(sink.Writes[0].Properties.ContainsKey("array")); + Assert.Equal("\"System.Int32[]\"", sink.Writes[0].Properties["array"].ToString()); + Assert.Equal("{$array}", sink.Writes[0].MessageTemplate.Text); - const int expected = 42; + SelfLog.Disable(); + Assert.Empty(selfLog.ToString()); + } - logger.Log(LogLevel.Information, expected, "Test", null, null); + [Fact] + public void CarriesEventIdIfNonzero() + { + var (logger, sink) = SetUp(LogLevel.Trace); - Assert.Equal(1, sink.Writes.Count); + const int expected = 42; - var eventId = (StructureValue) sink.Writes[0].Properties["EventId"]; - var id = (ScalarValue) eventId.Properties.Single(p => p.Name == "Id").Value; - Assert.Equal(42, id.Value); - } + logger.Log(LogLevel.Information, expected, "Test", null!, null!); - [Fact] - public void WhenDisposeIsFalseProvidedLoggerIsNotDisposed() - { - var logger = new DisposeTrackingLogger(); - // ReSharper disable once RedundantArgumentDefaultValue - var provider = new SerilogLoggerProvider(logger, false); - provider.Dispose(); - Assert.False(logger.IsDisposed); - } + Assert.Single(sink.Writes); - [Fact] - public void WhenDisposeIsTrueProvidedLoggerIsDisposed() - { - var logger = new DisposeTrackingLogger(); - var provider = new SerilogLoggerProvider(logger, true); - provider.Dispose(); - Assert.True(logger.IsDisposed); - } + var eventId = (StructureValue) sink.Writes[0].Properties["EventId"]; + var id = (ScalarValue) eventId.Properties.Single(p => p.Name == "Id").Value; + Assert.Equal(42, id.Value); + } - [Fact] - public void BeginScopeDestructuresObjectsWhenDestructurerIsUsedInMessageTemplate() - { - var (logger, sink) = SetUp(LogLevel.Trace); + [Fact] + public void WhenDisposeIsFalseProvidedLoggerIsNotDisposed() + { + var logger = new DisposeTrackingLogger(); + // ReSharper disable once RedundantArgumentDefaultValue + var provider = new SerilogLoggerProvider(logger, false); + provider.Dispose(); + Assert.False(logger.IsDisposed); + } - using (logger.BeginScope("{@Person}", new Person { FirstName = "John", LastName = "Smith" })) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + [Fact] + public void WhenDisposeIsTrueProvidedLoggerIsDisposed() + { + var logger = new DisposeTrackingLogger(); + var provider = new SerilogLoggerProvider(logger, true); + provider.Dispose(); + Assert.True(logger.IsDisposed); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("Person")); + [Fact] + public void BeginScopeDestructuresObjectsWhenDestructurerIsUsedInMessageTemplate() + { + var (logger, sink) = SetUp(LogLevel.Trace); - var person = (StructureValue)sink.Writes[0].Properties["Person"]; - var firstName = (ScalarValue)person.Properties.Single(p => p.Name == "FirstName").Value; - var lastName = (ScalarValue)person.Properties.Single(p => p.Name == "LastName").Value; - Assert.Equal("John", firstName.Value); - Assert.Equal("Smith", lastName.Value); + using (logger.BeginScope("{@Person}", new Person { FirstName = "John", LastName = "Smith" })) + { + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); } - [Fact] - public void BeginScopeDestructuresObjectsWhenDestructurerIsUsedInDictionary() - { - var (logger, sink) = SetUp(LogLevel.Trace); + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("Person")); - using (logger.BeginScope(new Dictionary {{ "@Person", new Person { FirstName = "John", LastName = "Smith" }}})) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + var person = (StructureValue)sink.Writes[0].Properties["Person"]; + var firstName = (ScalarValue)person.Properties.Single(p => p.Name == "FirstName").Value; + var lastName = (ScalarValue)person.Properties.Single(p => p.Name == "LastName").Value; + Assert.Equal("John", firstName.Value); + Assert.Equal("Smith", lastName.Value); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("Person")); + [Fact] + public void BeginScopeDestructuresObjectsWhenDestructurerIsUsedInDictionary() + { + var (logger, sink) = SetUp(LogLevel.Trace); - var person = (StructureValue)sink.Writes[0].Properties["Person"]; - var firstName = (ScalarValue)person.Properties.Single(p => p.Name == "FirstName").Value; - var lastName = (ScalarValue)person.Properties.Single(p => p.Name == "LastName").Value; - Assert.Equal("John", firstName.Value); - Assert.Equal("Smith", lastName.Value); + using (logger.BeginScope(new Dictionary {{ "@Person", new Person { FirstName = "John", LastName = "Smith" }}})) + { + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); } - [Fact] - public void BeginScopeDoesNotModifyKeyWhenDestructurerIsNotUsedInMessageTemplate() - { - var (logger, sink) = SetUp(LogLevel.Trace); + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("Person")); - using (logger.BeginScope("{FirstName}", "John")) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + var person = (StructureValue)sink.Writes[0].Properties["Person"]; + var firstName = (ScalarValue)person.Properties.Single(p => p.Name == "FirstName").Value; + var lastName = (ScalarValue)person.Properties.Single(p => p.Name == "LastName").Value; + Assert.Equal("John", firstName.Value); + Assert.Equal("Smith", lastName.Value); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("FirstName")); - } + [Fact] + public void BeginScopeDoesNotModifyKeyWhenDestructurerIsNotUsedInMessageTemplate() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void BeginScopeDoesNotModifyKeyWhenDestructurerIsNotUsedInDictionary() + using (logger.BeginScope("{FirstName}", "John")) { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + } - using (logger.BeginScope(new Dictionary { { "FirstName", "John"}})) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("FirstName")); + } - Assert.Equal(1, sink.Writes.Count); - Assert.True(sink.Writes[0].Properties.ContainsKey("FirstName")); - } + [Fact] + public void BeginScopeDoesNotModifyKeyWhenDestructurerIsNotUsedInDictionary() + { + var (logger, sink) = SetUp(LogLevel.Trace); - [Fact] - public void NamedScopesAreCaptured() + using (logger.BeginScope(new Dictionary { { "FirstName", "John"}})) { - var (logger, sink) = SetUp(LogLevel.Trace); + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); + } - using (logger.BeginScope("Outer")) - using (logger.BeginScope("Inner")) - { - logger.Log(LogLevel.Information, 0, TestMessage, null, null); - } + Assert.Single(sink.Writes); + Assert.True(sink.Writes[0].Properties.ContainsKey("FirstName")); + } - Assert.Equal(1, sink.Writes.Count); + [Fact] + public void NamedScopesAreCaptured() + { + var (logger, sink) = SetUp(LogLevel.Trace); - Assert.True(sink.Writes[0].Properties.TryGetValue(SerilogLoggerProvider.ScopePropertyName, out var scopeValue)); - var sequence = Assert.IsType(scopeValue); - var items = sequence.Elements.Select(e => Assert.IsType(e).Value).Cast().ToArray(); - Assert.Equal(2, items.Length); - Assert.Equal("Outer", items[0]); - Assert.Equal("Inner", items[1]); + using (logger.BeginScope("Outer")) + using (logger.BeginScope("Inner")) + { + logger.Log(LogLevel.Information, 0, TestMessage, null!, null!); } - class FoodScope : IEnumerable> - { - readonly string _name; + Assert.Single(sink.Writes); - public FoodScope(string name) - { - _name = name; - } + Assert.True(sink.Writes[0].Properties.TryGetValue(SerilogLoggerProvider.ScopePropertyName, out var scopeValue)); + var sequence = Assert.IsType(scopeValue); + var items = sequence.Elements.Select(e => Assert.IsType(e).Value).Cast().ToArray(); + Assert.Equal(2, items.Length); + Assert.Equal("Outer", items[0]); + Assert.Equal("Inner", items[1]); + } - public IEnumerator> GetEnumerator() - { - yield return new KeyValuePair("Name", _name); - } + class FoodScope : IEnumerable> + { + readonly string _name; - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + public FoodScope(string name) + { + _name = name; } - class LuckyScope : IEnumerable> + public IEnumerator> GetEnumerator() { - readonly int _luckyNumber; + yield return new KeyValuePair("Name", _name); + } - public LuckyScope(int luckyNumber) - { - _luckyNumber = luckyNumber; - } + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } - public IEnumerator> GetEnumerator() - { - yield return new KeyValuePair("LuckyNumber", _luckyNumber); - } + class LuckyScope : IEnumerable> + { + readonly int _luckyNumber; - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + public LuckyScope(int luckyNumber) + { + _luckyNumber = luckyNumber; } - class Person + public IEnumerator> GetEnumerator() { - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public string FirstName { get; set; } - - // ReSharper disable once UnusedAutoPropertyAccessor.Local - public string LastName { get; set; } + yield return new KeyValuePair("LuckyNumber", _luckyNumber); } - [Theory] - [InlineData(1)] - [InlineData(10)] - [InlineData(48)] - [InlineData(100)] - public void LowAndHighNumberedEventIdsAreMapped(int id) + IEnumerator IEnumerable.GetEnumerator() { - var orig = new EventId(id, "test"); - var mapped = SerilogLogger.CreateEventIdProperty(orig); - var value = Assert.IsType(mapped.Value); - Assert.Equal(2, value.Properties.Count); - var idValue = value.Properties.Single(p => p.Name == "Id").Value; - var scalar = Assert.IsType(idValue); - Assert.Equal(id, scalar.Value); + return GetEnumerator(); } + } - [Fact] - public void MismatchedMessageTemplateParameterCountIsHandled() - { - var (logger, sink) = SetUp(LogLevel.Trace); + class Person + { + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public string? FirstName { get; set; } - logger.LogInformation("Some test message with {Two} {Properties}", "OneProperty"); + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public string? LastName { get; set; } + } - Assert.Equal(0, sink.Writes.Count); - } + [Theory] + [InlineData(1)] + [InlineData(10)] + [InlineData(48)] + [InlineData(100)] + public void LowAndHighNumberedEventIdsAreMapped(int id) + { + var orig = new EventId(id, "test"); + var mapped = SerilogLogger.CreateEventIdProperty(orig); + var value = Assert.IsType(mapped.Value); + Assert.Equal(2, value.Properties.Count); + var idValue = value.Properties.Single(p => p.Name == "Id").Value; + var scalar = Assert.IsType(idValue); + Assert.Equal(id, scalar.Value); + } + + [Fact] + public void MismatchedMessageTemplateParameterCountIsHandled() + { + var (logger, sink) = SetUp(LogLevel.Trace); + + logger.LogInformation("Some test message with {Two} {Properties}", "OneProperty"); + + Assert.Empty(sink.Writes); } } diff --git a/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs b/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs index d833c0c..7c194d1 100644 --- a/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs +++ b/test/Serilog.Extensions.Logging.Tests/Support/DisposeTrackingLogger.cs @@ -1,354 +1,351 @@ -using System; -using System.Collections.Generic; using Serilog.Core; using Serilog.Events; -namespace Serilog.Extensions.Logging.Tests.Support +namespace Serilog.Extensions.Logging.Tests.Support; + +public class DisposeTrackingLogger : ILogger, IDisposable { - public class DisposeTrackingLogger : ILogger, IDisposable - { - public bool IsDisposed { get; set; } - - public ILogger ForContext(ILogEventEnricher enricher) - { - return new LoggerConfiguration().CreateLogger(); - } - - public ILogger ForContext(IEnumerable enrichers) - { - return new LoggerConfiguration().CreateLogger(); - } - - public ILogger ForContext(string propertyName, object value, bool destructureObjects = false) - { - return new LoggerConfiguration().CreateLogger(); - } - - public ILogger ForContext() - { - return new LoggerConfiguration().CreateLogger(); - } - - public ILogger ForContext(Type source) - { - return new LoggerConfiguration().CreateLogger(); - } - - public void Write(LogEvent logEvent) - { - } - - public void Write(LogEventLevel level, string messageTemplate) - { - } - - public void Write(LogEventLevel level, string messageTemplate, T propertyValue) - { - } - - public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Write(LogEventLevel level, string messageTemplate, params object[] propertyValues) - { - } - - public void Write(LogEventLevel level, Exception exception, string messageTemplate) - { - } - - public void Write(LogEventLevel level, Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0, - T1 propertyValue1) - { - } - - public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0, - T1 propertyValue1, T2 propertyValue2) - { - } - - public void Write(LogEventLevel level, Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public bool IsEnabled(LogEventLevel level) - { - return false; - } - - public void Verbose(string messageTemplate) - { - } - - public void Verbose(string messageTemplate, T propertyValue) - { - } - - public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Verbose(string messageTemplate, params object[] propertyValues) - { - } - - public void Verbose(Exception exception, string messageTemplate) - { - } - - public void Verbose(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Verbose(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public void Debug(string messageTemplate) - { - } - - public void Debug(string messageTemplate, T propertyValue) - { - } - - public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Debug(string messageTemplate, params object[] propertyValues) - { - } - - public void Debug(Exception exception, string messageTemplate) - { - } - - public void Debug(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Debug(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public void Information(string messageTemplate) - { - } - - public void Information(string messageTemplate, T propertyValue) - { - } - - public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Information(string messageTemplate, params object[] propertyValues) - { - } - - public void Information(Exception exception, string messageTemplate) - { - } - - public void Information(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Information(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public void Warning(string messageTemplate) - { - } - - public void Warning(string messageTemplate, T propertyValue) - { - } - - public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Warning(string messageTemplate, params object[] propertyValues) - { - } - - public void Warning(Exception exception, string messageTemplate) - { - } - - public void Warning(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Warning(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public void Error(string messageTemplate) - { - } - - public void Error(string messageTemplate, T propertyValue) - { - } - - public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Error(string messageTemplate, params object[] propertyValues) - { - } - - public void Error(Exception exception, string messageTemplate) - { - } - - public void Error(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Error(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public void Fatal(string messageTemplate) - { - } - - public void Fatal(string messageTemplate, T propertyValue) - { - } - - public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) - { - } - - public void Fatal(string messageTemplate, params object[] propertyValues) - { - } - - public void Fatal(Exception exception, string messageTemplate) - { - } - - public void Fatal(Exception exception, string messageTemplate, T propertyValue) - { - } - - public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) - { - } - - public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, - T2 propertyValue2) - { - } - - public void Fatal(Exception exception, string messageTemplate, params object[] propertyValues) - { - } - - public bool BindMessageTemplate(string messageTemplate, object[] propertyValues, out MessageTemplate parsedTemplate, - out IEnumerable boundProperties) - { - parsedTemplate = null; - boundProperties = null; - return false; - } - - public bool BindProperty(string propertyName, object value, bool destructureObjects, out LogEventProperty property) - { - property = null; - return false; - } - - public void Dispose() - { - IsDisposed = true; - } + public bool IsDisposed { get; set; } + + public ILogger ForContext(ILogEventEnricher enricher) + { + return new LoggerConfiguration().CreateLogger(); + } + + public ILogger ForContext(IEnumerable enrichers) + { + return new LoggerConfiguration().CreateLogger(); + } + + public ILogger ForContext(string propertyName, object value, bool destructureObjects = false) + { + return new LoggerConfiguration().CreateLogger(); + } + + public ILogger ForContext() + { + return new LoggerConfiguration().CreateLogger(); + } + + public ILogger ForContext(Type source) + { + return new LoggerConfiguration().CreateLogger(); + } + + public void Write(LogEvent logEvent) + { + } + + public void Write(LogEventLevel level, string messageTemplate) + { + } + + public void Write(LogEventLevel level, string messageTemplate, T propertyValue) + { + } + + public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Write(LogEventLevel level, string messageTemplate, params object[] propertyValues) + { + } + + public void Write(LogEventLevel level, Exception exception, string messageTemplate) + { + } + + public void Write(LogEventLevel level, Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0, + T1 propertyValue1) + { + } + + public void Write(LogEventLevel level, Exception exception, string messageTemplate, T0 propertyValue0, + T1 propertyValue1, T2 propertyValue2) + { + } + + public void Write(LogEventLevel level, Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public bool IsEnabled(LogEventLevel level) + { + return false; + } + + public void Verbose(string messageTemplate) + { + } + + public void Verbose(string messageTemplate, T propertyValue) + { + } + + public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Verbose(string messageTemplate, params object[] propertyValues) + { + } + + public void Verbose(Exception exception, string messageTemplate) + { + } + + public void Verbose(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Verbose(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Verbose(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public void Debug(string messageTemplate) + { + } + + public void Debug(string messageTemplate, T propertyValue) + { + } + + public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Debug(string messageTemplate, params object[] propertyValues) + { + } + + public void Debug(Exception exception, string messageTemplate) + { + } + + public void Debug(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Debug(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Debug(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public void Information(string messageTemplate) + { + } + + public void Information(string messageTemplate, T propertyValue) + { + } + + public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Information(string messageTemplate, params object[] propertyValues) + { + } + + public void Information(Exception exception, string messageTemplate) + { + } + + public void Information(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Information(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Information(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public void Warning(string messageTemplate) + { + } + + public void Warning(string messageTemplate, T propertyValue) + { + } + + public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Warning(string messageTemplate, params object[] propertyValues) + { + } + + public void Warning(Exception exception, string messageTemplate) + { + } + + public void Warning(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Warning(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Warning(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public void Error(string messageTemplate) + { + } + + public void Error(string messageTemplate, T propertyValue) + { + } + + public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Error(string messageTemplate, params object[] propertyValues) + { + } + + public void Error(Exception exception, string messageTemplate) + { + } + + public void Error(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Error(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Error(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public void Fatal(string messageTemplate) + { + } + + public void Fatal(string messageTemplate, T propertyValue) + { + } + + public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2) + { + } + + public void Fatal(string messageTemplate, params object[] propertyValues) + { + } + + public void Fatal(Exception exception, string messageTemplate) + { + } + + public void Fatal(Exception exception, string messageTemplate, T propertyValue) + { + } + + public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1) + { + } + + public void Fatal(Exception exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1, + T2 propertyValue2) + { + } + + public void Fatal(Exception exception, string messageTemplate, params object[] propertyValues) + { + } + + public bool BindMessageTemplate(string messageTemplate, object[] propertyValues, out MessageTemplate? parsedTemplate, + out IEnumerable? boundProperties) + { + parsedTemplate = null; + boundProperties = null; + return false; + } + + public bool BindProperty(string propertyName, object value, bool destructureObjects, out LogEventProperty? property) + { + property = null; + return false; + } + + public void Dispose() + { + IsDisposed = true; } } diff --git a/test/Serilog.Extensions.Logging.Tests/Support/ExtensionsProvider.cs b/test/Serilog.Extensions.Logging.Tests/Support/ExtensionsProvider.cs index 583293c..1fc2bb0 100644 --- a/test/Serilog.Extensions.Logging.Tests/Support/ExtensionsProvider.cs +++ b/test/Serilog.Extensions.Logging.Tests/Support/ExtensionsProvider.cs @@ -1,45 +1,41 @@ // 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; -using System.Collections.Generic; using Microsoft.Extensions.Logging; -using Serilog.Events; -namespace Serilog.Extensions.Logging.Tests.Support +namespace Serilog.Extensions.Logging.Tests.Support; + +public class ExtensionsProvider : ILoggerProvider, Microsoft.Extensions.Logging.ILogger { - public class ExtensionsProvider : ILoggerProvider, Microsoft.Extensions.Logging.ILogger + private readonly LogLevel enabledLevel; + public List<(LogLevel logLevel, EventId eventId, object? state, Exception exception, string message)> Writes { get; set; } = new(); + + public ExtensionsProvider(LogLevel enabledLevel) + { + this.enabledLevel = enabledLevel; + } + + public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) + { + return this; + } + + public IDisposable BeginScope(TState state) + { + return this; + } + + public bool IsEnabled(LogLevel logLevel) + { + return enabledLevel <= logLevel; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + Writes.Add((logLevel, eventId, state, exception, formatter(state, exception))); + } + + public void Dispose() { - private readonly LogLevel enabledLevel; - public List<(LogLevel logLevel, EventId eventId, object state, Exception exception, string message)> Writes { get; set; } = new List<(LogLevel logLevel, EventId eventId, object state, Exception exception, string message)>(); - - public ExtensionsProvider(LogLevel enabledLevel) - { - this.enabledLevel = enabledLevel; - } - - public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName) - { - return this; - } - - public IDisposable BeginScope(TState state) - { - return this; - } - - public bool IsEnabled(LogLevel logLevel) - { - return enabledLevel <= logLevel; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - Writes.Add((logLevel, eventId, state, exception, formatter(state, exception))); - } - - public void Dispose() - { - } } -} \ No newline at end of file +} diff --git a/test/Serilog.Extensions.Logging.Tests/Support/SerilogSink.cs b/test/Serilog.Extensions.Logging.Tests/Support/SerilogSink.cs index cd7d5d7..d26aac5 100644 --- a/test/Serilog.Extensions.Logging.Tests/Support/SerilogSink.cs +++ b/test/Serilog.Extensions.Logging.Tests/Support/SerilogSink.cs @@ -1,19 +1,17 @@ -// 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.Collections.Generic; using Serilog.Core; using Serilog.Events; -namespace Serilog.Extensions.Logging.Tests.Support +namespace Serilog.Extensions.Logging.Tests.Support; + +public class SerilogSink : ILogEventSink { - public class SerilogSink : ILogEventSink - { - public List Writes { get; set; } = new List(); + public List Writes { get; set; } = new(); - public void Emit(LogEvent logEvent) - { - Writes.Add(logEvent); - } + public void Emit(LogEvent logEvent) + { + Writes.Add(logEvent); } -} \ No newline at end of file +}