Last active
April 23, 2026 15:17
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| "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}" | |
| } | |
| } | |
| ] | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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