From c5d723d9922e02a3776b2f7fbfbc1a6064679feb Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Fri, 27 Dec 2024 14:54:45 +0100 Subject: [PATCH 1/5] Fix: remove visible --- .../CodeOfChaos.Extensions.AspNetCore.csproj | 4 ++-- .../CodeOfChaos.Extensions.EntityFrameworkCore.csproj | 6 +++--- .../CodeOfChaos.Extensions.Serilog.csproj | 4 ++-- src/CodeOfChaos.Extensions/CodeOfChaos.Extensions.csproj | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CodeOfChaos.Extensions.AspNetCore/CodeOfChaos.Extensions.AspNetCore.csproj b/src/CodeOfChaos.Extensions.AspNetCore/CodeOfChaos.Extensions.AspNetCore.csproj index 81f36a7..69a8db8 100644 --- a/src/CodeOfChaos.Extensions.AspNetCore/CodeOfChaos.Extensions.AspNetCore.csproj +++ b/src/CodeOfChaos.Extensions.AspNetCore/CodeOfChaos.Extensions.AspNetCore.csproj @@ -28,9 +28,9 @@ - + - + diff --git a/src/CodeOfChaos.Extensions.EntityFrameworkCore/CodeOfChaos.Extensions.EntityFrameworkCore.csproj b/src/CodeOfChaos.Extensions.EntityFrameworkCore/CodeOfChaos.Extensions.EntityFrameworkCore.csproj index 3300ca8..9536517 100644 --- a/src/CodeOfChaos.Extensions.EntityFrameworkCore/CodeOfChaos.Extensions.EntityFrameworkCore.csproj +++ b/src/CodeOfChaos.Extensions.EntityFrameworkCore/CodeOfChaos.Extensions.EntityFrameworkCore.csproj @@ -24,10 +24,10 @@ - + - + - + diff --git a/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj b/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj index 98654d5..8a3a9c2 100644 --- a/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj +++ b/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj @@ -27,8 +27,8 @@ - + - + diff --git a/src/CodeOfChaos.Extensions/CodeOfChaos.Extensions.csproj b/src/CodeOfChaos.Extensions/CodeOfChaos.Extensions.csproj index 278f0fe..f9248db 100644 --- a/src/CodeOfChaos.Extensions/CodeOfChaos.Extensions.csproj +++ b/src/CodeOfChaos.Extensions/CodeOfChaos.Extensions.csproj @@ -23,9 +23,9 @@ - + - + From fade4de6a727359f373fea9f0185d694f063334f Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Fri, 27 Dec 2024 14:56:39 +0100 Subject: [PATCH 2/5] Create ReaderWriterLockSlimExtensions.cs --- .../ReaderWriterLockSlimExtensions.cs | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/CodeOfChaos.Extensions/ReaderWriterLockSlimExtensions.cs diff --git a/src/CodeOfChaos.Extensions/ReaderWriterLockSlimExtensions.cs b/src/CodeOfChaos.Extensions/ReaderWriterLockSlimExtensions.cs new file mode 100644 index 0000000..57c1914 --- /dev/null +++ b/src/CodeOfChaos.Extensions/ReaderWriterLockSlimExtensions.cs @@ -0,0 +1,71 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +// ReSharper disable once CheckNamespace +namespace System.Threading; +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public static class ReaderWriterLockSlimExtensions { + + // ----------------------------------------------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------------------------------------------- + public static IDisposable Read(this ReaderWriterLockSlim rwLock) { + rwLock.EnterReadLock(); + return new ReadReleaser(rwLock); + } + + public static IDisposable Write(this ReaderWriterLockSlim rwLock) { + rwLock.EnterWriteLock(); + return new WriteReleaser(rwLock); + } + + public static UpgradableReadReleaser UpgradeableRead(this ReaderWriterLockSlim rwLock) { + rwLock.EnterUpgradeableReadLock(); + return new UpgradableReadReleaser(rwLock); + } + + public static IDisposable? TryRead(this ReaderWriterLockSlim rwLock, int millisecondsTimeout, Action? onTimeout = null) { + if (rwLock.TryEnterReadLock(millisecondsTimeout)) { + return new ReadReleaser(rwLock); + } + + onTimeout?.Invoke();// Handle timeout scenario + return null; + } + + public static IDisposable? TryWrite(this ReaderWriterLockSlim rwLock, int millisecondsTimeout, Action? onTimeout = null) { + if (rwLock.TryEnterWriteLock(millisecondsTimeout)) { + return new WriteReleaser(rwLock); + } + + onTimeout?.Invoke();// Handle timeout scenario + return null; + } + + public static IDisposable? TryUpgradeableRead(this ReaderWriterLockSlim rwLock, int millisecondsTimeout, Action? onTimeout = null) { + if (rwLock.TryEnterUpgradeableReadLock(millisecondsTimeout)) { + return new UpgradableReadReleaser(rwLock); + } + + onTimeout?.Invoke();// Handle timeout scenario + return null; + } + + // ----------------------------------------------------------------------------------------------------------------- + // Helper Class + // ----------------------------------------------------------------------------------------------------------------- + private readonly struct ReadReleaser(ReaderWriterLockSlim rwLock) : IDisposable { + public void Dispose() => rwLock.ExitReadLock(); + } + + private readonly struct WriteReleaser(ReaderWriterLockSlim rwLock) : IDisposable { + public void Dispose() => rwLock.ExitWriteLock(); + } + + public readonly struct UpgradableReadReleaser(ReaderWriterLockSlim rwLock) : IDisposable { + public ReaderWriterLockSlim Lock { get; } = rwLock; + public void Dispose() => Lock.ExitUpgradeableReadLock(); + } +} From de6003336b08cd64719b583e09b681bce485c81d Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Fri, 27 Dec 2024 15:19:32 +0100 Subject: [PATCH 3/5] Feat: Common Console Config --- .../CodeOfChaos.Extensions.Serilog.csproj | 3 + .../ConsoleFormats.cs | 13 +++++ .../ConsoleThemes.cs | 32 +++++++++++ .../Enrichers/PaddedSectionEnricher.cs | 31 +++++++++++ .../LoggerConfigurationExtensions.cs | 55 +++++++++++++++++++ .../LoggerExtensions.cs | 3 + 6 files changed, 137 insertions(+) create mode 100644 src/CodeOfChaos.Extensions.Serilog/ConsoleFormats.cs create mode 100644 src/CodeOfChaos.Extensions.Serilog/ConsoleThemes.cs create mode 100644 src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs create mode 100644 src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs diff --git a/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj b/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj index 8a3a9c2..ecc2cd8 100644 --- a/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj +++ b/src/CodeOfChaos.Extensions.Serilog/CodeOfChaos.Extensions.Serilog.csproj @@ -22,8 +22,11 @@ + + + diff --git a/src/CodeOfChaos.Extensions.Serilog/ConsoleFormats.cs b/src/CodeOfChaos.Extensions.Serilog/ConsoleFormats.cs new file mode 100644 index 0000000..0ddd805 --- /dev/null +++ b/src/CodeOfChaos.Extensions.Serilog/ConsoleFormats.cs @@ -0,0 +1,13 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +namespace CodeOfChaos.Extensions.Serilog; + +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public static class ConsoleOutputTemplates { + public const string Default = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"; + public const string DefaultShort = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}"; + public const string AnnaSasDevServer = "[{Timestamp:HH:mm:ss} {Level:u3} {Section,-8}] {Message:lj}{NewLine}"; +} diff --git a/src/CodeOfChaos.Extensions.Serilog/ConsoleThemes.cs b/src/CodeOfChaos.Extensions.Serilog/ConsoleThemes.cs new file mode 100644 index 0000000..2ebda27 --- /dev/null +++ b/src/CodeOfChaos.Extensions.Serilog/ConsoleThemes.cs @@ -0,0 +1,32 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +using Serilog.Sinks.SystemConsole.Themes; +using CodeOfChaos.Ansi; + +namespace CodeOfChaos.Extensions.Serilog; + +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public static class ConsoleThemes { + public static readonly AnsiConsoleTheme AnnaSasDevTheme = new( + new Dictionary { + [ConsoleThemeStyle.Text] = AnsiColor.AsFore("white"), + [ConsoleThemeStyle.SecondaryText] = AnsiColor.AsFore("silver"), + [ConsoleThemeStyle.TertiaryText] = AnsiColor.AsFore("gray"), + [ConsoleThemeStyle.Invalid] = AnsiColor.AsFore("gold"), + [ConsoleThemeStyle.Null] = AnsiColor.AsFore("coral"), + [ConsoleThemeStyle.Name] = AnsiColor.AsFore("slategray"), + [ConsoleThemeStyle.String] = AnsiColor.AsFore("aqua"), + [ConsoleThemeStyle.Number] = AnsiColor.AsFore("mediumpurple"), + [ConsoleThemeStyle.Boolean] = AnsiColor.AsFore("coral"), + [ConsoleThemeStyle.Scalar] = AnsiColor.AsFore("coral"), + [ConsoleThemeStyle.LevelVerbose] = AnsiColor.AsFore("silver"), + [ConsoleThemeStyle.LevelDebug] = AnsiColor.AsFore("rose"), + [ConsoleThemeStyle.LevelInformation] = AnsiColor.AsFore("white"), + [ConsoleThemeStyle.LevelWarning] = AnsiColor.AsFore("gold"), + [ConsoleThemeStyle.LevelError] = AnsiColor.AsFore("white") + AnsiColor.AsBack("rose"), + [ConsoleThemeStyle.LevelFatal] = AnsiColor.AsFore("white") + AnsiColor.AsBack("maroon") + }); +} diff --git a/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs b/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs new file mode 100644 index 0000000..075e1d7 --- /dev/null +++ b/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs @@ -0,0 +1,31 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +using Serilog.Core; +using Serilog.Events; + +namespace CodeOfChaos.Extensions.Serilog.Enrichers; +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public class PaddedSectionEnricher : ILogEventEnricher { + public const int MaxLength = 8; + + // ----------------------------------------------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------------------------------------------- + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { + if (!logEvent.Properties.TryGetValue("Section", out LogEventPropertyValue? sectionProperty)) { + // If "Section" is not defined, fallback to default value + sectionProperty = new ScalarValue(string.Empty); + } + + string sectionValue = sectionProperty.ToString().Trim('"'); // Remove quotes and trim + + // Left-pad as required to a max of 8 characters + string paddedSection = sectionValue.PadLeft(MaxLength)[..MaxLength]; + + LogEventProperty paddedProperty = propertyFactory.CreateProperty("Section", paddedSection); + logEvent.AddOrUpdateProperty(paddedProperty); + } +} diff --git a/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs b/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs new file mode 100644 index 0000000..357918d --- /dev/null +++ b/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +using CodeOfChaos.Extensions.Serilog.Enrichers; +using Serilog; +using Serilog.Core; +using Serilog.Events; +using Serilog.Sinks.SystemConsole.Themes; + +namespace CodeOfChaos.Extensions.Serilog; + +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public static class LoggerConfigurationExtensions { + public static LoggerConfiguration WriteToAsyncConsole( + this LoggerConfiguration loggerConfiguration, + LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose, + string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}", + IFormatProvider? formatProvider = null, + LoggingLevelSwitch? levelSwitch = null, + LogEventLevel? standardErrorFromLevel = null, + ConsoleTheme? theme = null, + bool applyThemeToRedirectedOutput = false, + object? syncRoot = null + ) { + loggerConfiguration.WriteTo.Async(lsc => lsc.Console( + restrictedToMinimumLevel, + outputTemplate, + formatProvider, + levelSwitch, + standardErrorFromLevel, + theme, + applyThemeToRedirectedOutput, + syncRoot + )); + return loggerConfiguration; + } + + public static LoggerConfiguration WithPaddedSectionEnricher(this LoggerConfiguration loggerConfiguration) { + return loggerConfiguration.Enrich.With(); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Opinionated configurations + // ----------------------------------------------------------------------------------------------------------------- + public static LoggerConfiguration AsAnnaSasDevServerConsole(this LoggerConfiguration loggerConfiguration) { + return loggerConfiguration + .WithPaddedSectionEnricher() + .WriteToAsyncConsole( + outputTemplate: ConsoleOutputTemplates.AnnaSasDevServer, + theme: ConsoleThemes.AnnaSasDevTheme + ); + } +} diff --git a/src/CodeOfChaos.Extensions.Serilog/LoggerExtensions.cs b/src/CodeOfChaos.Extensions.Serilog/LoggerExtensions.cs index 004c20d..79fe674 100644 --- a/src/CodeOfChaos.Extensions.Serilog/LoggerExtensions.cs +++ b/src/CodeOfChaos.Extensions.Serilog/LoggerExtensions.cs @@ -104,4 +104,7 @@ public static void ExitFatal(this ILogger logger, int exitCode, string messageTe logger.Fatal(messageTemplate, propertyValues); throw new ExitApplicationException(exitCode, messageTemplate); } + + + public static ILogger ForSectionProperty(this ILogger logger, string sectionName) => logger.ForContext("Section", sectionName); } From c3e9548e86c14dee5d7ce2fcfdcd26292390465a Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Fri, 27 Dec 2024 15:23:24 +0100 Subject: [PATCH 4/5] Feat: TruncateSourceContextEnricher --- .../Enrichers/PaddedSectionEnricher.cs | 8 ++++- .../TruncateSourceContextEnricher.cs | 34 +++++++++++++++++++ .../LoggerConfigurationExtensions.cs | 8 +++-- 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/CodeOfChaos.Extensions.Serilog/Enrichers/TruncateSourceContextEnricher.cs diff --git a/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs b/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs index 075e1d7..87c484f 100644 --- a/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs +++ b/src/CodeOfChaos.Extensions.Serilog/Enrichers/PaddedSectionEnricher.cs @@ -9,7 +9,13 @@ namespace CodeOfChaos.Extensions.Serilog.Enrichers; // Code // --------------------------------------------------------------------------------------------------------------------- public class PaddedSectionEnricher : ILogEventEnricher { - public const int MaxLength = 8; + public int MaxLength { get; } = 8; + + // ----------------------------------------------------------------------------------------------------------------- + // Constructors + // ----------------------------------------------------------------------------------------------------------------- + public PaddedSectionEnricher() { } + public PaddedSectionEnricher(int maxLength) => MaxLength = maxLength; // ----------------------------------------------------------------------------------------------------------------- // Methods diff --git a/src/CodeOfChaos.Extensions.Serilog/Enrichers/TruncateSourceContextEnricher.cs b/src/CodeOfChaos.Extensions.Serilog/Enrichers/TruncateSourceContextEnricher.cs new file mode 100644 index 0000000..0b54331 --- /dev/null +++ b/src/CodeOfChaos.Extensions.Serilog/Enrichers/TruncateSourceContextEnricher.cs @@ -0,0 +1,34 @@ +// --------------------------------------------------------------------------------------------------------------------- +// Imports +// --------------------------------------------------------------------------------------------------------------------- +using Serilog.Core; +using Serilog.Events; + +namespace CodeOfChaos.Extensions.Serilog.Enrichers; +// --------------------------------------------------------------------------------------------------------------------- +// Code +// --------------------------------------------------------------------------------------------------------------------- +public class TruncateSourceContextEnricher : ILogEventEnricher { + public int MaxLength { get; } = 8; + + // ----------------------------------------------------------------------------------------------------------------- + // Constructors + // ----------------------------------------------------------------------------------------------------------------- + public TruncateSourceContextEnricher() { } + public TruncateSourceContextEnricher(int maxLength) => MaxLength = maxLength; + + // ----------------------------------------------------------------------------------------------------------------- + // Methods + // ----------------------------------------------------------------------------------------------------------------- + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { + if (!logEvent.Properties.TryGetValue("SourceContext", out LogEventPropertyValue? sourceContextValue) + || sourceContextValue is not ScalarValue { Value: string sourceContext }) return; + + string truncatedSourceContext = sourceContext.Length > MaxLength + 3 + ? string.Concat("...", sourceContext.AsSpan(sourceContext.Length - MaxLength, MaxLength)) + : sourceContext; + + var truncatedProperty = new LogEventProperty("SourceContext", new ScalarValue(truncatedSourceContext)); + logEvent.AddOrUpdateProperty(truncatedProperty); + } +} diff --git a/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs b/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs index 357918d..e70944d 100644 --- a/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs +++ b/src/CodeOfChaos.Extensions.Serilog/LoggerConfigurationExtensions.cs @@ -37,9 +37,11 @@ public static LoggerConfiguration WriteToAsyncConsole( return loggerConfiguration; } - public static LoggerConfiguration WithPaddedSectionEnricher(this LoggerConfiguration loggerConfiguration) { - return loggerConfiguration.Enrich.With(); - } + public static LoggerConfiguration WithPaddedSectionEnricher(this LoggerConfiguration loggerConfiguration, int maxLength = 8) + => loggerConfiguration.Enrich.With(new PaddedSectionEnricher(maxLength)); + + public static LoggerConfiguration WithTruncateSourceContextEnricher(this LoggerConfiguration loggerConfiguration, int maxLength = 8) + => loggerConfiguration.Enrich.With(new TruncateSourceContextEnricher(maxLength)); // ----------------------------------------------------------------------------------------------------------------- // Opinionated configurations From 6d7567e4106a7446d0ab131d873c0951fc9bcb9c Mon Sep 17 00:00:00 2001 From: Anna Sas Date: Fri, 27 Dec 2024 15:29:54 +0100 Subject: [PATCH 5/5] Feat: Package updates --- .../Tests.CodeOfChaos.Extensions.AspNetCore.csproj | 2 +- .../Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj | 2 +- .../Tests.CodeOfChaos.Extensions.Serilog.csproj | 2 +- .../Tests.CodeOfChaos.Extensions.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Tests.CodeOfChaos.Extensions.AspNetCore/Tests.CodeOfChaos.Extensions.AspNetCore.csproj b/tests/Tests.CodeOfChaos.Extensions.AspNetCore/Tests.CodeOfChaos.Extensions.AspNetCore.csproj index 00ed7f8..bbeaa25 100644 --- a/tests/Tests.CodeOfChaos.Extensions.AspNetCore/Tests.CodeOfChaos.Extensions.AspNetCore.csproj +++ b/tests/Tests.CodeOfChaos.Extensions.AspNetCore/Tests.CodeOfChaos.Extensions.AspNetCore.csproj @@ -13,7 +13,7 @@ - + diff --git a/tests/Tests.CodeOfChaos.Extensions.EntityFrameworkCore/Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj b/tests/Tests.CodeOfChaos.Extensions.EntityFrameworkCore/Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj index fb18307..daccf40 100644 --- a/tests/Tests.CodeOfChaos.Extensions.EntityFrameworkCore/Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj +++ b/tests/Tests.CodeOfChaos.Extensions.EntityFrameworkCore/Tests.CodeOfChaos.Extensions.EntityFrameworkCore.csproj @@ -13,7 +13,7 @@ - + diff --git a/tests/Tests.CodeOfChaos.Extensions.Serilog/Tests.CodeOfChaos.Extensions.Serilog.csproj b/tests/Tests.CodeOfChaos.Extensions.Serilog/Tests.CodeOfChaos.Extensions.Serilog.csproj index 189e28d..c80aae1 100644 --- a/tests/Tests.CodeOfChaos.Extensions.Serilog/Tests.CodeOfChaos.Extensions.Serilog.csproj +++ b/tests/Tests.CodeOfChaos.Extensions.Serilog/Tests.CodeOfChaos.Extensions.Serilog.csproj @@ -13,7 +13,7 @@ - + diff --git a/tests/Tests.CodeOfChaos.Extensions/Tests.CodeOfChaos.Extensions.csproj b/tests/Tests.CodeOfChaos.Extensions/Tests.CodeOfChaos.Extensions.csproj index 8615a47..0942251 100644 --- a/tests/Tests.CodeOfChaos.Extensions/Tests.CodeOfChaos.Extensions.csproj +++ b/tests/Tests.CodeOfChaos.Extensions/Tests.CodeOfChaos.Extensions.csproj @@ -13,7 +13,7 @@ - +