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..a28c7b39f4425 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/CA1873Example.csproj @@ -0,0 +1,14 @@ + + + + Exe + net10.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..5ba830e4c7869 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/csharp/CA1873Example/Fix.cs @@ -0,0 +1,29 @@ +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. + // 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 {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/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..eb5497f8e1f5e --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/CA1873Example.vbproj @@ -0,0 +1,13 @@ + + + + Exe + CA1873Example + net10.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..27a77712fda08 --- /dev/null +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/ca1873/vb/CA1873Example/Fix.vb @@ -0,0 +1,28 @@ +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. + ' 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(data As Integer()) + 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 +'