GenParameters(lm);
_builder.Append($@")
- {nestedIndentation}{{
+ {nestedIndentation}{{");
+
+ string enabledCheckIndentation = lm.SkipEnabledCheck ? "" : " ";
+ if (!lm.SkipEnabledCheck)
+ {
+ _builder.Append($@"
{nestedIndentation}if ({logger}.IsEnabled({level}))
{nestedIndentation}{{");
+ }
if (UseLoggerMessageDefine(lm))
{
_builder.Append($@"
- {nestedIndentation}__{lm.Name}Callback({logger}, ");
+ {nestedIndentation}{enabledCheckIndentation}__{lm.Name}Callback({logger}, ");
GenCallbackArguments(lm);
- _builder.Append(@$"{exceptionArg});");
+ _builder.Append($"{exceptionArg});");
}
else
{
_builder.Append($@"
- {nestedIndentation}{logger}.Log(
- {level},
- new global::Microsoft.Extensions.Logging.EventId({lm.EventId}, {eventName}),
- ");
- GenHolder(lm);
- _builder.Append($@",
- {exceptionArg},
- __{lm.Name}Struct.Format);");
+ {nestedIndentation}{enabledCheckIndentation}{logger}.Log(
+ {nestedIndentation}{enabledCheckIndentation}{level},
+ {nestedIndentation}{enabledCheckIndentation}new global::Microsoft.Extensions.Logging.EventId({lm.EventId}, {eventName}),
+ {nestedIndentation}{enabledCheckIndentation}");
+ GenHolder(lm);
+ _builder.Append($@",
+ {nestedIndentation}{enabledCheckIndentation}{exceptionArg},
+ {nestedIndentation}{enabledCheckIndentation}__{lm.Name}Struct.Format);");
+ }
+
+ if (!lm.SkipEnabledCheck)
+ {
+ _builder.Append($@"
+ {nestedIndentation}}}");
}
_builder.Append($@"
- {nestedIndentation}}}
{nestedIndentation}}}");
static string GetException(LoggerMethod lm)
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System.Collections.Immutable;
namespace Microsoft.Extensions.Logging.Generators
{
}
/// <summary>
- /// Gets the set of logging classes or structs containing methods to output.
+ /// Gets the set of logging classes containing methods to output.
/// </summary>
public IReadOnlyList<LoggerClass> GetLogClasses(IEnumerable<ClassDeclarationSyntax> classes)
{
bool multipleLoggerFields = false;
ids.Clear();
- foreach (var member in classDec.Members)
+ foreach (MemberDeclarationSyntax member in classDec.Members)
{
var method = member as MethodDeclarationSyntax;
if (method == null)
}
sm ??= _compilation.GetSemanticModel(classDec.SyntaxTree);
+ IMethodSymbol logMethodSymbol = sm.GetDeclaredSymbol(method, _cancellationToken) as IMethodSymbol;
+ Debug.Assert(logMethodSymbol != null, "log method is present.");
+ (int eventId, int? level, string message, string? eventName, bool skipEnabledCheck) = (-1, null, string.Empty, null, false);
foreach (AttributeListSyntax mal in method.AttributeLists)
{
continue;
}
- (int eventId, int? level, string message, string? eventName) = ExtractAttributeValues(ma.ArgumentList!, sm);
+ bool hasMisconfiguredInput = false;
+ ImmutableArray<AttributeData>? boundAttrbutes = logMethodSymbol?.GetAttributes();
+
+ if (boundAttrbutes == null)
+ {
+ continue;
+ }
+
+ foreach (AttributeData attributeData in boundAttrbutes)
+ {
+ // supports: [LoggerMessage(0, LogLevel.Warning, "custom message")]
+ // supports: [LoggerMessage(eventId: 0, level: LogLevel.Warning, message: "custom message")]
+ if (attributeData.ConstructorArguments.Any())
+ {
+ foreach (TypedConstant typedConstant in attributeData.ConstructorArguments)
+ {
+ if (typedConstant.Kind == TypedConstantKind.Error)
+ {
+ hasMisconfiguredInput = true;
+ }
+ }
+
+ ImmutableArray<TypedConstant> items = attributeData.ConstructorArguments;
+ Debug.Assert(items.Length == 3);
+
+ eventId = items[0].IsNull ? -1 : (int)GetItem(items[0]);
+ level = items[1].IsNull ? null : (int?)GetItem(items[1]);
+ message = items[2].IsNull ? "" : (string)GetItem(items[2]);
+ }
+
+ // argument syntax takes parameters. e.g. EventId = 0
+ // supports: e.g. [LoggerMessage(EventId = 0, Level = LogLevel.Warning, Message = "custom message")]
+ if (attributeData.NamedArguments.Any())
+ {
+ foreach (KeyValuePair<string, TypedConstant> namedArgument in attributeData.NamedArguments)
+ {
+ TypedConstant typedConstant = namedArgument.Value;
+ if (typedConstant.Kind == TypedConstantKind.Error)
+ {
+ hasMisconfiguredInput = true;
+ }
+ else
+ {
+ TypedConstant value = namedArgument.Value;
+ switch (namedArgument.Key)
+ {
+ case "EventId":
+ eventId = (int)GetItem(value);
+ break;
+ case "Level":
+ level = value.IsNull ? null : (int?)GetItem(value);
+ break;
+ case "SkipEnabledCheck":
+ skipEnabledCheck = (bool)GetItem(value);
+ break;
+ case "EventName":
+ eventName = (string?)GetItem(value);
+ break;
+ case "Message":
+ message = value.IsNull ? "" : (string)GetItem(value);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (hasMisconfiguredInput)
+ {
+ // skip further generator execution and let compiler generate the errors
+ break;
+ }
IMethodSymbol? methodSymbol = sm.GetDeclaredSymbol(method, _cancellationToken);
if (methodSymbol != null)
EventName = eventName,
IsExtensionMethod = methodSymbol.IsExtensionMethod,
Modifiers = method.Modifiers.ToString(),
+ SkipEnabledCheck = skipEnabledCheck
};
ExtractTemplates(message, lm.TemplateMap, lm.TemplateList);
return (loggerField, false);
}
- private (int eventId, int? level, string message, string? eventName) ExtractAttributeValues(AttributeArgumentListSyntax args, SemanticModel sm)
- {
- int eventId = 0;
- int? level = null;
- string? eventName = null;
- string message = string.Empty;
- foreach (AttributeArgumentSyntax a in args.Arguments)
- {
- // argument syntax takes parameters. e.g. EventId = 0
- Debug.Assert(a.NameEquals != null);
- switch (a.NameEquals.Name.ToString())
- {
- case "EventId":
- eventId = (int)sm.GetConstantValue(a.Expression, _cancellationToken).Value!;
- break;
- case "EventName":
- eventName = sm.GetConstantValue(a.Expression, _cancellationToken).ToString();
- break;
- case "Level":
- level = (int)sm.GetConstantValue(a.Expression, _cancellationToken).Value!;
- break;
- case "Message":
- message = sm.GetConstantValue(a.Expression, _cancellationToken).ToString();
- break;
- }
- }
- return (eventId, level, message, eventName);
- }
-
private void Diag(DiagnosticDescriptor desc, Location? location, params object?[]? messageArgs)
{
_reportDiagnostic(Diagnostic.Create(desc, location, messageArgs));
return string.Empty;
}
+
+ private static object GetItem(TypedConstant arg) => arg.Kind == TypedConstantKind.Array ? arg.Values : arg.Value;
}
/// <summary>
public bool IsExtensionMethod;
public string Modifiers = string.Empty;
public string LoggerField = string.Empty;
+ public bool SkipEnabledCheck;
}
/// <summary>
public sealed partial class LoggerMessageAttribute : System.Attribute
{
public LoggerMessageAttribute() { }
+ public LoggerMessageAttribute(int eventId, Microsoft.Extensions.Logging.LogLevel level, string message) { }
public int EventId { get { throw null; } set { } }
public string? EventName { get { throw null; } set { } }
public Microsoft.Extensions.Logging.LogLevel Level { get { throw null; } set { } }
public string Message { get { throw null; } set { } }
+ public bool SkipEnabledCheck { get { throw null; } set { } }
}
public partial class Logger<T> : Microsoft.Extensions.Logging.ILogger, Microsoft.Extensions.Logging.ILogger<T>
{
public LoggerMessageAttribute() { }
/// <summary>
+ /// Initializes a new instance of the <see cref="LoggerMessageAttribute"/> class
+ /// which is used to guide the production of a strongly-typed logging method.
+ /// </summary>
+ /// <param name="eventId">The log event Id.</param>
+ /// <param name="level">The log level.</param>
+ /// <param name="message">Format string of the log message.</param>
+ public LoggerMessageAttribute(int eventId, LogLevel level, string message)
+ {
+ EventId = eventId;
+ Level = level;
+ Message = message;
+ }
+
+ /// <summary>
/// Gets the logging event id for the logging method.
/// </summary>
public int EventId { get; set; } = -1;
/// Gets the message text for the logging method.
/// </summary>
public string Message { get; set; } = "";
+
+ /// <summary>
+ /// Gets the flag to skip IsEnabled check for the logging method.
+ /// </summary>
+ public bool SkipEnabledCheck { get; set; }
}
}
--- /dev/null
+// <auto-generated/>
+#nullable enable
+
+namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
+{
+ partial class TestWithDefaultValues
+ {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.0.0")]
+ private readonly struct __M0Struct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
+ {
+
+ public override string ToString()
+ {
+
+ return $"";
+ }
+
+ public static string Format(__M0Struct state, global::System.Exception? ex) => state.ToString();
+
+ public int Count => 1;
+
+ public global::System.Collections.Generic.KeyValuePair<string, object?> this[int index]
+ {
+ get => index switch
+ {
+ 0 => new global::System.Collections.Generic.KeyValuePair<string, object?>("{OriginalFormat}", ""),
+
+ _ => throw new global::System.IndexOutOfRangeException(nameof(index)), // return the same exception LoggerMessage.Define returns in this case
+ };
+ }
+
+ public global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<string, object?>> GetEnumerator()
+ {
+ for (int i = 0; i < 1; i++)
+ {
+ yield return this[i];
+ }
+ }
+
+ global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.0.0")]
+ public static partial void M0(global::Microsoft.Extensions.Logging.ILogger logger, global::Microsoft.Extensions.Logging.LogLevel level)
+ {
+ if (logger.IsEnabled(level))
+ {
+ logger.Log(
+ level,
+ new global::Microsoft.Extensions.Logging.EventId(-1, nameof(M0)),
+ new __M0Struct(),
+ null,
+ __M0Struct.Format);
+ }
+ }
+ }
+}
--- /dev/null
+// <auto-generated/>
+#nullable enable
+
+namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
+{
+ partial class TestWithSkipEnabledCheck
+ {
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.0.0")]
+ private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.Exception?> __M0Callback =
+ global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Information, new global::Microsoft.Extensions.Logging.EventId(0, nameof(M0)), "Message: When using SkipEnabledCheck, the generated code skips logger.IsEnabled(logLevel) check before calling log. To be used when consumer has already guarded logger method in an IsEnabled check.", true);
+
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.0.0")]
+ public static partial void M0(global::Microsoft.Extensions.Logging.ILogger logger)
+ {
+ __M0Callback(logger, null);
+ }
+ }
+}
\ No newline at end of file
Assert.Equal(string.Empty, logger.LastFormattedString);
Assert.Equal(LogLevel.Debug, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);
+
+ logger.Reset();
+ MessageTestExtensions.M5(logger, LogLevel.Trace);
+ Assert.Null(logger.LastException);
+ Assert.Equal(string.Empty, logger.LastFormattedString);
+ Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
+ Assert.Equal(-1, logger.LastEventId.Id);
+ Assert.Equal(1, logger.CallCount);
+
+ logger.Reset();
+ MessageTestExtensions.M6(logger, LogLevel.Trace);
+ Assert.Null(logger.LastException);
+ Assert.Equal(string.Empty, logger.LastFormattedString);
+ Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
+ Assert.Equal(6, logger.LastEventId.Id);
+ Assert.Equal(1, logger.CallCount);
}
[Fact]
Assert.Equal("M9", logger.LastFormattedString);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);
+
+ logger.Reset();
+ LevelTestExtensions.M10vs11(logger);
+ Assert.Null(logger.LastException);
+ Assert.Equal("event ID 10 vs. 11", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Warning, logger.LastLogLevel);
+ Assert.Equal(1, logger.CallCount);
+ Assert.Equal(11, logger.LastEventId.Id);
}
[Fact]
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);
Assert.Equal("CustomEventName", logger.LastEventId.Name);
+
+ logger.Reset();
+ EventNameTestExtensions.CustomEventName(logger);
+ Assert.Null(logger.LastException);
+ Assert.Equal("CustomEventName", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
+ Assert.Equal(1, logger.CallCount);
+ Assert.Equal("CustomEventName", logger.LastEventId.Name);
+ }
+
+ [Fact]
+ public void SkipEnabledCheckTests()
+ {
+ var logger = new MockLogger();
+
+ logger.Reset();
+ logger.Enabled = false;
+ Assert.False(logger.IsEnabled(LogLevel.Information));
+ SkipEnabledCheckExtensions.LoggerMethodWithFalseSkipEnabledCheck(logger);
+ Assert.Null(logger.LastException);
+ Assert.Null(logger.LastFormattedString);
+ Assert.Equal((LogLevel)(-1), logger.LastLogLevel);
+ Assert.Equal(0, logger.CallCount);
+ Assert.Equal(default, logger.LastEventId);
+
+ logger.Reset();
+ logger.Enabled = false;
+ Assert.False(logger.IsEnabled(LogLevel.Debug));
+ SkipEnabledCheckExtensions.LoggerMethodWithTrueSkipEnabledCheck(logger);
+ Assert.Null(logger.LastException);
+ Assert.Equal("Message: When using SkipEnabledCheck, the generated code skips logger.IsEnabled(logLevel) check before calling log. To be used when consumer has already guarded logger method in an IsEnabled check.", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Debug, logger.LastLogLevel);
+ Assert.Equal(1, logger.CallCount);
+ Assert.Equal("LoggerMethodWithTrueSkipEnabledCheck", logger.LastEventId.Name);
}
[Fact]
}
[Fact]
- public async Task TestBaseline_TestWithTwoParams_Success()
+ public async Task TestBaseline_TestWithSkipEnabledCheck_Success()
{
string testSourceCode = @"
namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
{
- internal static partial class TestWithTwoParams
+ internal static partial class TestWithSkipEnabledCheck
{
- [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = ""M0 {a1} {a2}"")]
- public static partial void M0(ILogger logger, int a1, System.Collections.Generic.IEnumerable<int> a2);
+ [LoggerMessage(EventId = 0, Level = LogLevel.Information, Message = ""Message: When using SkipEnabledCheck, the generated code skips logger.IsEnabled(logLevel) check before calling log. To be used when consumer has already guarded logger method in an IsEnabled check."", SkipEnabledCheck = true)]
+ public static partial void M0(ILogger logger);
+ }
+}";
+ await VerifyAgainstBaselineUsingFile("TestWithSkipEnabledCheck.generated.txt", testSourceCode);
+ }
+
+ [Fact]
+ public async Task TestBaseline_TestWithDefaultValues_Success()
+ {
+ string testSourceCode = @"
+namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
+{
+ internal static partial class TestWithDefaultValues
+ {
+ [LoggerMessage]
+ public static partial void M0(ILogger logger, LogLevel level);
}
}";
+ await VerifyAgainstBaselineUsingFile("TestWithDefaultValues.generated.txt", testSourceCode);
+ }
+
+ [Theory]
+ [InlineData("EventId = 0, Level = LogLevel.Error, Message = \"M0 {a1} {a2}\"")]
+ [InlineData("eventId: 0, level: LogLevel.Error, message: \"M0 {a1} {a2}\"")]
+ [InlineData("0, LogLevel.Error, \"M0 {a1} {a2}\"")]
+ [InlineData("0, LogLevel.Error, \"M0 {a1} {a2}\", SkipEnabledCheck = false")]
+ public async Task TestBaseline_TestWithTwoParams_Success(string argumentList)
+ {
+ string testSourceCode = $@"
+namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
+{{
+ internal static partial class TestWithTwoParams
+ {{
+ [LoggerMessage({argumentList})]
+ public static partial void M0(ILogger logger, int a1, System.Collections.Generic.IEnumerable<int> a2);
+ }}
+}}";
await VerifyAgainstBaselineUsingFile("TestWithTwoParams.generated.txt", testSourceCode);
}
Assert.Equal(DiagnosticDescriptors.LoggingMethodHasBody.Id, diagnostics[0].Id);
}
+ [Theory]
+ [InlineData("EventId = 0, Level = null, Message = \"This is a message with {foo}\"")]
+ [InlineData("eventId: 0, level: null, message: \"This is a message with {foo}\"")]
+ [InlineData("0, null, \"This is a message with {foo}\"")]
+ public async Task WithNullLevel_GeneratorWontFail(string argumentList)
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator($@"
+ partial class C
+ {{
+ [LoggerMessage({argumentList})]
+ static partial void M1(ILogger logger, string foo);
+
+ [LoggerMessage({argumentList})]
+ static partial void M2(ILogger logger, LogLevel level, string foo);
+ }}
+ ");
+
+ Assert.Empty(diagnostics);
+ }
+
+ [Theory]
+ [InlineData("EventId = null, Level = LogLevel.Debug, Message = \"This is a message with {foo}\"")]
+ [InlineData("eventId: null, level: LogLevel.Debug, message: \"This is a message with {foo}\"")]
+ [InlineData("null, LogLevel.Debug, \"This is a message with {foo}\"")]
+ public async Task WithNullEventId_GeneratorWontFail(string argumentList)
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator($@"
+ partial class C
+ {{
+ [LoggerMessage({argumentList})]
+ static partial void M1(ILogger logger, string foo);
+ }}
+ ");
+
+ Assert.Empty(diagnostics);
+ }
+
+ [Fact]
+ public async Task WithNullMessage_GeneratorWontFail()
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator(@"
+ partial class C
+ {
+ [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = null)]
+ static partial void M1(ILogger logger, string foo);
+ }
+ ");
+
+ Assert.Single(diagnostics);
+ Assert.Equal(DiagnosticDescriptors.ArgumentHasNoCorrespondingTemplate.Id, diagnostics[0].Id);
+ Assert.Contains("Argument 'foo' is not referenced from the logging message", diagnostics[0].GetMessage(), StringComparison.InvariantCulture);
+ }
+
+ [Fact]
+ public async Task WithNullSkipEnabledCheck_GeneratorWontFail()
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator(@"
+ partial class C
+ {
+ [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""This is a message with {foo}"", SkipEnabledCheck = null)]
+ static partial void M1(ILogger logger, string foo);
+ }
+ ");
+
+ Assert.Empty(diagnostics);
+ }
+
+ [Fact]
+ public async Task WithBadMisconfiguredInput_GeneratorWontFail()
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator(@"
+ public static partial class C
+ {
+ [LoggerMessage(SkipEnabledCheck = 6)]
+ public static partial void M0(ILogger logger, LogLevel level);
+
+ [LoggerMessage(eventId: true, level: LogLevel.Debug, message: ""misconfigured eventId as bool"")]
+ public static partial void M1(ILogger logger);
+ }
+ ");
+
+ Assert.Empty(diagnostics);
+ }
+
[Fact]
public async Task MissingTemplate()
{
Assert.Empty(diagnostics);
}
+ [Theory]
+ [InlineData("false")]
+ [InlineData("true")]
+ [InlineData("null")]
+ public async Task UsingSkipEnabledCheck(string skipEnabledCheckValue)
+ {
+ IReadOnlyList<Diagnostic> diagnostics = await RunGenerator($@"
+ partial class C
+ {{
+ public partial class WithLoggerMethodUsingSkipEnabledCheck
+ {{
+ [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = ""M1"", SkipEnabledCheck = {skipEnabledCheckValue})]
+ static partial void M1(ILogger logger);
+ }}
+ }}
+ ");
+
+ Assert.Empty(diagnostics);
+ }
+
[Fact]
public async Task MissingExceptionType()
{
{
[LoggerMessage(EventId = 0, Level = LogLevel.Trace, Message = "M0", EventName = "CustomEventName")]
public static partial void M0(ILogger logger);
+
+ [LoggerMessage(EventId = 2, Level = LogLevel.Trace, Message = "CustomEventName")] // EventName inferred from method name
+ public static partial void CustomEventName(ILogger logger);
}
}
[LoggerMessage(EventId = 9, Message = "M9")]
public static partial void M9(LogLevel level, ILogger logger);
+
+ [LoggerMessage(eventId: 10, level: LogLevel.Warning, message: "event ID 10 vs. 11", EventId = 11)]
+ public static partial void M10vs11(ILogger logger);
}
}
[LoggerMessage(EventId = 4, Level = LogLevel.Debug, Message = "{p1}")]
public static partial void M4(ILogger logger, string p1, int p2, int p3);
#endif
+
+ [LoggerMessage]
+ public static partial void M5(ILogger logger, LogLevel level);
+
+ [LoggerMessage(EventId = 6, Message = "")]
+ public static partial void M6(ILogger logger, LogLevel level);
}
}
--- /dev/null
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
+{
+ internal static partial class SkipEnabledCheckExtensions
+ {
+ [LoggerMessage(EventId = 0, Level = LogLevel.Debug, Message = "Message: When using SkipEnabledCheck, the generated code skips logger.IsEnabled(logLevel) check before calling log. To be used when consumer has already guarded logger method in an IsEnabled check.", SkipEnabledCheck = true)]
+ internal static partial void LoggerMethodWithTrueSkipEnabledCheck(ILogger logger);
+
+ [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "M1", SkipEnabledCheck = false)]
+ internal static partial void LoggerMethodWithFalseSkipEnabledCheck(ILogger logger);
+ }
+}
\ No newline at end of file