diff --git a/Build.ps1 b/Build.ps1 index b13c813..c265894 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -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" @@ -20,7 +20,7 @@ foreach ($src in ls src/*) { echo "build: Packaging project in $src" - & dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix + & dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix -p:ContinuousIntegrationBuild=true if($LASTEXITCODE -ne 0) { exit 1 } Pop-Location diff --git a/README.md b/README.md index bd8781c..8b2313a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Serilog.Enrichers.Thread [![Build status](https://ci.appveyor.com/api/projects/status/2vgxdy3swg6eaj3f?svg=true)](https://ci.appveyor.com/project/serilog/serilog-enrichers-thread) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Enrichers.Thread.svg?style=flat)](https://www.nuget.org/packages/Serilog.Enrichers.Thread/) Enrich Serilog events with properties from the current thread. - + ### Getting started Install the package from NuGet: @@ -10,37 +10,41 @@ Install the package from NuGet: Install-Package Serilog.Enrichers.Thread ``` -In your logger configuration, apply `Enrich.WithThreadId()`: +In your logger configuration, apply `Enrich.WithThreadId()` and `Enrich.WithThreadName()`: ```csharp Log.Logger = new LoggerConfiguration() .Enrich.WithThreadId() + .Enrich.WithThreadName() .CreateLogger(); ``` + Many sinks simply include all properties without further action required, so the thread id will be logged automatically. -However, some sinks, such as the File and Console sinks use an output template and the new ThreadId may not be automatically output in your sink. In this case, in order for the ThreadId to show up in the logging, you will need to create or modify your output template. +However, some sinks, such as the File and Console sinks use an output template and the new `ThreadId` may not be automatically output in your sink. In this case, in order for the `ThreadId` or `ThreadName` to show up in the logging, you will need to create or modify your output template. ```csharp w.File(...., outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} {Properties}{NewLine}{Exception}") ``` -Here, {Properties} can include not only ThreadId, but any other enrichment which is applied. Alternatively, {ThreadId} could be used instead, if you want to only add the thread id enrichment. +Here, \{Properties} can include not only `ThreadId` and `ThreadName`, but any other enrichment which is applied. Alternatively, \{ThreadId} could be used instead, if you want to only add the thread id enrichment and \{ThreadName}, if you want to only add the thread name enrichment. An example, which also uses the Serilogs.Sinks.Async Nuget package, is below: ```csharp + Thread.CurrentThread.Name = "MyWorker"; + var logger = Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.Console(restrictedToMinimumLevel:Serilog.Events.LogEventLevel.Information) - .WriteTo.Async(w=>w.File("..\\..\\..\\..\\logs\\SerilogLogFile.json", rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} <{ThreadId}>{NewLine}{Exception}")) + .WriteTo.Async(w=>w.File("..\\..\\..\\..\\logs\\SerilogLogFile.json", rollingInterval: RollingInterval.Day, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} <{ThreadId}><{ThreadName}>{NewLine}{Exception}")) .Enrich.WithThreadId() .CreateLogger(); ``` Which would produce an output in the log file as follows: ``` -2018-04-06 13:12:45.684 +02:00 [ERR] The file file_name.svg does not exist <4> +2018-04-06 13:12:45.684 +02:00 [ERR] The file file_name.svg does not exist <4> ``` -Where, <4> is an example thread id. +Where, <4> is an example thread id and \ is an example thread name. To use the enricher, first install the NuGet package: @@ -48,5 +52,17 @@ To use the enricher, first install the NuGet package: Install-Package Serilog.Enrichers.Thread ``` +Note: +The \{ThreadName} property will only be attached when it is not null. Otherwise it will be omitted. +If you want to get this property always attached you can use the following: +```csharp +using Serilog.Enrichers; + +Log.Logger = new LoggerConfiguration() + .Enrich.WithThreadName() + .Enrich.WithProperty(ThreadNameEnricher.ThreadNamePropertyName, "MyDefault") + .CreateLogger(); +``` +The enrichment order is important. Otherwise "MyDefault" would always win. Copyright © 2016 Serilog Contributors - Provided under the [Apache License, Version 2.0](http://apache.org/licenses/LICENSE-2.0.html). diff --git a/appveyor.yml b/appveyor.yml index 396e0ef..90138f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,23 +1,26 @@ version: '{build}' skip_tags: true -image: Visual Studio 2017 +image: Visual Studio 2022 configuration: Release build_script: - ps: ./Build.ps1 test: off artifacts: - path: artifacts/Serilog.*.nupkg +- path: artifacts/Serilog.*.snupkg deploy: - provider: NuGet api_key: - secure: N59tiJECUYpip6tEn0xvdmDAEiP9SIzyLEFLpwiigm/8WhJvBNs13QxzT1/3/JW/ + secure: Fh92tRIFbe1FAiyD8lTThWgAorQ1vV+eFYMlUK0iLHBBenJcy/UYc1qj6kgHvUcO skip_symbols: true on: - branch: /^(master|dev)$/ + branch: /^(main|dev)$/ - provider: GitHub auth_token: secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX - artifact: /Serilog.*\.nupkg/ + artifacts: + /Serilog.*\.nupkg/ + /Serilog.*\.snupkg/ tag: v$(appveyor_build_version) on: - branch: master + branch: main diff --git a/assets/serilog-enricher-nuget.png b/assets/serilog-enricher-nuget.png new file mode 100644 index 0000000..0a1173e Binary files /dev/null and b/assets/serilog-enricher-nuget.png differ diff --git a/global.json b/global.json deleted file mode 100644 index 31a5f7f..0000000 --- a/global.json +++ /dev/null @@ -1 +0,0 @@ -{"projects":["src","test"]} \ No newline at end of file diff --git a/serilog-enrichers-thread.sln b/serilog-enrichers-thread.sln index d577d7a..5b1edc3 100644 --- a/serilog-enrichers-thread.sln +++ b/serilog-enrichers-thread.sln @@ -1,15 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.329 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.34928.147 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{037440DE-440B-4129-9F7A-09B42D00397E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject Build.ps1 = Build.ps1 - global.json = global.json - NuGet.Config = NuGet.Config README.md = README.md assets\Serilog.snk = assets\Serilog.snk EndProjectSection diff --git a/src/Serilog.Enrichers.Thread/Enrichers/ThreadIdEnricher.cs b/src/Serilog.Enrichers.Thread/Enrichers/ThreadIdEnricher.cs index 959877f..ad683ea 100644 --- a/src/Serilog.Enrichers.Thread/Enrichers/ThreadIdEnricher.cs +++ b/src/Serilog.Enrichers.Thread/Enrichers/ThreadIdEnricher.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Threading; using Serilog.Core; using Serilog.Events; using System; @@ -22,12 +21,17 @@ namespace Serilog.Enrichers /// /// Enriches log events with a ThreadId property containing the . /// - public class ThreadIdEnricher : ILogEventEnricher + sealed class ThreadIdEnricher : ILogEventEnricher { /// /// The property name added to enriched log events. /// - public const string ThreadIdPropertyName = "ThreadId"; + const string ThreadIdPropertyName = "ThreadId"; + + /// + /// The cached last created "ThreadId" property with some thread id. It is likely to be reused frequently so avoiding heap allocations. + /// + private LogEventProperty? _lastValue; /// /// Enrich the log event. @@ -36,7 +40,14 @@ public class ThreadIdEnricher : ILogEventEnricher /// Factory for creating new properties to add to the event. public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { - logEvent.AddPropertyIfAbsent(new LogEventProperty(ThreadIdPropertyName, new ScalarValue(Environment.CurrentManagedThreadId))); + var threadId = Environment.CurrentManagedThreadId; + + var last = _lastValue; + if (last is null || (int)((ScalarValue)last.Value).Value! != threadId) + // no need to synchronize threads on write - just some of them will win + _lastValue = last = new LogEventProperty(ThreadIdPropertyName, new ScalarValue(threadId)); + + logEvent.AddPropertyIfAbsent(last); } } } diff --git a/src/Serilog.Enrichers.Thread/Enrichers/ThreadNameEnricher.cs b/src/Serilog.Enrichers.Thread/Enrichers/ThreadNameEnricher.cs index ff098cb..7bf4ab3 100644 --- a/src/Serilog.Enrichers.Thread/Enrichers/ThreadNameEnricher.cs +++ b/src/Serilog.Enrichers.Thread/Enrichers/ThreadNameEnricher.cs @@ -12,23 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if THREAD_NAME using System.Threading; using Serilog.Core; using Serilog.Events; namespace Serilog.Enrichers { - /// - /// Enriches log events with a ThreadName property containing the + /// Enriches log events with a ThreadName property containing the . /// - public class ThreadNameEnricher : ILogEventEnricher + sealed class ThreadNameEnricher : ILogEventEnricher { /// /// The property name added to enriched log events. /// - public const string ThreadNamePropertyName = "ThreadName"; + const string ThreadNamePropertyName = "ThreadName"; + + /// + /// The cached last created "ThreadName" property with some thread name. It is likely to be reused frequently so avoiding heap allocations. + /// + private LogEventProperty? _lastValue; /// /// Enrich the log event. @@ -38,11 +41,15 @@ public class ThreadNameEnricher : ILogEventEnricher public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { var threadName = Thread.CurrentThread.Name; - if (threadName != null) + if (threadName is not null) { - logEvent.AddPropertyIfAbsent(new LogEventProperty(ThreadNamePropertyName, new ScalarValue(threadName))); + var last = _lastValue; + if (last is null || (string)((ScalarValue)last.Value).Value! != threadName) + // no need to synchronize threads on write - just some of them will win + _lastValue = last = new LogEventProperty(ThreadNamePropertyName, new ScalarValue(threadName)); + + logEvent.AddPropertyIfAbsent(last); } } } } -#endif \ No newline at end of file diff --git a/src/Serilog.Enrichers.Thread/Properties/AssemblyInfo.cs b/src/Serilog.Enrichers.Thread/Properties/AssemblyInfo.cs deleted file mode 100644 index e6a0a37..0000000 --- a/src/Serilog.Enrichers.Thread/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; -using System.Reflection; - -[assembly: AssemblyVersion("2.0.0.0")] - -[assembly: CLSCompliant(true)] diff --git a/src/Serilog.Enrichers.Thread/Serilog.Enrichers.Thread.csproj b/src/Serilog.Enrichers.Thread/Serilog.Enrichers.Thread.csproj index 63689c1..67eea47 100644 --- a/src/Serilog.Enrichers.Thread/Serilog.Enrichers.Thread.csproj +++ b/src/Serilog.Enrichers.Thread/Serilog.Enrichers.Thread.csproj @@ -1,10 +1,16 @@ - + Enrich Serilog events with properties from the current thread. - 3.1.0 + 4.0.0 + 4.0.0.0 Serilog Contributors - net45;netstandard1.0;netstandard2.0 + + net471;net462 + + $(TargetFrameworks);net8.0;net6.0;netstandard2.0 true true Serilog.Enrichers.Thread @@ -13,27 +19,28 @@ true Serilog.Enrichers.Thread serilog;thread;enricher - http://serilog.net/images/serilog-enricher-nuget.png + serilog-enricher-nuget.png http://serilog.net - http://www.apache.org/licenses/LICENSE-2.0 - false + Apache-2.0 + README.md + true + true + true + snupkg + latest + enable - + - - - + + + True + + + - - $(DefineConstants);THREAD_NAME - - - - $(DefineConstants);THREAD_NAME - - diff --git a/src/Serilog.Enrichers.Thread/ThreadLoggerConfigurationExtensions.cs b/src/Serilog.Enrichers.Thread/ThreadLoggerConfigurationExtensions.cs index 7ca9b55..9ff10c5 100644 --- a/src/Serilog.Enrichers.Thread/ThreadLoggerConfigurationExtensions.cs +++ b/src/Serilog.Enrichers.Thread/ThreadLoggerConfigurationExtensions.cs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. - using System; using System.Threading; using Serilog.Configuration; @@ -21,7 +20,7 @@ namespace Serilog { /// - /// Extends to add enrichers for . + /// Extends to add enrichers for /// capabilities. /// public static class ThreadLoggerConfigurationExtensions @@ -31,7 +30,7 @@ public static class ThreadLoggerConfigurationExtensions /// /// Logger enrichment configuration. /// Configuration object allowing method chaining. - /// + /// If is null. public static LoggerConfiguration WithThreadId( this LoggerEnrichmentConfiguration enrichmentConfiguration) { @@ -39,18 +38,17 @@ public static LoggerConfiguration WithThreadId( return enrichmentConfiguration.With(); } -#if THREAD_NAME /// /// Enrich log events with a ThreadName property containing the . /// - /// - /// + /// Logger enrichment configuration. + /// Configuration object allowing method chaining. + /// If is null. public static LoggerConfiguration WithThreadName( this LoggerEnrichmentConfiguration enrichmentConfiguration) { if (enrichmentConfiguration == null) throw new ArgumentNullException(nameof(enrichmentConfiguration)); return enrichmentConfiguration.With(); } -#endif } }