420 lines
14 KiB
C#
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);
|
|
}
|