/// <summary> /// In addition to forwarding all calls from the underlying Diagnostic Listener to the specified <c>eventObserver</c>, /// the <c>eventObserver</c>'s <c>OnCompleted()</c> handler will be called if the DiagnosticSource-assembly is unloaded /// or dynamically swapped for another version. This allows subscribers to know that no more events are coming. /// To handle such case, it is recommended to give up on the existing subscription and to schedule a from-scratch /// re-subscription on a timer after a short time period. Such delay ensures that the new assembly version is loaded by then. /// Notably, a few events will be lost. This is an explicit design decision in the context of the fact that assembly /// unloads are extremely rare. /// If the IDisposable returned by this method is disposed, then the above-described notification will not be delivered. /// </summary> /// <remarks> /// Consider using <c>Datadog.Util.ObserverAdapter</c> in shared sources to conveniently create observers suitable for this API. /// </remarks> public IDisposable SubscribeToEvents(IObserver <KeyValuePair <string, object> > eventObserver, Func <string, object, object, bool> isEventEnabledFilter) { if (_diagnosticListenerInstance == null) { return(NoOpSingeltons.EventSubscription); } Validate.NotNull(eventObserver, nameof(eventObserver)); // isEventEnabledFilter may be null DynamicInvoker_DiagnosticListener invoker = null; try { invoker = _dynamicInvokerHandle.GetInvoker(); IDisposable eventsSubscription = invoker.Call.Subscribe(_diagnosticListenerInstance, eventObserver, isEventEnabledFilter); Action <DiagnosticSourceAssembly.IDynamicInvoker> invokerInvalidatedAction = (invkr) => { // DiagnosticListener does NOT call OnCompleted when the subscription is disposed. So we DO need to call it here: eventObserver.OnCompleted(); eventsSubscription.Dispose(); }; DynamicInvokerHandle <DynamicInvoker_DiagnosticListener> invokerHandle = _dynamicInvokerHandle; IDisposable invokerInvalidatedActionSub = invokerHandle.SubscribeInvalidatedListener(invokerInvalidatedAction); IDisposable eventsSubscriptionWrapper = new Disposables.Action(() => { invokerInvalidatedActionSub.Dispose(); eventsSubscription.Dispose(); }); return(eventsSubscriptionWrapper); } catch (Exception ex) { throw LogAndRethrowStubInvocationError(ex, nameof(DynamicInvoker_DiagnosticListener.StubbedApis.Subscribe), isStaticApi: false, invoker?.TargetType); } }
/// <summary> /// In addition to forwarding all calls from the underlying Diagnostic Source collection to the specified <c>diagnosticSourcesObserver</c>, /// the <c>diagnosticSourcesObserver</c>'s <c>OnCompleted()</c> handler will be called if the DiagnosticSource-assembly is unloaded /// or dynamically swapped for another version. This allows subscribers to know that no more events are coming. /// To handle such case, it is recommended to give up on the existing subscription and to schedule a from-scratch /// re-subscription on a timer after a short time period. Such delay ensures that the new assembly version is loaded by then. /// Notably, a few events will be lost. This is an explicit design decision in the context of the fact that assembly /// unloads are extremely rare. /// If the IDisposable returned by this method is disposed, then the above-described notification will not be delivered. /// </summary> /// <remarks>Consider using <c>Datadog.Util.ObserverAdapter</c> in shared sources to conveniently create observers suitable for this API.</remarks> public static IDisposable SubscribeToAllSources(IObserver <DiagnosticListenerStub> diagnosticSourcesObserver) { Validate.NotNull(diagnosticSourcesObserver, nameof(diagnosticSourcesObserver)); DynamicInvoker_DiagnosticListener invoker = null; try { invoker = DynamicInvoker.Current.DiagnosticListener; IObservable <object> allSourcesObservable = invoker.Call.get_AllListeners(); IObserver <object> observerAdapter = new DiagnosticListenerToStubObserverAdapter(diagnosticSourcesObserver); IDisposable dsSubscription = allSourcesObservable.Subscribe(observerAdapter); Action <DiagnosticSourceAssembly.IDynamicInvoker> invokerInvalidatedAction = (invkr) => { // DiagnosticListener calls OnCompleted when the subscription is disposed. So we do NOT need to call it here: // observerAdapter.OnCompleted(); dsSubscription.Dispose(); }; DynamicInvokerHandle <DynamicInvoker_DiagnosticListener> invokerHandle = invoker.Handle; IDisposable invokerInvalidatedActionSub = invokerHandle.SubscribeInvalidatedListener(invokerInvalidatedAction); IDisposable dsSubscriptionWrapper = new Disposables.Action(() => { invokerInvalidatedActionSub.Dispose(); dsSubscription.Dispose(); }); return(dsSubscriptionWrapper); } catch (Exception ex) { throw LogAndRethrowStubInvocationError(ex, invoker?.GetType(), nameof(DynamicInvoker_DiagnosticListener.StubbedApis.get_AllListeners), invoker?.TargetType); } }