package decorator import ( "context" "fmt" "log/slog" "time" "git.loyso.art/frx/kurious/internal/common/xcontext" ) type commandLoggingDecorator[T any] struct { base CommandHandler[T] log *slog.Logger } func (c commandLoggingDecorator[T]) Handle(ctx context.Context, cmd T) (err error) { handlerName := getTypeName[T]() ctx = xcontext.WithLogFields(ctx, slog.String("handler", handlerName)) xcontext.LogDebug(ctx, c.log, "executing command") start := time.Now() defer func() { elapsed := slog.Duration("elapsed", time.Since(start)) if err == nil { xcontext.LogInfo(ctx, c.log, "command executed successfuly", elapsed) } else { xcontext.LogError(ctx, c.log, "command execution failed", elapsed, slog.Any("err", err)) } }() return c.base.Handle(ctx, cmd) } type queryLoggingDecorator[Q, U any] struct { base QueryHandler[Q, U] log *slog.Logger } func (q queryLoggingDecorator[Q, U]) Handle(ctx context.Context, query Q) (entity U, err error) { handlerName := getTypeName[Q]() ctx = xcontext.WithLogFields(ctx, slog.String("handler", handlerName)) xcontext.LogDebug(ctx, q.log, "executing command") start := time.Now() defer func() { elapsed := slog.Duration("elapsed", time.Since(start)) if err == nil { xcontext.LogInfo(ctx, q.log, "command executed successfuly", elapsed) } else { xcontext.LogError(ctx, q.log, "command execution failed", elapsed, slog.Any("err", err)) } }() return q.base.Handle(ctx, query) } func getTypeName[T any]() string { var t T out := fmt.Sprintf("%T", t) return out }