< Summary

Information
Class: NexMediator.Pipeline.Behaviors.LoggingBehavior<T1, T2>
Assembly: NexMediator.Pipeline
File(s): /home/runner/work/NexMediator/NexMediator/src/NexMediator.Pipeline/Behaviors/LoggingBehavior.cs
Line coverage
70%
Covered lines: 49
Uncovered lines: 21
Coverable lines: 70
Total lines: 124
Line coverage: 70%
Branch coverage
58%
Covered branches: 7
Total branches: 12
Branch coverage: 58.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
.ctor(...)50%22100%
Handle()50%11865.57%

File(s)

/home/runner/work/NexMediator/NexMediator/src/NexMediator.Pipeline/Behaviors/LoggingBehavior.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2using NexMediator.Abstractions.Context;
 3using NexMediator.Abstractions.Interfaces;
 4using System.Diagnostics;
 5
 6namespace NexMediator.Pipeline.Behaviors;
 7
 8/// <summary>
 9/// Pipeline behavior that logs requests and responses,
 10/// optionally including a correlation ID if available.
 11/// </summary>
 12/// <typeparam name="TRequest">The request type.</typeparam>
 13/// <typeparam name="TResponse">The response type.</typeparam>
 14public class LoggingBehavior<TRequest, TResponse> : INexPipelineBehavior<TRequest, TResponse>
 15    where TRequest : INexRequest<TResponse>
 16{
 17    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
 18    private readonly ICorrelationContext? _correlation;
 19
 20    /// <summary>
 21    /// Creates an instance of <see cref="LoggingBehavior{TRequest,TResponse}"/>
 22    /// without correlation support.
 23    /// </summary>
 24    /// <param name="logger">The logger instance from DI.</param>
 625    public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
 626    {
 627        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 528        _correlation = null;
 529    }
 30
 31    /// <summary>
 32    /// Creates an instance of <see cref="LoggingBehavior{TRequest,TResponse}"/>
 33    /// with correlation support.
 34    /// </summary>
 35    /// <param name="logger">The logger instance from DI.</param>
 36    /// <param name="correlation">The correlation context providing an ID.</param>
 37    public LoggingBehavior(
 638        ILogger<LoggingBehavior<TRequest, TResponse>> logger, ICorrelationContext correlation) : this(logger)
 539    {
 540        _correlation = correlation ?? throw new ArgumentNullException(nameof(correlation));
 541    }
 42
 43    /// <inheritdoc/>
 44    public async Task<TResponse> Handle(
 45        TRequest request,
 46        RequestHandlerDelegate<TResponse> next,
 47        CancellationToken cancellationToken)
 448    {
 449        var requestName = typeof(TRequest).Name;
 450        var correlationId = _correlation?.CorrelationId;
 451        var stopwatch = Stopwatch.StartNew();
 52
 53        // Log start of request
 454        if (!string.IsNullOrEmpty(correlationId))
 455        {
 456            _logger.LogInformation(
 457                "Handling {RequestType} started at {StartTime} (CorrelationId: {CorrelationId})",
 458                requestName,
 459                DateTime.UtcNow,
 460                correlationId);
 461        }
 62        else
 063        {
 064            _logger.LogInformation(
 065                "Handling {RequestType} started at {StartTime}",
 066                requestName,
 067                DateTime.UtcNow);
 068        }
 69
 70        try
 471        {
 472            var response = await next();
 373            stopwatch.Stop();
 74
 75            // Log successful completion
 376            if (!string.IsNullOrEmpty(correlationId))
 377            {
 378                _logger.LogInformation(
 379                    "Handled {RequestType} completed in {ElapsedMilliseconds}ms (CorrelationId: {CorrelationId}) with re
 380                    requestName,
 381                    stopwatch.ElapsedMilliseconds,
 382                    correlationId,
 383                    response);
 384            }
 85            else
 086            {
 087                _logger.LogInformation(
 088                    "Handled {RequestType} completed in {ElapsedMilliseconds}ms with response {@Response}",
 089                    requestName,
 090                    stopwatch.ElapsedMilliseconds,
 091                    response);
 092            }
 93
 394            return response;
 95        }
 196        catch (Exception ex)
 197        {
 198            stopwatch.Stop();
 99
 100            // Log error
 1101            if (!string.IsNullOrEmpty(correlationId))
 1102            {
 1103                _logger.LogError(
 1104                    ex,
 1105                    "Error handling {RequestType} after {ElapsedMilliseconds}ms (CorrelationId: {CorrelationId}) {@Reque
 1106                    requestName,
 1107                    stopwatch.ElapsedMilliseconds,
 1108                    correlationId,
 1109                    request);
 1110            }
 111            else
 0112            {
 0113                _logger.LogError(
 0114                    ex,
 0115                    "Error handling {RequestType} after {ElapsedMilliseconds}ms {@Request}",
 0116                    requestName,
 0117                    stopwatch.ElapsedMilliseconds,
 0118                    request);
 0119            }
 120
 1121            throw;
 122        }
 3123    }
 124}