Skip to content

Commit

Permalink
Merge pull request #222 from nblumhardt/v7
Browse files Browse the repository at this point in the history
v7 - pin to `Microsoft.Extensions.Logging` v7
  • Loading branch information
nblumhardt authored May 4, 2023
2 parents 9765013 + 5ba09d1 commit b524ab6
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 174 deletions.
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

0 comments on commit b524ab6

Please sign in to comment.