FastLogr 1.0.0
dotnet add package FastLogr --version 1.0.0
NuGet\Install-Package FastLogr -Version 1.0.0
<PackageReference Include="FastLogr" Version="1.0.0" />
paket add FastLogr --version 1.0.0
#r "nuget: FastLogr, 1.0.0"
// Install FastLogr as a Cake Addin #addin nuget:?package=FastLogr&version=1.0.0 // Install FastLogr as a Cake Tool #tool nuget:?package=FastLogr&version=1.0.0
FastLogr <img src="https://github.com/MichaelHochriegl/FastLogr/blob/main/FastLogr_noBorder_64x64.png?raw=true" height="30" width="30" >
A less convoluted approach to the newly introduced high-performance logging Microsoft recently introduced.
Purpose
Microsoft introduced a new warning CA1848: Use the LoggerMessage delegates
that links to the page describing
high-performance logging by either writing an Action
for your log message or, by using
their source generated approach.
As I'm not really a fan of either of those proposed ways I created this package.
FastLogr
tries to combine both approaches that MS suggests and do it in a more elegant way.
It also uses source generators to limit what you have to code, but instead of the MS approach with way less hassle.
The following sections compare the MS approach and the FastLogr
approach.
MS Approach
To get the MS source gen going you need to make your class partial
and also provide a static
, partial
method.
namespace FastLogr.Example.WorkerService;
public partial class MsApproach
{
[LoggerMessage(
EventId = 0,
Level = LogLevel.Critical,
Message = "Could not open socket to `{hostName}`")]
public static partial void CouldNotOpenSocket(
ILogger logger, string hostName);
}
The code generated by this looks like this:
// <auto-generated/>
#nullable enable
namespace FastLogr.Example.WorkerService
{
partial class MsApproach
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.8.27404")]
private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.String, global::System.Exception?> __CouldNotOpenSocketCallback =
global::Microsoft.Extensions.Logging.LoggerMessage.Define<global::System.String>(global::Microsoft.Extensions.Logging.LogLevel.Critical, new global::Microsoft.Extensions.Logging.EventId(0, nameof(CouldNotOpenSocket)), "Could not open socket to `{hostName}`", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true });
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.8.27404")]
public static partial void CouldNotOpenSocket(global::Microsoft.Extensions.Logging.ILogger logger, global::System.String hostName)
{
if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Critical))
{
__CouldNotOpenSocketCallback(logger, hostName, null);
}
}
}
}
This is just one example of how you can get the MS way going, more can be found in the documentation.
FastLogr
Approach
To get the FastLogr
source gen going you simply need to provide an Action
with the parameters you want to log.
using FastLogr.Attributes;
namespace FastLogr.Example.WorkerService;
public class FastLogrApproach
{
[LogMessage(MessageTemplate = "Writing log with FastLogr, my message was '{message}'", LogLevel = LogLevel.Critical, EventId = 0)]
private static Action<string> LogFastLogrMessage = default!;
}
No need to mark your class as partial
just for the sake of logging.
The generated code will look like this:
using System;
using Microsoft.Extensions.Logging;
using FastLogr.Attributes;
namespace SourceGenPlayground.Example.Worker;
public static class LogFastLogrMessageExtensions
{
private static readonly Action<ILogger, string, Exception> s_logFastLogrMessage = LoggerMessage.Define<string>(LogLevel.Critical, new EventId(0, ""), "Writing log with FastLogr, my message was '{message}'");
public static void LogFastLogrMessage(this ILogger logger, string arg1) => s_logFastLogrMessage(logger, arg1, default !);
}
The usage of the FastLogr
approach is simple, as it provides you with an extension method on your ILogger
instance:
using FastLogr.Attributes;
using SourceGenPlayground.Example.Worker;
namespace FastLogr.Example.WorkerService;
public class FastLogrApproach
{
private readonly ILogger<FastLogrApproach> _logger;
[LogMessage(MessageTemplate = "Writing log with FastLogr, my message was '{message}'", LogLevel = LogLevel.Critical, EventId = 0)]
private static Action<string> LogFastLogrMessage = default!;
public FastLogrApproach(ILogger<FastLogrApproach> logger)
{
_logger = logger;
_logger.LogFastLogrMessage("MyCustomMessage");
}
}
Installation
FastLogr
is published as a nuget package, so installation is simple:
dotnet add package FastLogr
There are also YOLO packages pushed here on this Github repository.
Usage
You define your log message as a combination of the LogMessage
attribute and an Action
with the parameter types
you want to pass to your log message.
using FastLogr.Attributes;
using SourceGenPlayground.Example.Worker;
namespace FastLogr.Example.WorkerService;
public class FastLogrApproach
{
private readonly ILogger<FastLogrApproach> _logger;
[LogMessage(MessageTemplate = "Writing log with FastLogr, my message was '{message}'", LogLevel = LogLevel.Critical, EventId = 0)]
private static Action<string> LogFastLogrMessage = default!;
public FastLogrApproach(ILogger<FastLogrApproach> logger)
{
_logger = logger;
_logger.LogFastLogrMessage("MyCustomMessage");
}
}
As shown above FastLogr
will generate an extension method for ILogger
and you can use it right away.
The types you want to log can be pretty much anything, e.g.:
using FastLogr.Attributes;
namespace FastLogr.Example.WorkerService;
public class FastLogrApproach
{
private readonly ILogger<FastLogrApproach> _logger;
[LogMessage(MessageTemplate = "Writing log with FastLogr, my message was '{message}'", LogLevel = LogLevel.Critical, EventId = 0)]
private static Action<string, FancyType> LogFastLogrMessage = default!;
public FastLogrApproach(ILogger<FastLogrApproach> logger)
{
_logger = logger;
_logger.LogFastLogrMessage("MyCustomMessage", new FancyType("fany message", 420, true));
}
}
public record FancyType(string FancyTypeString, int FancyTypeInt, bool FancyTypeBool);
Any usings
that your class
has will also be available to the ILogger
extension built by FastLogr
.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 317 | 8/9/2023 |