Possibilties to add Logging for Notifications
meierhoeferjannis opened this issue · 5 comments
With the MediatR library i used a Decorator for the NotificationHandler. The Purpose was to add logging to these Handlers. Usually you would use a Pipeline for this, but as far as i know you can not use Pipelines with Notifications.
In MediatR you could tell him to ignore the Decorator ( because it implements the INotificationHandler Interface and would usually get registered), via the configuration. Sample shown below.
services.AddMediatR(configuration =>
{
configuration.TypeEvaluator = type => type != typeof(LoggingDecorator<>);
configuration.RegisterServicesFromAssembly(ApplicationAssembly.Assembly);
});
internal sealed class LoggingDecorator<TNotification>:INotificationHandler<TNotification>
where TNotification : INotification
{
private readonly INotificationHandler<TNotification> _Inner;
private readonly ILogger<LoggingDecorator<TNotification>> _Logger;
public LoggingDecorator(INotificationHandler<TNotification> inner, ILogger<LoggingDecorator<TNotification>> logger)
{
_Inner = inner;
_Logger = logger;
}
public async ValueTask Handle(TNotification notification, CancellationToken cancellationToken)
{
_Logger.LogInformation("Starting notification {@Notification}, {@DateTimeUtc}", typeof(TNotification),
DateTime.UtcNow);
try
{
await _Inner.Handle(notification, cancellationToken);
}
catch (Exception e)
{
_Logger.LogCritical(e, "Exceptional Error: {@Message}", e.Message);
}
_Logger.LogInformation("Completed notification {@Notification}, {@DateTimeUtc}", typeof(TNotification),
DateTime.UtcNow);
}
}
When you dont do this you get a Circular Dependency. Is there a way to achieve something similar with this Library? Btw if there is a better way to achieve logging in the NotificationHandlers let me know :D
Hi!
I added a sample showing the various ways you can handle notifications. Notably for doing cross cutting concerns such as logging, you can either use a generic handlers like the one you have above, or just handle INotification
which is also supported. See sample code:
Mediator/samples/Notifications/Program.cs
Lines 32 to 62 in 3c6326e
Code output:
$ dotnet run
Publishing!
-----------------------------------
CatchAllNotificationHandler - e9c1302b-0eab-4193-8445-ab70a93265d6
ConcreteNotificationHandler - e9c1302b-0eab-4193-8445-ab70a93265d6
GenericNotificationHandler`1 - e9c1302b-0eab-4193-8445-ab70a93265d6
-----------------------------------
Finished publishing!
Thank you very much for the reply!
I don't know if I miss something, but the CatchAllNotificationHandler and the GenericNotificationHandler don't handle all the use cases a decorator can handle.
Yes they get always called when a Notification is published but if you want to log when the notification is completed you would need to implement the logging logic in every concrete handler or publish something like a NotificationFinishedNotification, which is logged by a GenericNotificationHandler for example.
Also, if you want to add Exception Handling and Logging you would need to add the Logic in every concrete Handler.
With a decorator you could avoid this. I'm pretty sure you are a more experienced Programmer than I am, and if you say my approach is kind a wrong or violates some kind of programming principle, please let me know.
So would it be possible to enhance the library that Decorators can be used? If so, I would try to implement the logic myself and provide a PR :)
Woops yeah I understand now, I completely misssed your point, sorry 😄
Does this commit help? It lets you remove specific registrations... I think the open generic implementation for notifications is similar to the one in MediatR, but not sure. I'll have a look at this soon
Hi,
yeah, that commit helped a lot! I experimented a bit and found a solution.
var decorator = services.Where(t => t.ImplementationType == typeof(LoggingDecorator<>)); services.Remove(decorator.FirstOrDefault());
With removing the Decorator from the ServiceCollection it works! Thanks a lot and keep up the great work :D
Thats great! Thanks for your patience and kindness 😄