You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Event id is not an effective concept; customers don't want to use it and don't have anything to do with it. So, we want overloads that don't require that.
We are trying to shift customers to not use message strings and stick with structured logging. So, we want overloads that don't include a message.
We routinely find situations where log levels are specified as a logging method parameter rather than in the attribute definition, so we want overloads that don't include a level.
Bottom line is that the lack of these constructors leads to considerably more ceremony for the customers. More stuff to type with no upside to them.
Proposal
public sealed class LoggerMessageAttribute : Attribute
{
public LoggerMessageAttribute()
public LoggerMessageAttribute(int eventId, LogLevel level, string message)
+ public LoggerMessageAttribute(LogLevel level, string message)+ public LoggerMessageAttribute(LogLevel level)+ public LoggerMessageAttribute(string message)
}
Original description
dotnet/extensions supports a variety of shortcut constructors on LogMethodAttribute. In the past these shortcuts were deemed undesirable. While I don't know the details behind the original decisions, now that we have more history of internal usage and a better track record we should reconsider.
@geeknoid - can you enumerate exactly which APIs you hope to bring over?
Event id is not an effective concept, customers don't want to use it and don't have anything to do with it. So we want overloads that don't require that.
We are trying to shift customers to not use message strings and stick with structured logging. So we want overloads that don't include a message.
We routinely find situations where log levels are specified as a logging method parameter rather than in the attribute definition, so we want overloads that don't include a level.
Bottom line is that the lack of these contrusctors leads to considerably more ceremony for the customers. More stuff to type with no upside to them.
Event id is not an effective concept, customers don't want to use it and don't have anything to do with it. So we want overloads that don't require that.
If this is the case, why are we proposing the following constructors? would be better reducing a more helper constructors in such scenario.
publicLoggerMessageAttribute(int eventId,LogLevel level)
public LoggerMessageAttribute(inteventId,stringmessage)publicLoggerMessageAttribute(int eventide)
Just a heads up, I suspect without changes to static analysis users that attempt to use the new attribute constructors will get a warning that multiple events use the same -1 id, and warnings that the message string doesn't include their parameter names. Presumably we'd want to remove those warnings.
Regarding event id, we found internally that our telemetry backend tools have nothing to do with event id/event name and those just get dropped on the floor. As such, application teams don't really care about the event ids and would rather avoid having to deal with them.
Regarding the LogLevel, the code generator recognizes that there isn't any LogLevel specified in the attribute and then insists that a LogLevel value be provided as an argument to the logging method. This makes it possible to have dynamically configurable log level which is desirable in several situations.
In terms of ceremony, here's some examples:
internalstaticclassLogging{[LoggerMessage(LogLevel.Information)]voidCreateRecord(thisILoggerlogger,stringrecordId);[LoggerMessage(LogLevel.Debug)]voidDeleteRecord(thisILoggerlogger,stringrecordId);[LoggerMessage("A record is being skipped: {recordId}")]voidSkipRecord(thisILoggerlogger,stringrecordId);[LoggerMessage(LogLevel.Warning,"I am a broken record: {recordId}")]voidBrokenRecord(thisILoggerlogger,stringrecordId);}
As opposed to the more verbose:
internalstaticclassLogging{[LoggerMessage(LogLevel=LogLevel.Information)]voidCreateRecord(thisILoggerlogger,stringrecordId);[LoggerMessage(LogLevel=LogLevel.Debug)]voidDeleteRecord(thisILoggerlogger,stringrecordId);[LoggerMessage(Messgae="A record is being skipped: {recordId}")]voidSkipRecord(thisILoggerlogger,stringrecordId);[LoggerMessage(LogLevel=LogLevel.Warning,Message="I am a broken record: {recordId}")]voidBrokenRecord(thisILoggerlogger,stringrecordId);}
There is simply no value in forcing the developer to enter this extra boilerplate throughout their code rather than adding a set of constructors that address the real-world mainstream use of the attribute.
The bullet points, especially that we consider event id a mistake, is somewhat surprising
To add a little history, I think EventId got added to the original logging design to increase compat with ETW, and the id got added to the LoggerMessage attribute in turn because it was part of ILogger.Log(). I don't consider EventId existing to be a mistake, but I do agree with Martin that currently customers aren't getting much value from specifying it. Having it be optional feels better than having it be required. In the future some new scenarios like client-side EventId based filtering might provide customers more value around it, but other customers will continue having no reason to care about it.
Given that we've already gone against guidelines by having the (int, LogLevel, string) secondary constructor, we feel that this is a reasonable enhancement to usability of people creating these logger functions.
namespaceMicrosoft.Extensions.Logging;publicsealedpartialclassLoggerMessageAttribute:Attribute{// Existing:// public LoggerMessageAttribute();// public LoggerMessageAttribute(int eventId, LogLevel level, string message);publicLoggerMessageAttribute(LogLevellevel,stringmessage);publicLoggerMessageAttribute(LogLevellevel);publicLoggerMessageAttribute(stringmessage);}
Activity
geeknoid commentedon Jun 8, 2023
Here's the set:
So:
Event id is not an effective concept, customers don't want to use it and don't have anything to do with it. So we want overloads that don't require that.
We are trying to shift customers to not use message strings and stick with structured logging. So we want overloads that don't include a message.
We routinely find situations where log levels are specified as a logging method parameter rather than in the attribute definition, so we want overloads that don't include a level.
Bottom line is that the lack of these contrusctors leads to considerably more ceremony for the customers. More stuff to type with no upside to them.
tarekgh commentedon Jun 8, 2023
If this is the case, why are we proposing the following constructors? would be better reducing a more helper constructors in such scenario.
geeknoid commentedon Jun 8, 2023
@tarekgh I hate it when people point out logical flaws in my stuff :-)
Yeah, I suppose it would be reasonable to not include those.
[-]Add additional LoggerMethodAttribute constructors[/-][+]Add additional LoggerMessageAttribute constructors[/+]noahfalk commentedon Jun 9, 2023
Just a heads up, I suspect without changes to static analysis users that attempt to use the new attribute constructors will get a warning that multiple events use the same -1 id, and warnings that the message string doesn't include their parameter names. Presumably we'd want to remove those warnings.
tarekgh commentedon Jun 9, 2023
@noahfalk what you are referring to is the source gen diagnostic SYSLIB1006 which we already changed it to be just
infoinstead ofwarning#72263
#85581
runtime/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs
Line 48 in 7de4e1b
We may consider changing the code to ignore the default event id
-1and not produce any warning or info for that Id.runtime/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs
Line 269 in 7de4e1b
If there is not any other concern, I'll modify the proposal and post it in the description, and we can proceed with the design review.
3 remaining items
geeknoid commentedon Jun 13, 2023
A few follow-ups:
Regarding event id, we found internally that our telemetry backend tools have nothing to do with event id/event name and those just get dropped on the floor. As such, application teams don't really care about the event ids and would rather avoid having to deal with them.
Regarding the LogLevel, the code generator recognizes that there isn't any LogLevel specified in the attribute and then insists that a LogLevel value be provided as an argument to the logging method. This makes it possible to have dynamically configurable log level which is desirable in several situations.
In terms of ceremony, here's some examples:
As opposed to the more verbose:
There is simply no value in forcing the developer to enter this extra boilerplate throughout their code rather than adding a set of constructors that address the real-world mainstream use of the attribute.
noahfalk commentedon Jun 13, 2023
To add a little history, I think EventId got added to the original logging design to increase compat with ETW, and the id got added to the LoggerMessage attribute in turn because it was part of ILogger.Log(). I don't consider EventId existing to be a mistake, but I do agree with Martin that currently customers aren't getting much value from specifying it. Having it be optional feels better than having it be required. In the future some new scenarios like client-side EventId based filtering might provide customers more value around it, but other customers will continue having no reason to care about it.
tarekgh commentedon Jun 13, 2023
Marked as ready for review as @geeknoid want to discuss it one more time after he added more info to the issue.
bartonjs commentedon Jun 15, 2023
Video
Given that we've already gone against guidelines by having the
(int, LogLevel, string)secondary constructor, we feel that this is a reasonable enhancement to usability of people creating these logger functions.