books/backend/Books.Api/Logging/SubscribeAsynchronousToDecorator.cs
Nicolaj Hartmann 66f6fa138d Initial commit: Books accounting system with EventFlow CQRS
Backend (.NET 10):
- EventFlow CQRS/Event Sourcing with PostgreSQL
- GraphQL.NET API with mutations and queries
- Custom ReadModelSqlGenerator for snake_case PostgreSQL columns
- Hangfire for background job processing
- Integration tests with isolated test databases

Frontend (React/Vite):
- Initial project structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 02:52:30 +01:00

48 lines
1.7 KiB
C#

using System.Diagnostics;
using EventFlow.Aggregates;
using EventFlow.Core;
using EventFlow.Subscribers;
namespace Books.Api.Logging;
public class SubscribeAsynchronousToDecorator<TAggregate, TIdentity, TEvent>(
ISubscribeAsynchronousTo<TAggregate, TIdentity, TEvent> inner,
ILogger<SubscribeAsynchronousToDecorator<TAggregate, TIdentity, TEvent>> logger)
: ISubscribeAsynchronousTo<TAggregate, TIdentity, TEvent>
where TAggregate : IAggregateRoot<TIdentity>
where TIdentity : IIdentity
where TEvent : IAggregateEvent<TAggregate, TIdentity>
{
public async Task HandleAsync(
IDomainEvent<TAggregate, TIdentity, TEvent> domainEvent,
CancellationToken cancellationToken)
{
var eventName = typeof(TEvent).Name;
var handlerName = inner.GetType().Name;
var aggregateId = domainEvent.AggregateIdentity.Value;
logger.LogDebug(
"Handling {EventName} for {AggregateId} with {HandlerName}",
eventName, aggregateId, handlerName);
var stopwatch = Stopwatch.StartNew();
try
{
await inner.HandleAsync(domainEvent, cancellationToken);
stopwatch.Stop();
logger.LogInformation(
"Handled {EventName} for {AggregateId} with {HandlerName} in {ElapsedMs}ms",
eventName, aggregateId, handlerName, stopwatch.ElapsedMilliseconds);
}
catch (Exception ex)
{
stopwatch.Stop();
logger.LogError(ex,
"Failed to handle {EventName} for {AggregateId} with {HandlerName} after {ElapsedMs}ms",
eventName, aggregateId, handlerName, stopwatch.ElapsedMilliseconds);
throw;
}
}
}