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