Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v7 - pin to Microsoft.Extensions.Logging v7 #222

Merged
merged 6 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if(Test-Path .\artifacts) {

$branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL];
$revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL];
$suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)))-$revision"}[$branch -eq "master" -and $revision -ne "local"]
$suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)))-$revision"}[$branch -eq "main" -and $revision -ne "local"]

echo "build: Version suffix is $suffix"

Expand Down
3 changes: 1 addition & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)assets/Serilog.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
</Project>
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Serilog.Extensions.Logging [![Build status](https://ci.appveyor.com/api/projects/status/865nohxfiq1rnby0/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog-framework-logging/history) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Extensions.Logging.svg?style=flat)](https://www.nuget.org/packages/Serilog.Extensions.Logging/)
# Serilog.Extensions.Logging [![Build status](https://ci.appveyor.com/api/projects/status/865nohxfiq1rnby0/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog-framework-logging/history) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Extensions.Logging.svg?style=flat)](https://www.nuget.org/packages/Serilog.Extensions.Logging/)

A Serilog provider for [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging), the logging subsystem used by ASP.NET Core.

Expand All @@ -16,9 +16,9 @@ The package implements `AddSerilog()` on `ILoggingBuilder` and `ILoggerFactory`

**First**, install the _Serilog.Extensions.Logging_ [NuGet package](https://www.nuget.org/packages/Serilog.Extensions.Logging) into your web or console app. You will need a way to view the log messages - _Serilog.Sinks.Console_ writes these to the console.

```powershell
Install-Package Serilog.Extensions.Logging -DependencyVersion Highest
Install-Package Serilog.Sinks.Console
```sh
dotnet add package Serilog.Extensions.Logging
dotnet add package Serilog.Sinks.Console
```

**Next**, in your application's `Startup` method, configure Serilog first:
Expand All @@ -34,7 +34,7 @@ public class Startup
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();

// Other startup code
```

Expand All @@ -46,7 +46,7 @@ call `AddSerilog()` on the provided `loggingBuilder`.
{
services.AddLogging(loggingBuilder =>
loggingBuilder.AddSerilog(dispose: true));

// Other services ...
}
```
Expand All @@ -60,7 +60,7 @@ call `AddSerilog()` on the provided `loggingBuilder`.
IApplicationLifetime appLifetime)
{
loggerfactory.AddSerilog();

// Ensure any buffered events are sent at shutdown
appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
```
Expand All @@ -69,7 +69,7 @@ That's it! With the level bumped up a little you should see log output like:

```
[22:14:44.646 DBG] RouteCollection.RouteAsync
Routes:
Routes:
Microsoft.AspNet.Mvc.Routing.AttributeRoute
{controller=Home}/{action=Index}/{id?}
Handled? True
Expand Down Expand Up @@ -144,6 +144,10 @@ using (_logger.BeginScope(scopeProps) {
// }
```

### Versioning

This package tracks the versioning and target framework support of its [_Microsoft.Extensions.Logging_](https://nuget.org/packages/Microsoft.Extensions.Logging) dependency.

### Credits

This package evolved from an earlier package _Microsoft.Framework.Logging.Serilog_ [provided by the ASP.NET team](https://github.com/aspnet/Logging/pull/182).
4 changes: 2 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ deploy:
secure: EN9f+XXE3fW+ebL4wxrIbafdtbNvRfddBN8UUixvctYh4qMBHzr1JdnM83QsM1zo
skip_symbols: true
on:
branch: /^(master|dev)$/
branch: /^(main|dev)$/
- provider: GitHub
auth_token:
secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX
artifact: /Serilog.*\.nupkg/
tag: v$(appveyor_build_version)
on:
branch: master
branch: main

107 changes: 49 additions & 58 deletions samples/Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,66 @@
using Serilog;
using Serilog.Extensions.Logging;

namespace Sample;
// Creating a `LoggerProviderCollection` lets Serilog optionally write
// events through other dynamically-added MEL ILoggerProviders.
var providers = new LoggerProviderCollection();

public class Program
{
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();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.WriteTo.Providers(providers)
.CreateLogger();

var services = new ServiceCollection();
var services = new ServiceCollection();

services.AddSingleton(providers);
services.AddSingleton<ILoggerFactory>(sc =>
{
var providerCollection = sc.GetService<LoggerProviderCollection>();
var factory = new SerilogLoggerFactory(null, true, providerCollection);
services.AddSingleton(providers);
services.AddSingleton<ILoggerFactory>(sc =>
{
var providerCollection = sc.GetService<LoggerProviderCollection>();
var factory = new SerilogLoggerFactory(null, true, providerCollection);

foreach (var provider in sc.GetServices<ILoggerProvider>())
factory.AddProvider(provider);
foreach (var provider in sc.GetServices<ILoggerProvider>())
factory.AddProvider(provider);

return factory;
});
return factory;
});

services.AddLogging(l => l.AddConsole());
services.AddLogging(l => l.AddConsole());

var serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();
var serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

var startTime = DateTimeOffset.UtcNow;
logger.LogInformation(1, "Started at {StartTime} and 0x{Hello:X} is hex of 42", startTime, 42);
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<object>(LogLevel.Critical, 0, null!, null, null!);
logger.LogError("Unexpected error", ex);
logger.LogWarning("Unexpected warning", ex);
}
try
{
throw new Exception("Boom!");
}
catch (Exception ex)
{
logger.LogCritical(ex, "Unexpected critical error starting application");
logger.Log(LogLevel.Critical, 0, "Unexpected critical error", ex, null!);
// This write should not log anything
logger.Log<object>(LogLevel.Critical, 0, null!, null, null!);
logger.LogError(ex, "Unexpected error");
logger.LogWarning(ex, "Unexpected warning");
}

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 });
}
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);
var endTime = DateTimeOffset.UtcNow;
logger.LogInformation(2, "Stopping at {StopTime}", endTime);

logger.LogInformation("Stopping");
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);
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();
}
}
serviceProvider.Dispose();
5 changes: 3 additions & 2 deletions samples/Sample/Sample.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<AssemblyName>Sample</AssemblyName>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
Expand All @@ -16,4 +17,4 @@
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
</ItemGroup>

