< Summary

Information
Class: NexusLabs.Needlr.Logging.NeedlrLoggerMessageAttribute
Assembly: NexusLabs.Needlr.Logging
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Logging/NeedlrLoggerMessageAttribute.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 19
Coverable lines: 19
Total lines: 133
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%210%
.ctor(...)100%210%
.ctor(...)100%210%
.ctor(...)100%210%
get_EventId()100%210%
get_EventName()100%210%
get_Level()100%210%
get_Message()100%210%
get_SkipEnabledCheck()100%210%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Logging/NeedlrLoggerMessageAttribute.cs

#LineLine coverage
 1using System;
 2
 3using Microsoft.Extensions.Logging;
 4
 5namespace NexusLabs.Needlr.Logging;
 6
 7/// <summary>
 8/// Marks a <c>partial</c> method whose body Needlr will source-generate into a
 9/// high-performance, cancellation-aware logging method.
 10/// </summary>
 11/// <remarks>
 12/// <para>
 13/// This attribute mirrors the surface of <c>Microsoft.Extensions.Logging.LoggerMessageAttribute</c>
 14/// (<see cref="EventId"/>, <see cref="EventName"/>, <see cref="Level"/>, <see cref="Message"/>,
 15/// <see cref="SkipEnabledCheck"/>) so migrating an existing <c>[LoggerMessage]</c> method is a
 16/// near drop-in swap. The generated body reuses the public
 17/// <see cref="LoggerMessage.Define(LogLevel, EventId, string)"/> primitive — the same fast path the
 18/// built-in generator targets — so there is no performance penalty for the common case.
 19/// </para>
 20/// <para>
 21/// The difference from the built-in attribute is the <em>cancellation guard</em>: when the method
 22/// has a parameter assignable to <see cref="System.Exception"/> and that argument is a cancellation
 23/// (an <see cref="OperationCanceledException"/> by default), the generated body consults
 24/// <see cref="NeedlrCancellationLogging"/> and, by default, <strong>skips the log entirely</strong>.
 25/// Cancellation is normal control flow in production code, so logging it as a warning or error is
 26/// usually noise. The behavior can be globally overridden at startup (force-log or demote to a lower
 27/// level) via <see cref="NeedlrCancellationLogging"/>.
 28/// </para>
 29/// <para>
 30/// The decorated method must be <c>partial</c>, return <c>void</c>, be non-generic, and live in a
 31/// <c>partial</c> type. For an <c>instance</c> method, the containing type must expose an
 32/// <see cref="ILogger"/> field or property; for a <c>static</c> method, an <see cref="ILogger"/>
 33/// parameter supplies the logger.
 34/// </para>
 35/// <para>
 36/// This is a source-generation only feature. It requires the
 37/// <c>NexusLabs.Needlr.Logging</c> package and the generator that ships with it.
 38/// </para>
 39/// </remarks>
 40/// <example>
 41/// <code>
 42/// using Microsoft.Extensions.Logging;
 43/// using NexusLabs.Needlr.Logging;
 44///
 45/// public partial class OrderService
 46/// {
 47///     private readonly ILogger&lt;OrderService&gt; _logger;
 48///
 49///     public OrderService(ILogger&lt;OrderService&gt; logger) =&gt; _logger = logger;
 50///
 51///     // When 'error' is an OperationCanceledException, this logs nothing by default.
 52///     [NeedlrLoggerMessage(EventId = 42, Level = LogLevel.Warning, Message = "Order {OrderId} failed")]
 53///     public partial void LogOrderFailed(int orderId, Exception error);
 54/// }
 55/// </code>
 56/// </example>
 57[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
 58public sealed class NeedlrLoggerMessageAttribute : Attribute
 59{
 60    /// <summary>
 61    /// Initializes a new instance of the <see cref="NeedlrLoggerMessageAttribute"/> class.
 62    /// All values are supplied via the named properties.
 63    /// </summary>
 064    public NeedlrLoggerMessageAttribute()
 65    {
 066    }
 67
 68    /// <summary>
 69    /// Initializes a new instance of the <see cref="NeedlrLoggerMessageAttribute"/> class with a
 70    /// message template. The <see cref="Level"/> defaults to <see cref="LogLevel.Information"/>.
 71    /// </summary>
 72    /// <param name="message">The structured message template (e.g. <c>"Order {OrderId} failed"</c>).</param>
 073    public NeedlrLoggerMessageAttribute(string message)
 74    {
 075        Message = message;
 076    }
 77
 78    /// <summary>
 79    /// Initializes a new instance of the <see cref="NeedlrLoggerMessageAttribute"/> class with a
 80    /// log level and message template.
 81    /// </summary>
 82    /// <param name="level">The level at which the message is logged.</param>
 83    /// <param name="message">The structured message template (e.g. <c>"Order {OrderId} failed"</c>).</param>
 084    public NeedlrLoggerMessageAttribute(LogLevel level, string message)
 85    {
 086        Level = level;
 087        Message = message;
 088    }
 89
 90    /// <summary>
 91    /// Initializes a new instance of the <see cref="NeedlrLoggerMessageAttribute"/> class with an
 92    /// event id, log level, and message template.
 93    /// </summary>
 94    /// <param name="eventId">The numeric event id assigned to the log entry.</param>
 95    /// <param name="level">The level at which the message is logged.</param>
 96    /// <param name="message">The structured message template (e.g. <c>"Order {OrderId} failed"</c>).</param>
 097    public NeedlrLoggerMessageAttribute(int eventId, LogLevel level, string message)
 98    {
 099        EventId = eventId;
 0100        Level = level;
 0101        Message = message;
 0102    }
 103
 104    /// <summary>
 105    /// Gets or sets the numeric event id assigned to the generated log entry. Defaults to <c>0</c>.
 106    /// </summary>
 0107    public int EventId { get; set; }
 108
 109    /// <summary>
 110    /// Gets or sets the event name assigned to the generated log entry. When <see langword="null"/>,
 111    /// the decorated method's name is used.
 112    /// </summary>
 0113    public string? EventName { get; set; }
 114
 115    /// <summary>
 116    /// Gets or sets the level at which the message is logged. Defaults to
 117    /// <see cref="LogLevel.Information"/> when not supplied via a constructor.
 118    /// </summary>
 0119    public LogLevel Level { get; set; } = LogLevel.Information;
 120
 121    /// <summary>
 122    /// Gets or sets the structured message template. Placeholders (e.g. <c>{OrderId}</c>) bind to the
 123    /// method's non-exception parameters in declaration order, exactly as with the built-in attribute.
 124    /// </summary>
 0125    public string Message { get; set; } = string.Empty;
 126
 127    /// <summary>
 128    /// Gets or sets a value indicating whether the generated body omits the
 129    /// <see cref="ILogger.IsEnabled(LogLevel)"/> guard. Set to <see langword="true"/> only when the
 130    /// caller has already checked that the level is enabled. Defaults to <see langword="false"/>.
 131    /// </summary>
 0132    public bool SkipEnabledCheck { get; set; }
 133}