Skip to content

Add additional LoggerMessageAttribute constructors #87254

Closed

Description

@noahfalk

By @geeknoid

  • 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?

Activity

  1. added this to the 8.0.0 milestone on Jun 8, 2023
  2. ghost added
    needs-area-labelAn area label is needed to ensure this gets routed to the appropriate area owners
    on Jun 8, 2023
  3. geeknoid commented on Jun 8, 2023

    @geeknoid
    Member

    Here's the set:

    public sealed class LoggerMessageAttribute : Attribute
    {
        // existing
        public LoggerMessageAttribute()
        public LoggerMessageAttribute(int eventId, LogLevel level, string message)
    
        // proposed additions
        public LoggerMessageAttribute(int eventId, LogLevel level)
        public LoggerMessageAttribute(LogLevel level, string message)
        public LoggerMessageAttribute(LogLevel level)
        public LoggerMessageAttribute(string message)
        public LoggerMessageAttribute(int eventId, string message)
        public LoggerMessageAttribute(int eventId)
    
        // existing
        public int EventId { get; set; } = -1;
        public string? EventName { get; set; }
        public LogLevel Level { get; set; } = LogLevel.None;
        public string Message { get; set; } = "";
        public bool SkipEnabledCheck { get; 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.

  4. added and removed
    needs-area-labelAn area label is needed to ensure this gets routed to the appropriate area owners
    on Jun 8, 2023
  5. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    partner-impactThis issue impacts a partner who needs to be kept updated
    on Jun 8, 2023
  6. tarekgh commented on Jun 8, 2023

    @tarekgh
    Member

    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.

     public LoggerMessageAttribute(int eventId, LogLevel level)
     public LoggerMessageAttribute(int eventId, string message)
     public LoggerMessageAttribute(int eventide)
  7. geeknoid commented on Jun 8, 2023

    @geeknoid
    Member

    @tarekgh I hate it when people point out logical flaws in my stuff :-)

    Yeah, I suppose it would be reasonable to not include those.

  8. changed the title [-]Add additional LoggerMethodAttribute constructors[/-] [+]Add additional LoggerMessageAttribute constructors[/+] on Jun 9, 2023
  9. noahfalk commented on Jun 9, 2023

    @noahfalk
    MemberAuthor

    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.

  10. tarekgh commented on Jun 9, 2023

    @tarekgh
    Member

    @noahfalk what you are referring to is the source gen diagnostic SYSLIB1006 which we already changed it to be just info instead of warning

    #72263
    #85581

    We may consider changing the code to ignore the default event id -1 and not produce any warning or info for that Id.

    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.

  11. added
    blockingMarks issues that we want to fast track in order to unblock other important work
    on Jun 10, 2023
  12. 3 remaining items

  13. added
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    on Jun 13, 2023
  14. geeknoid commented on Jun 13, 2023

    @geeknoid
    Member

    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:

    internal static class Logging
    {
        [LoggerMessage(LogLevel.Information)]
        void CreateRecord(this ILogger logger, string recordId);
    
        [LoggerMessage(LogLevel.Debug)]
        void DeleteRecord(this ILogger logger, string recordId);
    
        [LoggerMessage("A record is being skipped: {recordId}")]
        void SkipRecord(this ILogger logger, string recordId);
    
        [LoggerMessage(LogLevel.Warning, "I am a broken record: {recordId}")]
        void BrokenRecord(this ILogger logger, string recordId);
    }

    As opposed to the more verbose:

    internal static class Logging
    {
        [LoggerMessage(LogLevel = LogLevel.Information)]
        void CreateRecord(this ILogger logger, string recordId);
    
        [LoggerMessage(LogLevel = LogLevel.Debug)]
        void DeleteRecord(this ILogger logger, string recordId);
    
        [LoggerMessage(Messgae = "A record is being skipped: {recordId}")]
        void SkipRecord(this ILogger logger, string recordId);
    
        [LoggerMessage(LogLevel = LogLevel.Warning, Message = "I am a broken record: {recordId}")]
        void BrokenRecord(this ILogger logger, string recordId);
    }

    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.

  15. noahfalk commented on Jun 13, 2023

    @noahfalk
    MemberAuthor

    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.

  16. added
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    and removed
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    on Jun 13, 2023
  17. tarekgh commented on Jun 13, 2023

    @tarekgh
    Member

    Marked as ready for review as @geeknoid want to discuss it one more time after he added more info to the issue.

  18. bartonjs commented on Jun 15, 2023

    @bartonjs
    Member

    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.

    namespace Microsoft.Extensions.Logging;
    
    public sealed partial class LoggerMessageAttribute : Attribute
    {
        // Existing:
        // public LoggerMessageAttribute();
        // public LoggerMessageAttribute(int eventId, LogLevel level, string message);
    
        public LoggerMessageAttribute(LogLevel level, string message);
        public LoggerMessageAttribute(LogLevel level);
        public LoggerMessageAttribute(string message);
    }
  19. added
    api-approvedAPI was approved in API review, it can be implemented
    and removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    blockingMarks issues that we want to fast track in order to unblock other important work
    api-ready-for-reviewAPI is ready for review, it is NOT ready for implementation
    on Jun 15, 2023
  20. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Jun 18, 2023
  21. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Jun 18, 2023
  22. ghost locked as resolved and limited conversation to collaborators on Jul 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-Extensions-Loggingpartner-impactThis issue impacts a partner who needs to be kept updated

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions