Skip to content

Commit

Permalink
Add LoggerMessageAttribute constructor's overloads (dotnet#87738)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekgh authored Jun 18, 2023
1 parent 1ea78a4 commit eb71494
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,43 @@ public IReadOnlyList<LoggerClass> GetLogClasses(IEnumerable<ClassDeclarationSynt
}

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.Empty : (string)GetItem(items[2]);
switch (items.Length)
{
case 1:
// LoggerMessageAttribute(LogLevel level)
// LoggerMessageAttribute(string message)
if (items[0].Type.SpecialType == SpecialType.System_String)
{
message = (string)GetItem(items[0]);
level = null;
}
else
{
message = string.Empty;
level = items[0].IsNull ? null : (int?)GetItem(items[0]);
}
eventId = -1;
break;

case 2:
// LoggerMessageAttribute(LogLevel level, string message)
eventId = -1;
level = items[0].IsNull ? null : (int?)GetItem(items[0]);
message = items[1].IsNull ? string.Empty : (string)GetItem(items[1]);
break;

case 3:
// LoggerMessageAttribute(int eventId, LogLevel level, string message)
eventId = items[0].IsNull ? -1 : (int)GetItem(items[0]);
level = items[1].IsNull ? null : (int?)GetItem(items[1]);
message = items[2].IsNull ? string.Empty : (string)GetItem(items[2]);
break;

default:
Debug.Assert(false, "Unexpected number of arguments in attribute constructor.");
break;
}
}

// argument syntax takes parameters. e.g. EventId = 0
Expand Down Expand Up @@ -266,7 +298,8 @@ public IReadOnlyList<LoggerClass> GetLogClasses(IEnumerable<ClassDeclarationSynt
}

// ensure there are no duplicate event ids.
if (!eventIds.Add(lm.EventId))
// LoggerMessageAttribute has constructors that don't take an EventId, we need to exclude the default Id -1 from duplication checks.
if (lm.EventId != -1 && !eventIds.Add(lm.EventId))
{
Diag(DiagnosticDescriptors.ShouldntReuseEventIds, ma.GetLocation(), lm.EventId, classDec.Identifier.Text);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ public sealed partial class LoggerMessageAttribute : System.Attribute
{
public LoggerMessageAttribute() { }
public LoggerMessageAttribute(int eventId, Microsoft.Extensions.Logging.LogLevel level, string message) { }
public LoggerMessageAttribute(Microsoft.Extensions.Logging.LogLevel level) { }
public LoggerMessageAttribute(Microsoft.Extensions.Logging.LogLevel level, string message) { }
public LoggerMessageAttribute(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 { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@ public LoggerMessageAttribute(int eventId, LogLevel level, string message)
Message = message;
}

/// <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="level">The log level.</param>
/// <param name="message">Format string of the log message.</param>
public LoggerMessageAttribute(LogLevel level, string message)
{
Level = level;
Message = message;
}

/// <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="level">The log level.</param>
public LoggerMessageAttribute(LogLevel level)
{
Level = level;
}

/// <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="message">Format string of the log message.</param>
public LoggerMessageAttribute(string message)
{
Message = message;
}

/// <summary>
/// Gets the logging event id for the logging method.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,27 @@ public void InstanceTests()
Assert.Equal("M1 Foo", logger.LastFormattedString);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);

logger.Reset();
o.M2("Bar");
Assert.Null(logger.LastException);
Assert.Equal("M2 Bar", logger.LastFormattedString);
Assert.Equal(LogLevel.Information, logger.LastLogLevel);
Assert.Equal(-1, logger.LastEventId.Id);

logger.Reset();
o.M3(LogLevel.Critical, "Foo Bar");
Assert.Null(logger.LastException);
Assert.Equal("M3 Foo Bar", logger.LastFormattedString);
Assert.Equal(LogLevel.Critical, logger.LastLogLevel);
Assert.Equal(-1, logger.LastEventId.Id);

logger.Reset();
o.M4();
Assert.Null(logger.LastException);
Assert.Equal("", logger.LastFormattedString);
Assert.Equal(LogLevel.Debug, logger.LastLogLevel);
Assert.Equal(-1, logger.LastEventId.Id);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,16 @@ public TestInstances(ILogger logger)

[LoggerMessage(EventId = 1, Level = LogLevel.Trace, Message = "M1 {p1}")]
public partial void M1(string p1);

// Test LoggerMessage Constructor's overloads

[LoggerMessage(LogLevel.Information, "M2 {p1}")]
public partial void M2(string p1);

[LoggerMessage("M3 {p1}")]
public partial void M3(LogLevel level, string p1);

[LoggerMessage(LogLevel.Debug)]
public partial void M4();
}
}

0 comments on commit eb71494

Please sign in to comment.