CA1873:避免可能成本高昂的日志记录

资产 价值
规则 ID CA1873
标题 避免可能成本高昂的日志记录
类别 性能
修复是中断修复还是非中断修复 Non-breaking
在 .NET 10 中默认启用 作为建议

原因

在许多情况下,日志记录被禁用或设置为日志级别,这会导致对日志记录参数进行不必要的评估。

规则说明

调用日志记录方法时,无论是否启用日志记录级别,都会评估其参数。 这可能会导致执行成本高昂的作,即使不会写入日志消息也是如此。 为了获得更好的性能,请使用检查来IsEnabled保护昂贵的日志记录调用,或使用属性的源生成的日志记录LoggerMessageAttribute

如何修复违规行为

若要修复此规则的冲突,请使用以下方法之一:

  • 使用检查来 IsEnabled保护日志记录调用。
  • 将源生成的日志记录与属性一 LoggerMessageAttribute 起使用。
  • 确保除非必要,否则不会在日志记录参数中执行昂贵的作。

Example

以下代码片段显示了 CA1873 的冲突:

class ViolationExample
{
    private readonly ILogger _logger;

    public ViolationExample(ILogger<ViolationExample> 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 });
    }
}
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

以下代码片段使用源生成的日志记录修复了冲突:

partial class FixExample
{
    private readonly ILogger _logger;

    public FixExample(ILogger<FixExample> 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);
}
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

    <LoggerMessage(Level:=LogLevel.Debug, Message:="Processing {Data} items")>
    Private Partial Sub LogProcessingData(data As Integer())
    End Sub

    <LoggerMessage(Level:=LogLevel.Trace, Message:="Data: Count={Count}, Items={Items}")>
    Private Partial Sub LogTraceData(count As Integer, items As Integer())
    End Sub
End Class

何时禁止显示警告

如果性能不关心或日志记录参数不涉及昂贵的作,则禁止显示此规则的警告是安全的。

禁止显示警告

如果只想抑制单个冲突,请将预处理器指令添加到源文件以禁用该规则,然后重新启用该规则。

#pragma warning disable CA1873
// The code that's violating the rule is on this line.
#pragma warning restore CA1873

若要禁用文件、文件夹或项目的规则,请在none中将其严重性设置为

[*.{cs,vb}]
dotnet_diagnostic.CA1873.severity = none

有关详细信息,请参阅 如何禁止显示代码分析警告

另请参阅