Skip to content

Reduce noise from CA1873#51818

Merged
stephentoub merged 1 commit intodotnet:mainfrom
stephentoub:ca1873noise
Nov 20, 2025
Merged

Reduce noise from CA1873#51818
stephentoub merged 1 commit intodotnet:mainfrom
stephentoub:ca1873noise

Conversation

@stephentoub
Copy link
Member

Several improvements to the analyzer:

  • Property accesses are common in logging calls, and property accesses are supposed to be cheap. Avoid raising diagnostics for property accesses.
  • GetType/GetHashCode/GetTimestamp are used reasonably-frequently in logging calls; special-case them to avoid diagnostics for them.
  • The main reason this rule exists is to eliminate cost on hot paths. Generally such hot paths aren't raising warning/error/critical diagnostics, such that the more rare warning/errors don't need as much attention to overheads. As such, I've changed the checks to only kick in by default for information and below, with a configuration switch that can be used to override to what levels it applies.

Several improvements to the analyzer:
- Property accesses are common in logging calls, and property accesses are supposed to be cheap. Avoid raising diagnostics for property accesses.
- GetType() is frequently used in logging calls; special-case it to avoid diagnostics for it.
- The main reason this rule exists is to eliminate cost on hot paths. Generally such hot paths aren't raising warning/error/critical diagnostics, such that the more rare warning/errors don't need as much attention to overheads. As such, I've changed the checks to only kick in by default for information and below, with a configuration switch that can be used to override to what levels it applies.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR reduces noise from analyzer CA1873 (AvoidPotentiallyExpensiveCallWhenLogging) by adding three key improvements: (1) exempting property accesses since they should be cheap, (2) special-casing common trivial methods like GetType/GetHashCode/GetTimestamp that are frequently used in logging, and (3) introducing log level filtering to only analyze logs at Information level and below by default, with a configurable threshold via EditorConfig.

Key Changes

  • Property accesses (without arguments) are now considered cheap and won't trigger diagnostics, though indexer arguments are still validated
  • Trivial methods (object.GetType, object.GetHashCode, Stopwatch.GetTimestamp) are exempted from analysis as they're common in logging and sufficiently cheap
  • By default, only log levels up to Information are analyzed; Warning/Error/Critical levels are skipped unless configured otherwise via dotnet_code_quality.CA1873.max_log_level

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
AvoidPotentiallyExpensiveCallWhenLogging.cs Core analyzer implementation: adds IsTrivialInvocation method to exempt common cheap methods, updates IsPotentiallyExpensive to treat simple property accesses as cheap, adds log level threshold checking with EditorConfig support, refactors RequiredSymbols class to use primary constructor and Dictionary instead of ImmutableDictionary
EditorConfigOptionNames.cs Adds MaxLogLevel constant for the new max_log_level EditorConfig option with proper XML documentation
AvoidPotentiallyExpensiveCallWhenLoggingTests.cs Updates existing tests to reflect new log level behavior (Warning/Error no longer flagged by default), adds comprehensive tests for trivial method exemptions (GetType, GetHashCode, GetTimestamp), adds tests for cast operations, adds extensive tests for log level configuration via EditorConfig, updates test helper methods to support EditorConfig testing

Copy link
Member

@tarekgh tarekgh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks!

@stephentoub
Copy link
Member Author

@jeffhandley, you good with this?

@baronfel
Copy link
Member

This is targeted for 11 because of what main is today - if this reduces false positives we could either try for a Backport for the January 1xx release, or backport to release/10.0.2xx for the February release of that feature band. Thoughts? I expect that given the impact to partner teams we'll want to go for the servicing release.

@stephentoub
Copy link
Member Author

I'm fine with either.

Copy link
Member

@jeffhandley jeffhandley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great; thanks, @stephentoub. And I agree we should backport into 10.0 servicing. I can shepherd that through.

@stephentoub stephentoub merged commit bb4aee4 into dotnet:main Nov 20, 2025
32 of 33 checks passed
@stephentoub stephentoub deleted the ca1873noise branch November 20, 2025 19:41
@stephentoub
Copy link
Member Author

try for a Backport for the January 1xx release

@baronfel, what branch is that?

@baronfel
Copy link
Member

/backport to release/10.0.1xx

That one :)

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx (link to workflow run)

@github-actions
Copy link
Contributor

@baronfel backporting to release/10.0.1xx failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Patch format detection failed.
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

@baronfel
Copy link
Member

@stephentoub that didn't apply cleanly - can you do the manual backport to release/10.0.1xx?

stephentoub added a commit to stephentoub/sdk that referenced this pull request Nov 21, 2025
Several improvements to the analyzer:

- Property accesses are common in logging calls, and property accesses are supposed to be cheap. Avoid raising diagnostics for property accesses.
- GetType/GetHashCode/GetTimestamp are used reasonably-frequently in logging calls; special-case them to avoid diagnostics for them.
- The main reason this rule exists is to eliminate cost on hot paths. Generally such hot paths aren't raising warning/error/critical diagnostics, such that the more rare warning/errors don't need as much attention to overheads. As such, I've changed the checks to only kick in by default for information and below, with a configuration switch that can be used to override to what levels it applies.
@stephentoub
Copy link
Member Author

@akoeplinger, are you aware of any issues with the backport action? A few times now it's failed to backport a change to a 10.0 release branch, but doing the cherry-pick locally has worked fine with zero conflicts.

@jhigh2000
Copy link

Was this fix backported to 10.0.103? I'm still seeing the analyzer light up for logging calls that reference simple property accesses.

@stephentoub
Copy link
Member Author

Was this fix backported to 10.0.103? I'm still seeing the analyzer light up for logging calls that reference simple property accesses.

Is it firing not because of property access but because there's an array allocation?

@jhigh2000
Copy link

No array allocation, just a string property, like

_logger.LogInformation("Parsing category {CategoryName}", category.Name);

logger analyzer hint shows

image image

Is the hint still there by design?

@stephentoub
Copy link
Member Author

But there is an array allocation, you just don't see it in the source. The signature of that overload is:

public static void LogInformation(this ILogger logger, string? message, params object?[] args)

@jhigh2000
Copy link

jhigh2000 commented Feb 15, 2026

Oh that signature 😁Got it. Every overload takes a params object?[] args, so just the cost of logging?
Is there a better alternative? I don't really want to set dotnet_diagnostic.CA1873.severity = silent

Edit: Am I just not understanding what this was supposed to address?

Property accesses are common in logging calls, and property accesses are supposed to be cheap. Avoid raising diagnostics for property accesses.

@stephentoub
Copy link
Member Author

Is there a better alternative?

Guard the call with an IsEnabled check, or use the source generator.

I don't really want to set dotnet_diagnostic.CA1873.severity = silent

The analyzer is only a suggestion by default. You must be raising its level somewhere?

The purpose of the analyzer is to flag work that has non-trivial cost that you're paying for even when logging is disabled. Allocation is such a thing, so it's doing its job. But if you don't want it, don't enable it :)

Edit: Am I just not understanding what this was supposed to address?

That's accurate, and if you were using the source generator, previously passing in a property access would have warned and now it won't. You're not getting a warning because of the property access, you're getting it because of the array allocation.

@jhigh2000
Copy link

That makes sense. Thanks for the explanation @stephentoub, much appreciated!

@akoeplinger
Copy link
Member

@akoeplinger, are you aware of any issues with the backport action? A few times now it's failed to backport a change to a 10.0 release branch, but doing the cherry-pick locally has worked fine with zero conflicts.

@stephentoub looks like I missed the earlier ping but I think I just fixed this with dotnet/arcade#16500, let me know if you still see it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants