From 2d274586b71923f4e6617d5bd7811acc46895fea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:30:40 +0000 Subject: [PATCH 1/4] Initial plan From 7178549a39b1494ad8a69a833e62f843e022ba1b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:38:34 +0000 Subject: [PATCH 2/4] Update CA1873 to recommend source-generated logging with LoggerMessageAttribute Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- .../code-analysis/quality-rules/ca1873.md | 104 ++---------------- .../csharp/CA1873Example/CA1873Example.csproj | 14 +++ .../ca1873/csharp/CA1873Example/Fix.cs | 28 +++++ .../ca1873/csharp/CA1873Example/Program.cs | 2 + .../ca1873/csharp/CA1873Example/Violation.cs | 22 ++++ .../vb/CA1873Example/CA1873Example.vbproj | 13 +++ .../snippets/ca1873/vb/CA1873Example/Fix.vb | 27 +++++ .../ca1873/vb/CA1873Example/Program.vb | 7 ++ .../ca1873/vb/CA1873Example/Violation.vb | 19 ++++ 9 files changed, 139 insertions(+), 97 deletions(-) create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Program.cs create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Violation.cs create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Program.vb create mode 100644 docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Violation.vb diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1873.md b/docs/fundamentals/code-analysis/quality-rules/ca1873.md index 3124289584046..9ccb5b2048069 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca1873.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca1873.md @@ -30,117 +30,27 @@ In many situations, logging is disabled or set to a log level that results in an ## Rule description -When logging methods are called, their arguments are evaluated regardless of whether the logging level is enabled. This can result in expensive operations being executed even when the log message won't be written. For better performance, guard expensive logging calls with a check to or use the `LoggerMessage` pattern. +When logging methods are called, their arguments are evaluated regardless of whether the logging level is enabled. This can result in expensive operations being executed even when the log message won't be written. For better performance, guard expensive logging calls with a check to or use source-generated logging with . ## How to fix violations To fix a violation of this rule, use one of the following approaches: - Guard the logging call with a check to . -- Use the `LoggerMessage` pattern with . +- Use source-generated logging with . - Ensure expensive operations aren't performed in logging arguments unless necessary. ## Example The following code snippet shows violations of CA1873: -```csharp -using Microsoft.Extensions.Logging; - -class Example -{ - private readonly ILogger _logger; - - public Example(ILogger logger) - { - _logger = logger; - } - - public void ProcessData(int[] data) - { - // Violation: expensive operation in logging argument. - _logger.LogDebug($"Processing {string.Join(", ", data)} items"); - - // Violation: object creation in logging argument. - _logger.LogTrace("Data: {Data}", new { Count = data.Length, Items = data }); - } -} -``` - -```vb -Imports Microsoft.Extensions.Logging - -Class Example - Private ReadOnly _logger As ILogger - - Public Sub New(logger As ILogger(Of Example)) - _logger = logger - End Sub - - Public Sub ProcessData(data As Integer()) - ' Violation: expensive operation in logging argument. - _logger.LogDebug($"Processing {String.Join(", ", data)} items") - - ' Violation: object creation in logging argument. - _logger.LogTrace("Data: {Data}", New With {.Count = data.Length, .Items = data}) - End Sub -End Class -``` +:::code language="csharp" source="./snippets/ca1873/csharp/CA1873Example/Violation.cs" id="ViolationExample"::: +:::code language="vb" source="./snippets/ca1873/vb/CA1873Example/Violation.vb" id="ViolationExample"::: -The following code snippet fixes the violations: +The following code snippet fixes the violations by using source-generated logging: -```csharp -using Microsoft.Extensions.Logging; - -class Example -{ - private readonly ILogger _logger; - - public Example(ILogger logger) - { - _logger = logger; - } - - public void ProcessData(int[] data) - { - // Fixed: guard with IsEnabled check. - if (_logger.IsEnabled(LogLevel.Debug)) - { - _logger.LogDebug($"Processing {string.Join(", ", data)} items"); - } - - // Fixed: guard with IsEnabled check. - if (_logger.IsEnabled(LogLevel.Trace)) - { - _logger.LogTrace("Data: {Data}", new { Count = data.Length, Items = data }); - } - } -} -``` - -```vb -Imports Microsoft.Extensions.Logging - -Class Example - Private ReadOnly _logger As ILogger - - Public Sub New(logger As ILogger(Of Example)) - _logger = logger - End Sub - - Public Sub ProcessData(data As Integer()) - ' Fixed: guard with IsEnabled check. - If _logger.IsEnabled(LogLevel.Debug) Then - _logger.LogDebug($"Processing {String.Join(", ", data)} items") - End If - - ' Fixed: guard with IsEnabled check. - If _logger.IsEnabled(LogLevel.Trace) Then - _logger.LogTrace("Data: {Data}", New With {.Count = data.Length, .Items = data}) - End If - End Sub -End Class -``` +:::code language="csharp" source="./snippets/ca1873/csharp/CA1873Example/Fix.cs" id="FixExample"::: +:::code language="vb" source="./snippets/ca1873/vb/CA1873Example/Fix.vb" id="FixExample"::: ## When to suppress warnings diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj new file mode 100644 index 0000000000000..9e1d4ecc0f1a9 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs new file mode 100644 index 0000000000000..a722e38440f7e --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.Logging; + +// +partial class FixExample +{ + private readonly ILogger _logger; + + public FixExample(ILogger logger) + { + _logger = logger; + } + + public void ProcessData(int[] data) + { + // Fixed: use source-generated logging. + LogProcessingData(string.Join(", ", data)); + + // Fixed: use source-generated logging. + LogTraceData(data.Length, data); + } + + [LoggerMessage(Level = LogLevel.Debug, Message = "Processing {Items} items")] + private partial void LogProcessingData(string items); + + [LoggerMessage(Level = LogLevel.Trace, Message = "Data: Count={Count}, Items={Items}")] + private partial void LogTraceData(int count, int[] items); +} +// diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Program.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Program.cs new file mode 100644 index 0000000000000..3751555cbd32d --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Violation.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Violation.cs new file mode 100644 index 0000000000000..35d8a8ad4df59 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Violation.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.Logging; + +// +class ViolationExample +{ + private readonly ILogger _logger; + + public ViolationExample(ILogger logger) + { + _logger = logger; + } + + public void ProcessData(int[] data) + { + // Violation: expensive operation in logging argument. + _logger.LogDebug($"Processing {string.Join(", ", data)} items"); + + // Violation: object creation in logging argument. + _logger.LogTrace("Data: {Data}", new { Count = data.Length, Items = data }); + } +} +// diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj new file mode 100644 index 0000000000000..efcf40c60731d --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj @@ -0,0 +1,13 @@ + + + + Exe + CA1873Example + net9.0 + + + + + + + diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb new file mode 100644 index 0000000000000..549b6a0d240fb --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb @@ -0,0 +1,27 @@ +Imports Microsoft.Extensions.Logging + +' +Partial Class FixExample + Private ReadOnly _logger As ILogger + + Public Sub New(logger As ILogger(Of FixExample)) + _logger = logger + End Sub + + Public Sub ProcessData(data As Integer()) + ' Fixed: use source-generated logging. + LogProcessingData(String.Join(", ", data)) + + ' Fixed: use source-generated logging. + LogTraceData(data.Length, data) + End Sub + + + Private Partial Sub LogProcessingData(items As String) + End Sub + + + Private Partial Sub LogTraceData(count As Integer, items As Integer()) + End Sub +End Class +' diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Program.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Program.vb new file mode 100644 index 0000000000000..46283ca23175e --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Program.vb @@ -0,0 +1,7 @@ +Imports System + +Module Program + Sub Main(args As String()) + Console.WriteLine("Hello World!") + End Sub +End Module diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Violation.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Violation.vb new file mode 100644 index 0000000000000..5de6e46917726 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Violation.vb @@ -0,0 +1,19 @@ +Imports Microsoft.Extensions.Logging + +' +Class ViolationExample + Private ReadOnly _logger As ILogger + + Public Sub New(logger As ILogger(Of ViolationExample)) + _logger = logger + End Sub + + Public Sub ProcessData(data As Integer()) + ' Violation: expensive operation in logging argument. + _logger.LogDebug($"Processing {String.Join(", ", data)} items") + + ' Violation: object creation in logging argument. + _logger.LogTrace("Data: {Data}", New With {.Count = data.Length, .Items = data}) + End Sub +End Class +' From 0a4348a67f8dae8629ee1344a21138388d896128 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 18:41:18 +0000 Subject: [PATCH 3/4] Fix code examples to properly avoid expensive operations in logging Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- .../snippets/ca1873/csharp/CA1873Example/Fix.cs | 7 ++++--- .../quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs index a722e38440f7e..5ba830e4c7869 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs @@ -13,14 +13,15 @@ public FixExample(ILogger logger) public void ProcessData(int[] data) { // Fixed: use source-generated logging. - LogProcessingData(string.Join(", ", data)); + // The data array is passed directly; no expensive operation executed unless log level is enabled. + LogProcessingData(data); // Fixed: use source-generated logging. LogTraceData(data.Length, data); } - [LoggerMessage(Level = LogLevel.Debug, Message = "Processing {Items} items")] - private partial void LogProcessingData(string items); + [LoggerMessage(Level = LogLevel.Debug, Message = "Processing {Data} items")] + private partial void LogProcessingData(int[] data); [LoggerMessage(Level = LogLevel.Trace, Message = "Data: Count={Count}, Items={Items}")] private partial void LogTraceData(int count, int[] items); diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb index 549b6a0d240fb..27a77712fda08 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb @@ -10,14 +10,15 @@ Partial Class FixExample Public Sub ProcessData(data As Integer()) ' Fixed: use source-generated logging. - LogProcessingData(String.Join(", ", data)) + ' The data array is passed directly; no expensive operation executed unless log level is enabled. + LogProcessingData(data) ' Fixed: use source-generated logging. LogTraceData(data.Length, data) End Sub - - Private Partial Sub LogProcessingData(items As String) + + Private Partial Sub LogProcessingData(data As Integer()) End Sub From 619965da7c21cafb7d9be828f6683dd8990978d8 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:01:14 -0800 Subject: [PATCH 4/4] Apply suggestions from code review --- .../snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj | 2 +- .../snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj index 9e1d4ecc0f1a9..a28c7b39f4425 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj @@ -2,7 +2,7 @@ Exe - net9.0 + net10.0 enable enable diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj index efcf40c60731d..eb5497f8e1f5e 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj @@ -3,7 +3,7 @@ Exe CA1873Example - net9.0 + net10.0