</Project>
</Project>
2 changes: 2 additions & 0 deletions serilog-extensions-logging.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=stringified/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public MessageTemplate Parse(string messageTemplate)

// ReSharper disable once InconsistentlySynchronizedField
// ignored warning because this is by design
var result = (MessageTemplate)_templates[messageTemplate];
var result = (MessageTemplate?)_templates[messageTemplate];
if (result != null)
return result;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public static class LevelConvert
/// <summary>
/// Convert <paramref name="logLevel"/> to the equivalent Serilog <see cref="LogEventLevel"/>.
/// </summary>
/// <param name="logLevel">A Microsoft.Extensions.Logging <see cref="LogLevel"/>.</param>
/// <param name="logLevel">A Microsoft.Extensions.Logging <see cref="Microsoft.Extensions.Logging.LogLevel"/>.</param>
/// <returns>The Serilog equivalent of <paramref name="logLevel"/>.</returns>
/// <remarks>The <see cref="LogLevel.None"/> value has no Serilog equivalent. It is mapped to
/// <remarks>The <see cref="Microsoft.Extensions.Logging.LogLevel.None"/> value has no Serilog equivalent. It is mapped to
/// <see cref="LogEventLevel.Fatal"/> as the closest approximation, but this has entirely
/// different semantics.</remarks>
public static LogEventLevel ToSerilogLevel(LogLevel logLevel)
Expand All @@ -46,7 +46,7 @@ public static LogEventLevel ToSerilogLevel(LogLevel logLevel)
}

/// <summary>
/// Convert <paramref name="logEventLevel"/> to the equivalent Microsoft.Extensions.Logging <see cref="LogLevel"/>.
/// Convert <paramref name="logEventLevel"/> to the equivalent Microsoft.Extensions.Logging <see cref="Microsoft.Extensions.Logging.LogLevel"/>.
/// </summary>
/// <param name="logEventLevel">A Serilog <see cref="LogEventLevel"/>.</param>
/// <returns>The Microsoft.Extensions.Logging equivalent of <paramref name="logEventLevel"/>.</returns>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@

namespace Serilog.Extensions.Logging;

readonly struct SerilogLogValues : IReadOnlyList<KeyValuePair<string, object>>
readonly struct SerilogLogValues : IReadOnlyList<KeyValuePair<string, object?>>
{
// 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<string, LogEventPropertyValue> _properties;
private readonly KeyValuePair<string, object>[] _values;
readonly MessageTemplate _messageTemplate;
readonly IReadOnlyDictionary<string, LogEventPropertyValue> _properties;
readonly KeyValuePair<string, object?>[] _values;

public SerilogLogValues(MessageTemplate messageTemplate, IReadOnlyDictionary<string, LogEventPropertyValue> properties)
{
Expand All @@ -34,24 +34,24 @@ public SerilogLogValues(MessageTemplate messageTemplate, IReadOnlyDictionary<str
_properties = properties ?? throw new ArgumentNullException(nameof(properties));

// The array is needed because the IReadOnlyList<T> interface expects indexed access
_values = new KeyValuePair<string, object>[_properties.Count + 1];
_values = new KeyValuePair<string, object?>[_properties.Count + 1];
var i = 0;
foreach (var p in properties)
{
_values[i] = new KeyValuePair<string, object>(p.Key, (p.Value is ScalarValue sv) ? sv.Value : p.Value);
_values[i] = new KeyValuePair<string, object?>(p.Key, (p.Value is ScalarValue sv) ? sv.Value : p.Value);
++i;
}
_values[i] = new KeyValuePair<string, object>("{OriginalFormat}", _messageTemplate.Text);
_values[i] = new KeyValuePair<string, object?>("{OriginalFormat}", _messageTemplate.Text);
}

public KeyValuePair<string, object> this[int index]
public KeyValuePair<string, object?> this[int index]
{
get => _values[index];
}

public int Count => _properties.Count + 1;

public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => ((IEnumerable<KeyValuePair<string, object>>)_values).GetEnumerator();
public IEnumerator<KeyValuePair<string, object?>> GetEnumerator() => ((IEnumerable<KeyValuePair<string, object?>>)_values).GetEnumerator();

public override string ToString() => _messageTemplate.Render(_properties);

Expand Down
23 changes: 12 additions & 11 deletions src/Serilog.Extensions.Logging/Extensions/Logging/SerilogLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ public SerilogLogger(
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 ??= Serilog.Log.Logger.ForContext(new[] { provider });
_logger = logger ?? Serilog.Log.Logger.ForContext(new[] { provider });

if (name != null)
{
Expand All @@ -57,12 +56,12 @@ public bool IsEnabled(LogLevel logLevel)
return logLevel != LogLevel.None && _logger.IsEnabled(LevelConvert.ToSerilogLevel(logLevel));
}

public IDisposable BeginScope<TState>(TState state)
public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return _provider.BeginScope(state);
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (logLevel == LogLevel.None)
{
Expand All @@ -81,15 +80,15 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
}
catch (Exception ex)
{
SelfLog.WriteLine($"Failed to write event through {typeof(SerilogLogger).Name}: {ex}");
SelfLog.WriteLine($"Failed to write event through {nameof(SerilogLogger)}: {ex}");
}

// Do not swallow exceptions from here because Serilog takes care of them in case of WriteTo and throws them back to the caller in case of AuditTo.
if (evt != null)
_logger.Write(evt);
}

LogEvent PrepareWrite<TState>(LogEventLevel level, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
LogEvent PrepareWrite<TState>(LogEventLevel level, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
string? messageTemplate = null;

Expand Down Expand Up @@ -139,7 +138,9 @@ LogEvent PrepareWrite<TState>(LogEventLevel level, EventId eventId, TState state
propertyName = "State";
messageTemplate = "{State:l}";
}
else if (formatter != null)
// `formatter` was originally accepted as nullable, so despite the new annotation, this check should still
// be made.
else if (formatter != null!)
{
propertyName = "Message";
messageTemplate = "{Message:l}";
Expand All @@ -159,12 +160,12 @@ LogEvent PrepareWrite<TState>(LogEventLevel level, EventId eventId, TState state
return new LogEvent(DateTimeOffset.Now, level, exception, parsedTemplate, properties);
}

static object? AsLoggableValue<TState>(TState state, Func<TState, Exception, string> formatter)
static object? AsLoggableValue<TState>(TState state, Func<TState, Exception?, string>? formatter)
{
object? sobj = state;
object? stateObj = state;
if (formatter != null)
sobj = formatter(state, null!);
return sobj;
stateObj = formatter(state, null);
return stateObj;
}

internal static LogEventProperty CreateEventIdProperty(EventId eventId)
Expand Down
Loading