예제 #1
0
        public DynamicInvoker(string diagnosticSourceAssemblyName, Type diagnosticSourceType, Type diagnosticListenerType)
        {
            Validate.NotNull(diagnosticSourceAssemblyName, nameof(diagnosticSourceAssemblyName));

            _diagnosticSourceAssemblyName = diagnosticSourceAssemblyName;
            _diagnosticSourceInvoker      = new DynamicInvoker_DiagnosticSource(diagnosticSourceType);
            _diagnosticListenerInvoker    = new DynamicInvoker_DiagnosticListener(diagnosticListenerType);

            _invalidationListeners = new DynamicInvokerInvalidationListenersCollection(nameof(DynamicInvoker), this);

            _isValid = 1;
        }
        public static DiagnosticSourceStub CreateNewSource(string diagnosticSourceName)
        {
            Validate.NotNull(diagnosticSourceName, nameof(diagnosticSourceName));

            DynamicInvoker_DiagnosticListener invoker = null;

            try
            {
                invoker = DynamicInvoker.Current.DiagnosticListener;
                object diagnosticListenerInstance = invoker.Call.Ctor(diagnosticSourceName);
                return(DiagnosticSourceStub.Wrap(diagnosticListenerInstance));
            }
            catch (Exception ex)
            {
                throw LogAndRethrowStubInvocationError(ex, invoker?.GetType(), nameof(DynamicInvoker_DiagnosticListener.StubbedApis.Ctor), invoker?.TargetType);
            }
        }
        internal static bool TryWrap(object diagnosticListenerInstance, out DiagnosticListenerStub diagnosticListenerStub)
        {
            if (diagnosticListenerInstance == null)
            {
                diagnosticListenerStub = NoOpSingeltons.DiagnosticListenerStub;
                return(true);
            }

            DynamicInvoker_DiagnosticListener invoker = DynamicInvoker.Current.DiagnosticListener;

            if (invoker != null && invoker.TryGetInvokerHandleForInstance(diagnosticListenerInstance, out DynamicInvokerHandle <DynamicInvoker_DiagnosticListener> handle))
            {
                diagnosticListenerStub = new DiagnosticListenerStub(diagnosticListenerInstance, handle);
                return(true);
            }
            else
            {
                diagnosticListenerStub = NoOpSingeltons.DiagnosticListenerStub;
                return(false);
            }
        }
        /// <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);
            }
        }
        public static DiagnosticListenerStub Wrap(object diagnosticListenerInstance)
        {
            if (diagnosticListenerInstance == null)
            {
                return(NoOpSingeltons.DiagnosticListenerStub);
            }

            DynamicInvoker_DiagnosticListener invoker = null;

            try
            {
                invoker = DynamicInvoker.Current.DiagnosticListener;
                DynamicInvokerHandle <DynamicInvoker_DiagnosticListener> handle = invoker.GetInvokerHandleForInstance(diagnosticListenerInstance);
                return(new DiagnosticListenerStub(diagnosticListenerInstance, handle));
            }
            catch (Exception ex)
            {
                throw ErrorUtil.LogAndRethrowStubInvocationError(ErrorUtil.CannotCreateStubMsg,
                                                                 ex,
                                                                 typeof(DynamicInvoker_DiagnosticListener),
                                                                 invoker?.TargetType,
                                                                 diagnosticListenerInstance);
            }
        }
 internal StubbedApis(DynamicInvoker_DiagnosticListener thisInvoker)
 {
     _thisInvoker     = thisInvoker;
     _cashedDelegates = new CashedDelegates();
 }