11using System ;
22using System . Collections . Concurrent ;
3+ using System . Diagnostics ;
34using System . Linq ;
45using System . Reactive . Disposables ;
56using System . Reactive . Subjects ;
910using System . Threading . Tasks ;
1011using Microsoft . Extensions . DependencyInjection ;
1112using static Merq . Telemetry ;
13+ using Tag = System . Collections . Generic . KeyValuePair < string , object ? > ;
1214
1315namespace Merq ;
1416
@@ -188,7 +190,7 @@ public bool CanHandle(IExecutable command) => canHandleMap.GetOrAdd(GetCommandTy
188190 public void Execute ( ICommand command )
189191 {
190192 var type = GetCommandType ( command ) ;
191- using var activity = StartActivity ( type , Process ) ;
193+ using var activity = StartActivity ( type , Telemetry . Process ) ;
192194
193195 try
194196 {
@@ -220,7 +222,7 @@ public void Execute(ICommand command)
220222 public TResult Execute < TResult > ( ICommand < TResult > command )
221223 {
222224 var type = GetCommandType ( command ) ;
223- using var activity = StartActivity ( type , Process ) ;
225+ using var activity = StartActivity ( type , Telemetry . Process ) ;
224226
225227 try
226228 {
@@ -251,7 +253,7 @@ public TResult Execute<TResult>(ICommand<TResult> command)
251253 public Task ExecuteAsync ( IAsyncCommand command , CancellationToken cancellation = default )
252254 {
253255 var type = GetCommandType ( command ) ;
254- using var activity = StartActivity ( type , Process ) ;
256+ using var activity = StartActivity ( type , Telemetry . Process ) ;
255257
256258 try
257259 {
@@ -284,7 +286,7 @@ public Task ExecuteAsync(IAsyncCommand command, CancellationToken cancellation =
284286 public Task < TResult > ExecuteAsync < TResult > ( IAsyncCommand < TResult > command , CancellationToken cancellation = default )
285287 {
286288 var type = GetCommandType ( command ) ;
287- using var activity = StartActivity ( type , Process ) ;
289+ using var activity = StartActivity ( type , Telemetry . Process ) ;
288290
289291 try
290292 {
@@ -314,41 +316,49 @@ public void Notify<TEvent>(TEvent e)
314316 {
315317 var type = ( e ?? throw new ArgumentNullException ( nameof ( e ) ) ) . GetType ( ) ;
316318 using var activity = StartActivity ( type , Publish ) ;
319+ var watch = Stopwatch . StartNew ( ) ;
317320
318- // TODO: if we prevent Notify for externally produced events, we won't be
319- // able to notify base event subscribers when those events are produced.
320- //var producer = services.GetService<IObservable<TEvent>>();
321- //if (producer != null)
322- // throw new NotSupportedException($"Cannot explicitly notify event {type} because it is externally produced by {producer.GetType()}.");
323-
324- // We call all subjects that are compatible with
325- // the event type, not just concrete event type subscribers.
326- // Also adds as compatible the dynamic conversion ones.
327- var compatible = compatibleSubjects . GetOrAdd ( type , eventType => subjects . Keys
328- . Where ( subjectEventType => subjectEventType . IsAssignableFrom ( eventType ) )
329- . Select ( subjectEventType => subjects [ subjectEventType ] )
330- . Concat ( dynamicSubjects
331- . GetOrAdd ( type . FullName , _ => new ( ) )
332- . Where ( pair => pair . Key != type && pair . Value != null )
333- . Select ( pair => pair . Value ! ) )
334- . ToArray ( ) ) ;
335-
336- foreach ( var subject in compatible )
321+ try
337322 {
338- try
323+ // TODO: if we prevent Notify for externally produced events, we won't be
324+ // able to notify base event subscribers when those events are produced.
325+ //var producer = services.GetService<IObservable<TEvent>>();
326+ //if (producer != null)
327+ // throw new NotSupportedException($"Cannot explicitly notify event {type} because it is externally produced by {producer.GetType()}.");
328+
329+ // We call all subjects that are compatible with
330+ // the event type, not just concrete event type subscribers.
331+ // Also adds as compatible the dynamic conversion ones.
332+ var compatible = compatibleSubjects . GetOrAdd ( type , eventType => subjects . Keys
333+ . Where ( subjectEventType => subjectEventType . IsAssignableFrom ( eventType ) )
334+ . Select ( subjectEventType => subjects [ subjectEventType ] )
335+ . Concat ( dynamicSubjects
336+ . GetOrAdd ( type . FullName , _ => new ( ) )
337+ . Where ( pair => pair . Key != type && pair . Value != null )
338+ . Select ( pair => pair . Value ! ) )
339+ . ToArray ( ) ) ;
340+
341+ foreach ( var subject in compatible )
339342 {
340- subject . OnNext ( e ) ;
341- }
342- catch ( Exception ex )
343- {
344- activity . RecordException ( ex ) ;
345- // TODO: should we swallow the exception and remove the
346- // failing subscribers?
347- // Rethrow original exception to preserve stacktrace.
348- ExceptionDispatchInfo . Capture ( ex ) . Throw ( ) ;
349- throw ;
343+ try
344+ {
345+ subject . OnNext ( e ) ;
346+ }
347+ catch ( Exception ex )
348+ {
349+ activity . RecordException ( ex ) ;
350+ // TODO: should we swallow the exception and remove the
351+ // failing subscribers?
352+ // Rethrow original exception to preserve stacktrace.
353+ ExceptionDispatchInfo . Capture ( ex ) . Throw ( ) ;
354+ throw ;
355+ }
350356 }
351357 }
358+ finally
359+ {
360+ Publishing . Record ( watch . ElapsedMilliseconds , new Tag ( "Event" , type . FullName ) ) ;
361+ }
352362 }
353363
354364 /// <summary>
@@ -487,8 +497,18 @@ void ExecuteCore<TCommand>(TCommand command) where TCommand : ICommand
487497 var handler = services . GetService < ICommandHandler < TCommand > > ( ) ;
488498 if ( handler != null )
489499 {
490- handler . Execute ( command ) ;
491- return ;
500+ var watch = Stopwatch . StartNew ( ) ;
501+ try
502+ {
503+ handler . Execute ( command ) ;
504+ return ;
505+ }
506+ finally
507+ {
508+ Processing . Record ( watch . ElapsedMilliseconds ,
509+ new Tag ( "Command" , typeof ( TCommand ) . FullName ) ,
510+ new Tag ( "Handler" , handler . GetType ( ) . FullName ) ) ;
511+ }
492512 }
493513
494514 // See if we can convert from the TCommand to a compatible type with
@@ -509,7 +529,17 @@ Task ExecuteAsyncCore<TCommand>(TCommand command, CancellationToken cancellation
509529 var handler = services . GetService < IAsyncCommandHandler < TCommand > > ( ) ;
510530 if ( handler != null )
511531 {
512- return handler . ExecuteAsync ( command , cancellation ) ;
532+ var watch = Stopwatch . StartNew ( ) ;
533+ try
534+ {
535+ return handler . ExecuteAsync ( command , cancellation ) ;
536+ }
537+ finally
538+ {
539+ Processing . Record ( watch . ElapsedMilliseconds ,
540+ new Tag ( "Command" , typeof ( TCommand ) . FullName ) ,
541+ new Tag ( "Handler" , handler . GetType ( ) . FullName ) ) ;
542+ }
513543 }
514544
515545 // See if we can convert from the TCommand to a compatible type with
@@ -528,7 +558,19 @@ TResult ExecuteCore<TCommand, TResult>(TCommand command) where TCommand : IComma
528558 {
529559 var handler = services . GetService < ICommandHandler < TCommand , TResult > > ( ) ;
530560 if ( handler != null )
531- return handler . Execute ( command ) ;
561+ {
562+ var watch = Stopwatch . StartNew ( ) ;
563+ try
564+ {
565+ return handler . Execute ( command ) ;
566+ }
567+ finally
568+ {
569+ Processing . Record ( watch . ElapsedMilliseconds ,
570+ new Tag ( "Command" , typeof ( TCommand ) . FullName ) ,
571+ new Tag ( "Handler" , handler . GetType ( ) . FullName ) ) ;
572+ }
573+ }
532574
533575 // See if we can convert from the TCommand to a compatible type with
534576 // a registered command handler
@@ -546,7 +588,19 @@ Task<TResult> ExecuteAsyncCore<TCommand, TResult>(TCommand command, Cancellation
546588 {
547589 var handler = services . GetService < IAsyncCommandHandler < TCommand , TResult > > ( ) ;
548590 if ( handler != null )
549- return handler . ExecuteAsync ( command , cancellation ) ;
591+ {
592+ var watch = Stopwatch . StartNew ( ) ;
593+ try
594+ {
595+ return handler . ExecuteAsync ( command , cancellation ) ;
596+ }
597+ finally
598+ {
599+ Processing . Record ( watch . ElapsedMilliseconds ,
600+ new Tag ( "Command" , typeof ( TCommand ) . FullName ) ,
601+ new Tag ( "Handler" , handler . GetType ( ) . FullName ) ) ;
602+ }
603+ }
550604
551605 // See if we can convert from the TCommand to a compatible type with
552606 // a registered command handler
0 commit comments