RSCG – TelemetryLogging
RSCG – TelemetryLogging
name | TelemetryLogging |
nuget | https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/ |
link | https://andrewlock.net/behind-logproperties-and-the-new-telemetry-logging-source-generator/ |
author | Microsoft |
Generating deep logging messages for a class
This is how you can use TelemetryLogging .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Telemetry.Abstractions" Version="8.0.0" /> </ItemGroup> </Project>
The code that you will use is
using System.Text.Json; using Microsoft.Extensions.Logging; using ILoggerFactory loggerFactory = LoggerFactory.Create( builder => { //builder.AddSimpleConsole(); builder.AddJsonConsole( options => options.JsonWriterOptions = new JsonWriterOptions() { Indented = true }); } ) ; ILogger<Person> logger = loggerFactory.CreateLogger<Person>(); logger.LogInformation("test"); (new LoggingSample(logger)).TestLogging(); public record Person (string firstName, string LastName) { }
using Microsoft.Extensions.Logging; public partial class LoggingSample { private readonly ILogger _logger; public LoggingSample(ILogger logger) { _logger = logger; } [LoggerMessage( EventId = 20, Level = LogLevel.Critical, Message = "Value is {value:E}")] public static partial void UsingFormatSpecifier( ILogger logger, double value); [LoggerMessage( EventId = 19, Level = LogLevel.Information, Message = "Logging all person properties", EventName = "PersonLogging")] public partial void LogWithProperties([LogProperties] Person person); [LoggerMessage( EventId = 9, Level = LogLevel.Trace, Message = "Fixed message", EventName = "CustomEventName")] public partial void LogWithCustomEventName(); [LoggerMessage( EventId = 10, Message = "Welcome to {city} {province}!")] public partial void LogWithDynamicLogLevel( string city, LogLevel level, string province); public void TestLogging() { LogWithProperties(new Person("Andrei", "Ignat")); //LogWithCustomEventName(); //LogWithDynamicLogLevel("Vancouver", LogLevel.Warning, "BC"); //LogWithDynamicLogLevel("Vancouver", LogLevel.Information, "BC"); //UsingFormatSpecifier(_logger, 12345.6789); } }
The code that is generated is
// <auto-generated/> #nullable enable #pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103 partial class LoggingSample { /// <summary> /// Logs "Value is {value:E}" at "Critical" level. /// </summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Gen.Logging", "8.0.0.0")] public static partial void UsingFormatSpecifier(global::Microsoft.Extensions.Logging.ILogger logger, double value) { var state = global::Microsoft.Extensions.Logging.LoggerMessageHelper.ThreadLocalState; _ = state.ReserveTagSpace(2); state.TagArray[1] = new("value", value); state.TagArray[0] = new("{OriginalFormat}", "Value is {value:E}"); logger.Log( global::Microsoft.Extensions.Logging.LogLevel.Critical, new(20, nameof(UsingFormatSpecifier)), state, null, static (s, _) => { var value = s.TagArray[1].Value; return global::System.FormattableString.Invariant($"Value is {value:E}"); }); state.Clear(); } /// <summary> /// Logs "Logging all person properties" at "Information" level. /// </summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Gen.Logging", "8.0.0.0")] public partial void LogWithProperties(global::Person person) { if (!_logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Information)) { return; } var state = global::Microsoft.Extensions.Logging.LoggerMessageHelper.ThreadLocalState; _ = state.ReserveTagSpace(3); state.TagArray[2] = new("person.firstName", person?.firstName); state.TagArray[1] = new("person.LastName", person?.LastName); state.TagArray[0] = new("{OriginalFormat}", "Logging all person properties"); _logger.Log( global::Microsoft.Extensions.Logging.LogLevel.Information, new(19, "PersonLogging"), state, null, static (s, _) => { return "Logging all person properties"; }); state.Clear(); } /// <summary> /// Logs "Fixed message" at "Trace" level. /// </summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Gen.Logging", "8.0.0.0")] public partial void LogWithCustomEventName() { if (!_logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Trace)) { return; } var state = global::Microsoft.Extensions.Logging.LoggerMessageHelper.ThreadLocalState; _ = state.ReserveTagSpace(1); state.TagArray[0] = new("{OriginalFormat}", "Fixed message"); _logger.Log( global::Microsoft.Extensions.Logging.LogLevel.Trace, new(9, "CustomEventName"), state, null, static (s, _) => { return "Fixed message"; }); state.Clear(); } /// <summary> /// Logs "Welcome to {city} {province}!". /// </summary> [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Gen.Logging", "8.0.0.0")] public partial void LogWithDynamicLogLevel(string city, global::Microsoft.Extensions.Logging.LogLevel level, string province) { if (!_logger.IsEnabled(level)) { return; } var state = global::Microsoft.Extensions.Logging.LoggerMessageHelper.ThreadLocalState; _ = state.ReserveTagSpace(3); state.TagArray[2] = new("city", city); state.TagArray[1] = new("province", province); state.TagArray[0] = new("{OriginalFormat}", "Welcome to {city} {province}!"); _logger.Log( level, new(10, nameof(LogWithDynamicLogLevel)), state, null, static (s, _) => { var city = s.TagArray[2].Value ?? "(null)"; var province = s.TagArray[1].Value ?? "(null)"; return global::System.FormattableString.Invariant($"Welcome to {city} {province}!"); }); state.Clear(); } }
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/TelemetryLogging
Leave a Reply