AdrianStrugala / SolTechnology.Core

Modern redable coding - TaleCode foundation
5 stars 1 forks source link

Create generic LoggingDecorator #1

Closed AdrianStrugala closed 9 months ago

AdrianStrugala commented 2 years ago

The current implementation is as follows:

   public class CommandHandlerLoggingDecorator<TCommand> : ICommandHandler<TCommand> where TCommand : ILoggedOperation, ICommand
    {
        private readonly ICommandHandler<TCommand> _handler;
        private readonly ILogger<ICommandHandler<TCommand>> _logger;

        public CommandHandlerLoggingDecorator(ICommandHandler<TCommand> handler,
            ILogger<ICommandHandler<TCommand>> logger)
        {
            _handler = handler;
            _logger = logger;
        }

        public async Task Handle(TCommand command)
        {
            using (_logger.BeginOperationScope(new KeyValuePair<string, object>(command.LogScope.OperationIdName, command.LogScope.OperationId)))
            {
                _logger.OperationStarted(command.LogScope.OperationName);

                try
                {
                    await _handler.Handle(command);
                    _logger.OperationSucceeded(command.LogScope.OperationName);
                }
                catch (Exception e)
                {
                    _logger.OperationFailed(command.LogScope.OperationName, e);
                    throw;
                }
            }
        }

I would like to remove ICommandHandler and ICommand dependencies. LoggerDecorator should be an abstraction layer with possibility to be easily added for any kind of handler,

mxb007 commented 10 months ago

Hello,

I'd like to confirm my understanding of the issue.

If we eliminate the dependencies on ICommand and ICommandHandler, we'll still need a mechanism to execute the decorated object. This might necessitate another interface, such as IHandler (with a Handle method). Alternatively, might we have to pass a Func via the constructor?

Initially, I was considering something like the following:

public class LoggerDecorator<TInput> : IHandler<TInput>
{
    private readonly IHandler<TInput> _innerHandler;
    private readonly ILogger _logger;

    public LoggerDecorator(IHandler<TInput> innerHandler, ILogger logger)
    {
        _innerHandler = innerHandler;
        _logger = logger;
    }

    public async Task HandleAsync(TInput input)
    {
        using (_logger.BeginOperationScope()
        {
            _logger.OperationStarted();
            try
            {
                await _innerHandler.HandleAsync(input);
                _logger.OperationSucceeded();
            }
            catch (Exception e)
            {
                _logger.OperationFailed(e);
                throw;
            }
        }
    }
}

I also have a question regarding the LogScope. Since it's currently tied to the Command, should we consider a different method for passing the LogScope?

AdrianStrugala commented 9 months ago

done