dotnet-cqrs/Svrnty.CQRS.Events/Logging/EventStreamLoggerExtensions.cs

420 lines
14 KiB
C#

using System;
using Svrnty.CQRS.Events.Subscriptions;
using Svrnty.CQRS.Events.Abstractions.Subscriptions;
using Microsoft.Extensions.Logging;
namespace Svrnty.CQRS.Events.Logging;
/// <summary>
/// High-performance structured logging extensions for event streaming operations.
/// </summary>
/// <remarks>
/// <para>
/// <strong>Phase 6 Feature:</strong>
/// Uses LoggerMessage source generators for zero-allocation logging with structured data.
/// All log messages include correlation IDs and event metadata for distributed tracing.
/// </para>
/// <para>
/// <strong>Benefits:</strong>
/// - Near-zero allocation logging (compiled delegates)
/// - Strongly-typed parameters with compile-time safety
/// - Automatic correlation ID propagation
/// - Consistent log structure across all event streaming operations
/// </para>
/// </remarks>
public static partial class EventStreamLoggerExtensions
{
// ========================================================================
// STREAM LIFECYCLE EVENTS
// ========================================================================
/// <summary>
/// Logs when a new stream is created.
/// </summary>
[LoggerMessage(
EventId = 1001,
Level = LogLevel.Information,
Message = "Stream created: {StreamName}, Type={StreamType}, Scope={StreamScope}, DeliverySemantics={DeliverySemantics}")]
public static partial void LogStreamCreated(
this ILogger logger,
string streamName,
string streamType,
string streamScope,
string deliverySemantics);
/// <summary>
/// Logs when a stream is deleted.
/// </summary>
[LoggerMessage(
EventId = 1002,
Level = LogLevel.Warning,
Message = "Stream deleted: {StreamName}")]
public static partial void LogStreamDeleted(
this ILogger logger,
string streamName);
// ========================================================================
// SUBSCRIPTION LIFECYCLE EVENTS
// ========================================================================
/// <summary>
/// Logs when a new subscription is registered.
/// </summary>
[LoggerMessage(
EventId = 2001,
Level = LogLevel.Information,
Message = "Subscription registered: {SubscriptionId}, Stream={StreamName}, Mode={SubscriptionMode}")]
public static partial void LogSubscriptionRegistered(
this ILogger logger,
string subscriptionId,
string streamName,
string subscriptionMode);
/// <summary>
/// Logs when a subscription is unregistered.
/// </summary>
[LoggerMessage(
EventId = 2002,
Level = LogLevel.Information,
Message = "Subscription unregistered: {SubscriptionId}, Stream={StreamName}")]
public static partial void LogSubscriptionUnregistered(
this ILogger logger,
string subscriptionId,
string streamName);
/// <summary>
/// Logs when a subscription is paused.
/// </summary>
[LoggerMessage(
EventId = 2003,
Level = LogLevel.Warning,
Message = "Subscription paused: {SubscriptionId}, Reason={Reason}")]
public static partial void LogSubscriptionPaused(
this ILogger logger,
string subscriptionId,
string reason);
/// <summary>
/// Logs when a subscription is resumed.
/// </summary>
[LoggerMessage(
EventId = 2004,
Level = LogLevel.Information,
Message = "Subscription resumed: {SubscriptionId}")]
public static partial void LogSubscriptionResumed(
this ILogger logger,
string subscriptionId);
// ========================================================================
// CONSUMER LIFECYCLE EVENTS
// ========================================================================
/// <summary>
/// Logs when a consumer connects to a subscription.
/// </summary>
[LoggerMessage(
EventId = 3001,
Level = LogLevel.Information,
Message = "Consumer connected: {ConsumerId}, Subscription={SubscriptionId}, Stream={StreamName}")]
public static partial void LogConsumerConnected(
this ILogger logger,
string consumerId,
string subscriptionId,
string streamName);
/// <summary>
/// Logs when a consumer disconnects from a subscription.
/// </summary>
[LoggerMessage(
EventId = 3002,
Level = LogLevel.Information,
Message = "Consumer disconnected: {ConsumerId}, Subscription={SubscriptionId}, Stream={StreamName}")]
public static partial void LogConsumerDisconnected(
this ILogger logger,
string consumerId,
string subscriptionId,
string streamName);
/// <summary>
/// Logs when a consumer's offset is reset.
/// </summary>
[LoggerMessage(
EventId = 3003,
Level = LogLevel.Warning,
Message = "Consumer offset reset: {ConsumerId}, Subscription={SubscriptionId}, OldOffset={OldOffset}, NewOffset={NewOffset}")]
public static partial void LogConsumerOffsetReset(
this ILogger logger,
string consumerId,
string subscriptionId,
long oldOffset,
long newOffset);
/// <summary>
/// Logs when a consumer is detected as lagging.
/// </summary>
[LoggerMessage(
EventId = 3004,
Level = LogLevel.Warning,
Message = "Consumer lagging: {ConsumerId}, Subscription={SubscriptionId}, Lag={Lag} events")]
public static partial void LogConsumerLagging(
this ILogger logger,
string consumerId,
string subscriptionId,
long lag);
/// <summary>
/// Logs when a consumer is detected as stalled (no progress).
/// </summary>
[LoggerMessage(
EventId = 3005,
Level = LogLevel.Error,
Message = "Consumer stalled: {ConsumerId}, Subscription={SubscriptionId}, TimeSinceUpdate={TimeSinceUpdate}, Lag={Lag}")]
public static partial void LogConsumerStalled(
this ILogger logger,
string consumerId,
string subscriptionId,
TimeSpan timeSinceUpdate,
long lag);
// ========================================================================
// EVENT PUBLISHING
// ========================================================================
/// <summary>
/// Logs when an event is published to a stream.
/// </summary>
[LoggerMessage(
EventId = 4001,
Level = LogLevel.Debug,
Message = "Event published: {EventId}, Type={EventType}, Stream={StreamName}, CorrelationId={CorrelationId}")]
public static partial void LogEventPublished(
this ILogger logger,
string eventId,
string eventType,
string streamName,
string? correlationId);
/// <summary>
/// Logs when a batch of events is published to a stream.
/// </summary>
[LoggerMessage(
EventId = 4002,
Level = LogLevel.Debug,
Message = "Event batch published: {EventCount} events, Stream={StreamName}")]
public static partial void LogEventBatchPublished(
this ILogger logger,
int eventCount,
string streamName);
/// <summary>
/// Logs when event publishing fails.
/// </summary>
[LoggerMessage(
EventId = 4003,
Level = LogLevel.Error,
Message = "Event publish failed: EventId={EventId}, Type={EventType}, Stream={StreamName}, Error={ErrorMessage}")]
public static partial void LogEventPublishFailed(
this ILogger logger,
string eventId,
string eventType,
string streamName,
string errorMessage,
Exception exception);
// ========================================================================
// EVENT CONSUMPTION
// ========================================================================
/// <summary>
/// Logs when an event is successfully consumed.
/// </summary>
[LoggerMessage(
EventId = 5001,
Level = LogLevel.Debug,
Message = "Event consumed: {EventId}, Type={EventType}, Subscription={SubscriptionId}, Consumer={ConsumerId}, Duration={DurationMs}ms")]
public static partial void LogEventConsumed(
this ILogger logger,
string eventId,
string eventType,
string subscriptionId,
string consumerId,
long durationMs);
/// <summary>
/// Logs when event consumption fails.
/// </summary>
[LoggerMessage(
EventId = 5002,
Level = LogLevel.Error,
Message = "Event consumption failed: {EventId}, Type={EventType}, Subscription={SubscriptionId}, Consumer={ConsumerId}, Error={ErrorMessage}")]
public static partial void LogEventConsumptionFailed(
this ILogger logger,
string eventId,
string eventType,
string subscriptionId,
string consumerId,
string errorMessage,
Exception exception);
/// <summary>
/// Logs when an event is being retried.
/// </summary>
[LoggerMessage(
EventId = 5003,
Level = LogLevel.Warning,
Message = "Event retry: {EventId}, Type={EventType}, Subscription={SubscriptionId}, Attempt={AttemptNumber}/{MaxAttempts}")]
public static partial void LogEventRetry(
this ILogger logger,
string eventId,
string eventType,
string subscriptionId,
int attemptNumber,
int maxAttempts);
/// <summary>
/// Logs when an event is sent to the dead letter queue.
/// </summary>
[LoggerMessage(
EventId = 5004,
Level = LogLevel.Error,
Message = "Event sent to dead letter queue: {EventId}, Type={EventType}, Subscription={SubscriptionId}, Reason={Reason}")]
public static partial void LogEventDeadLettered(
this ILogger logger,
string eventId,
string eventType,
string subscriptionId,
string reason);
// ========================================================================
// SCHEMA EVOLUTION
// ========================================================================
/// <summary>
/// Logs when an event schema is registered.
/// </summary>
[LoggerMessage(
EventId = 6001,
Level = LogLevel.Information,
Message = "Schema registered: {SchemaName}, Version={Version}, EventType={EventType}")]
public static partial void LogSchemaRegistered(
this ILogger logger,
string schemaName,
int version,
string eventType);
/// <summary>
/// Logs when an event is upcast to a newer version.
/// </summary>
[LoggerMessage(
EventId = 6002,
Level = LogLevel.Debug,
Message = "Event upcast: {EventId}, Schema={SchemaName}, FromVersion={FromVersion}, ToVersion={ToVersion}")]
public static partial void LogEventUpcast(
this ILogger logger,
string eventId,
string schemaName,
int fromVersion,
int toVersion);
/// <summary>
/// Logs when upcasting fails.
/// </summary>
[LoggerMessage(
EventId = 6003,
Level = LogLevel.Error,
Message = "Event upcast failed: {EventId}, Schema={SchemaName}, FromVersion={FromVersion}, ToVersion={ToVersion}, Error={ErrorMessage}")]
public static partial void LogEventUpcastFailed(
this ILogger logger,
string eventId,
string schemaName,
int fromVersion,
int toVersion,
string errorMessage,
Exception exception);
// ========================================================================
// EXACTLY-ONCE DELIVERY
// ========================================================================
/// <summary>
/// Logs when a duplicate event is detected and skipped.
/// </summary>
[LoggerMessage(
EventId = 7001,
Level = LogLevel.Debug,
Message = "Duplicate event skipped: {EventId}, Type={EventType}, Subscription={SubscriptionId}")]
public static partial void LogDuplicateEventSkipped(
this ILogger logger,
string eventId,
string eventType,
string subscriptionId);
/// <summary>
/// Logs when deduplication state is cleaned up.
/// </summary>
[LoggerMessage(
EventId = 7002,
Level = LogLevel.Debug,
Message = "Deduplication cleanup: Removed {Count} expired entries")]
public static partial void LogDeduplicationCleanup(
this ILogger logger,
int count);
// ========================================================================
// CROSS-SERVICE DELIVERY
// ========================================================================
/// <summary>
/// Logs when an event is sent to an external service via message broker.
/// </summary>
[LoggerMessage(
EventId = 8001,
Level = LogLevel.Information,
Message = "Event sent to external service: {EventId}, Type={EventType}, Exchange={Exchange}, RoutingKey={RoutingKey}")]
public static partial void LogEventSentExternal(
this ILogger logger,
string eventId,
string eventType,
string exchange,
string routingKey);
/// <summary>
/// Logs when an event is received from an external service.
/// </summary>
[LoggerMessage(
EventId = 8002,
Level = LogLevel.Information,
Message = "Event received from external service: {EventId}, Type={EventType}, Queue={QueueName}")]
public static partial void LogEventReceivedExternal(
this ILogger logger,
string eventId,
string eventType,
string queueName);
/// <summary>
/// Logs when external message broker connection is established.
/// </summary>
[LoggerMessage(
EventId = 8003,
Level = LogLevel.Information,
Message = "Connected to message broker: {BrokerType}, Host={Host}")]
public static partial void LogMessageBrokerConnected(
this ILogger logger,
string brokerType,
string host);
/// <summary>
/// Logs when external message broker connection is lost.
/// </summary>
[LoggerMessage(
EventId = 8004,
Level = LogLevel.Error,
Message = "Message broker connection lost: {BrokerType}, Host={Host}, Error={ErrorMessage}")]
public static partial void LogMessageBrokerDisconnected(
this ILogger logger,
string brokerType,
string host,
string errorMessage,
Exception? exception);
}