Observability

MediatorLite provides built-in observability through logging and OpenTelemetry tracing.

Logging Configuration

Enable/Disable Built-in Logging

services.AddMediatorLite(options =>
{
    options.EnableBuiltInLogging = true;  // Default: true
    options.DefaultLogLevel = LogLevel.Debug;
});

Per-Request Logging Control

// Disable logging for high-frequency queries
[MediatorLogging(Enabled = false)]
public record HighFrequencyQuery : IRequest<Result>;

// Enable payload logging for audit
[MediatorLogging(IncludePayload = true, LogLevel = 2)] // LogLevel.Information
public record AuditableCommand : IRequest<Unit>;

OpenTelemetry Integration

Enable Tracing

services.AddMediatorLite(options =>
{
    options.EnableTracing = true;  // Default: true
});

Configure OpenTelemetry

services.AddOpenTelemetry()
    .WithTracing(builder =>
    {
        builder.AddSource("MediatorLite");  // Add MediatorLite source
        builder.AddConsoleExporter();
    });

Activity Tags

MediatorLite activities include these tags:

Tag Description
mediatorlite.request.type Full type name of request
mediatorlite.response.type Full type name of response
mediatorlite.notification.type Full type name of notification
mediatorlite.handler.type Handler type name
mediatorlite.handler.count Number of notification handlers
mediatorlite.execution.strategy Notification execution strategy
error Boolean indicating error occurred
error.message Error message if applicable

Diagnostic Events

Subscribe to diagnostic events:

DiagnosticListener.AllListeners.Subscribe(listener =>
{
    if (listener.Name == "MediatorLite")
    {
        listener.Subscribe(kvp =>
        {
            switch (kvp.Key)
            {
                case "MediatorLite.RequestStarted":
                    Console.WriteLine($"Request started: {kvp.Value}");
                    break;
                case "MediatorLite.RequestCompleted":
                    Console.WriteLine($"Request completed: {kvp.Value}");
                    break;
            }
        });
    }
});

Available Events

Event Description
MediatorLite.RequestStarted Request handling began
MediatorLite.RequestCompleted Request handling completed
MediatorLite.RequestFailed Request handling failed
MediatorLite.NotificationPublished Notification published
MediatorLite.NotificationHandlerStarted Handler execution started
MediatorLite.NotificationHandlerCompleted Handler execution completed

Custom Logging Behavior

public class DetailedLoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly ILogger<DetailedLoggingBehavior<TRequest, TResponse>> _logger;

    public DetailedLoggingBehavior(ILogger<DetailedLoggingBehavior<TRequest, TResponse>> logger)
    {
        _logger = logger;
    }

    public async ValueTask<TResponse> HandleAsync(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken cancellationToken = default)
    {
        using var scope = _logger.BeginScope(new Dictionary<string, object>
        {
            ["RequestType"] = typeof(TRequest).Name,
            ["CorrelationId"] = Guid.NewGuid()
        });

        _logger.LogInformation("Handling {RequestType}: {@Request}", 
            typeof(TRequest).Name, request);

        var stopwatch = Stopwatch.StartNew();

        try
        {
            var response = await next();
            stopwatch.Stop();

            _logger.LogInformation(
                "Handled {RequestType} in {ElapsedMs}ms: {@Response}",
                typeof(TRequest).Name, stopwatch.ElapsedMilliseconds, response);

            return response;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error handling {RequestType}", typeof(TRequest).Name);
            throw;
        }
    }
}