Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save chrisfcarroll/ee200fa90c816a449f60a587e455cf3e to your computer and use it in GitHub Desktop.

Select an option

Save chrisfcarroll/ee200fa90c816a449f60a587e455cf3e to your computer and use it in GitHub Desktop.
SerilogSourceContextShortName - Abbreviate "Well.Known.Long.Namespace.And.Class" to "WellKnown:Class" in your log lines
"Serilog": {
"Using": [ "Serilog.Sinks.File","Serilog.Sinks.Console"],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Ljmu": "Verbose",
"DbsChecksStaging": "Verbose",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.EntityFrameworkCore": "Information",
"Microsoft.EntityFrameworkCore.Database": "Information",
"Microsoft.EntityFrameworkCore.Database.Connection": "Information",
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
"Microsoft.EntityFrameworkCore.ChangeTracking": "Warning",
"System.Net.Http.HttpClient": "Information",
"System": "Warning",
"System.Net": "Error"
}
},
"WriteTo": [
{
"Name": "File",
"Args": {
"Path": "../logs/log-Application-Name-%COMPUTERNAME%-.log",
"rollingInterval": "Day",
"retainedFileCountLimit":90,
"outputTemplate": "[{Timestamp:HH:mm:ss.f} {Level:u3} {ContextShortName}] {Message:lj} {Id} {TraceId}{NewLine}{Exception}"
}
},
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss.f} {Level:u3} {ContextShortName}] {Message:lj} {Id} {TraceId}{NewLine}{Exception}"
}
}
]
}
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
namespace PlatformExtensions;
public static class SerilogSourceContextShortName
{
public static LoggerConfiguration WithSourceContextShortName(this LoggerEnrichmentConfiguration enrich)
{
_ = enrich ?? throw new ArgumentNullException(nameof(enrich));
return enrich.With<SourceContextShortNameEnricher>();
}
}
/// <summary>
/// A Serilog enricher that adds a "ContextShortName" property to log events.
/// The <c>ContextShortName</c> is often just the <see cref="System.Type.Name"/> of
/// the class that is logging, without its namespace, but
/// <list type="number">
/// <item>Generic type parameters are removed and</item>
/// <item>Your favourite namespaces can be preserved in abbreviated form, e.g.:
/// <list type="bullet">
/// <item>RequestLoggingMiddleware --> "Request:"</item>
/// <item>Microsoft.AspNetCore. --> "AspNet:"</item>
/// <item>Microsoft.EntityFrameworkCore. --> "MS.EF:"</item>
/// <item>Microsoft. --> "MS:"</item>
/// <item>System.Net.Http.HttpClient --> "Http:"</item>
/// <item>System --> ""</item>
/// </list>
/// </item>
/// </list>
/// </summary>
class SourceContextShortNameEnricher : ILogEventEnricher
{
public const string PropertyName = "ContextShortName";
/// <summary>
/// Adds the <c>ContextShortName</c> property to the log event.
/// </summary>
/// <seealso cref="PropertyName"/>
/// <seealso cref="SourceContextShortNameEnricher"/>
/// <param name="logEvent"></param>
/// <param name="propertyFactory"></param>
/// <remarks>
/// For fine-tuning logging of MS and .Net classes consider something like this as a starting point:
/// <c>
/// "Serilog": {
/// "Using": [ "Serilog.Sinks.File","Serilog.Sinks.Console"],
/// "MinimumLevel": {
/// "Default": "Information",
/// "Override": {
/// "MyCode.BeingDevelopedNow": "Verbose",
/// "MyCode.QuiteStable": "Information",
/// "Microsoft": "Warning",
/// "Microsoft.Hosting.Lifetime": "Information",
/// "Microsoft.EntityFrameworkCore": "Information",
/// "Microsoft.EntityFrameworkCore.Database": "Information",
/// "Microsoft.EntityFrameworkCore.Database.Connection": "Information",
/// "Microsoft.EntityFrameworkCore.Database.Command": "Warning",
/// "Microsoft.EntityFrameworkCore.ChangeTracking": "Warning",
/// "System.Net.Http.HttpClient": "Information",
/// "System": "Warning",
/// "System.Net": "Error"
/// }
/// },
/// "WriteTo": [
/// {
/// "Name": "File",
/// "Args": {
/// "Path": "../logs/log-DbsChecksStaging-%COMPUTERNAME%-.log",
/// "rollingInterval": "Day",
/// "retainedFileCountLimit":90,
/// "outputTemplate": "[{Timestamp:HH:mm:ss.f} {Level:u3} {ContextShortName}] {Message:lj} {Id} {TraceId}{NewLine}{Exception}"
/// }
/// },
/// {
/// "Name": "Console",
/// "Args": {
/// "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
/// "outputTemplate": "[{Timestamp:HH:mm:ss.f} {Level:u3} {ContextShortName}] {Message:lj} {Id} {TraceId}{NewLine}{Exception}"
/// }
/// }
/// ]
/// },
/// </c>
/// </remarks>
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (logEvent is null || propertyFactory is null) return;
// ReSharper restore ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (logEvent.Properties.TryGetValue(Serilog.Core.Constants.SourceContextPropertyName, out var value))
{
var shortTypeNameWithoutGenerics = value.ToString()
.Split('`').First()
.Replace("RequestLoggingMiddleware", "Request:")
.Replace("Microsoft.AspNetCore.", "AspNet:")
.Replace("Microsoft.EntityFrameworkCore.Database", "MS.EF.Db:")
.Replace("Microsoft.EntityFrameworkCore.", "MS.EF:")
.Replace("Microsoft.", "MS:")
.Replace("System.Net.Http.HttpClient", "Http:")
.Replace("System.", "")
.Replace("\"","")
;
var source =
shortTypeNameWithoutGenerics.Substring(0, shortTypeNameWithoutGenerics.LastIndexOf(':') + 1)
+
shortTypeNameWithoutGenerics.Substring(shortTypeNameWithoutGenerics.LastIndexOf('.') + 1);
;
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(PropertyName, source));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment