IMethodSymbol logMethodSymbol = sm.GetDeclaredSymbol(method, _cancellationToken)!;
Debug.Assert(logMethodSymbol != null, "log method is present.");
(int eventId, int? level, string message, string? eventName, bool skipEnabledCheck) = (-1, null, string.Empty, null, false);
+ bool suppliedEventId = false;
foreach (AttributeListSyntax mal in method.AttributeLists)
{
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]);
+ if (!items[0].IsNull)
+ {
+ suppliedEventId = true;
+ eventId = (int)GetItem(items[0]);
+ }
level = items[1].IsNull ? null : (int?)GetItem(items[1]);
message = items[2].IsNull ? string.Empty : (string)GetItem(items[2]);
break;
{
case "EventId":
eventId = (int)GetItem(value);
+ suppliedEventId = true;
break;
case "Level":
level = value.IsNull ? null : (int?)GetItem(value);
break;
}
+ if (!suppliedEventId)
+ {
+ eventId = GetNonRandomizedHashCode(string.IsNullOrWhiteSpace(eventName) ? logMethodSymbol.Name : eventName);
+ }
+
var lm = new LoggerMethod
{
Name = logMethodSymbol.Name,
}
// ensure there are no duplicate event ids.
- // 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))
+ // We don't check Id duplication for the auto-generated event id.
+ if (suppliedEventId && !eventIds.Add(lm.EventId))
{
Diag(DiagnosticDescriptors.ShouldntReuseEventIds, ma.GetLocation(), lm.EventId, classDec.Identifier.Text);
}
// but instead is supposed to be taken as a parameter for the template.
public bool IsTemplateParameter => !IsLogger && !IsException && !IsLogLevel;
}
+
+ /// <summary>
+ /// Returns a non-randomized hash code for the given string.
+ /// We always return a positive value.
+ /// </summary>
+ internal static int GetNonRandomizedHashCode(string s)
+ {
+ uint result = 2166136261u;
+ foreach (char c in s)
+ {
+ result = (c ^ result) * 16777619;
+ }
+ return Math.Abs((int)result);
+ }
}
}
Assert.Null(logger.LastException);
Assert.Equal(string.Empty, logger.LastFormattedString);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
- Assert.Equal(-1, logger.LastEventId.Id);
+ Assert.Equal(400_526_807, logger.LastEventId.Id);
Assert.Equal(1, logger.CallCount);
logger.Reset();
var logger = new MockLogger();
var o = new TestInstances(logger);
+ // [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "M0")]
logger.Reset();
o.M0();
Assert.Null(logger.LastException);
Assert.Equal(LogLevel.Error, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);
+ // [LoggerMessage(EventId = 1, Level = LogLevel.Trace, Message = "M1 {p1}")]
logger.Reset();
o.M1("Foo");
Assert.Null(logger.LastException);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal(1, logger.CallCount);
+ // [LoggerMessage(LogLevel.Information, "M2 {p1}")]
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);
+ Assert.Equal(350_193_950, logger.LastEventId.Id);
+ // [LoggerMessage("M3 {p1}")]
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);
+ Assert.Equal(366_971_569, logger.LastEventId.Id);
+ // [LoggerMessage(LogLevel.Debug)]
logger.Reset();
o.M4();
Assert.Null(logger.LastException);
Assert.Equal("", logger.LastFormattedString);
Assert.Equal(LogLevel.Debug, logger.LastLogLevel);
- Assert.Equal(-1, logger.LastEventId.Id);
+ Assert.Equal(383_749_188, logger.LastEventId.Id);
+
+ // [LoggerMessage(level: LogLevel.Warning, message: "custom message {v}", eventId: 12341)]
+ logger.Reset();
+ o.M5("Hello");
+ Assert.Null(logger.LastException);
+ Assert.Equal("custom message Hello", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Warning, logger.LastLogLevel);
+ Assert.Equal(12341, logger.LastEventId.Id);
+
+ // [LoggerMessage(EventName = "My Event Name", Level = LogLevel.Information, Message = "M6 - {p1}")]
+ logger.Reset();
+ o.M6("Generate event Id");
+ Assert.Null(logger.LastException);
+ Assert.Equal("M6 - Generate event Id", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Information, logger.LastLogLevel);
+ Assert.Equal("My Event Name", logger.LastEventId.Name);
+ Assert.Equal(26_601_394, logger.LastEventId.Id);
+
+ // [LoggerMessage(Level = LogLevel.Warning, Message = "M7 - {p1}")]
+ logger.Reset();
+ o.M7("Generate event Id");
+ Assert.Null(logger.LastException);
+ Assert.Equal("M7 - Generate event Id", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Warning, logger.LastLogLevel);
+ Assert.Equal("M7", logger.LastEventId.Name);
+ Assert.Equal(434_082_045, logger.LastEventId.Id);
+
+ // [LoggerMessage(EventId = 100, Level = LogLevel.Warning, Message = "M8 - {p1}")]
+ logger.Reset();
+ o.M8("Generate event Id");
+ Assert.Null(logger.LastException);
+ Assert.Equal("M8 - Generate event Id", logger.LastFormattedString);
+ Assert.Equal(LogLevel.Warning, logger.LastLogLevel);
+ Assert.Equal("M8", logger.LastEventId.Name);
+ Assert.Equal(100, logger.LastEventId.Id);
}
[Fact]