/// <summary>
            /// Creates one FilterAndTransform specification from filterAndPayloadSpec starting at 'startIdx' and ending just before 'endIdx'.
            /// This FilterAndTransform will subscribe to DiagnosticSources specified by the specification and forward them to 'eventSource.
            /// For convenience, the 'Next' field is set to the 'next' parameter, so you can easily form linked lists.
            /// </summary>
            public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform next)
            {
                Debug.Assert(filterAndPayloadSpec != null && startIdx >= 0 && startIdx <= endIdx && endIdx <= filterAndPayloadSpec.Length);
                Next         = next;
                _eventSource = eventSource;

                string listenerNameFilter = null;       // Means WildCard.
                string eventNameFilter    = null;       // Means WildCard.
                string activityName       = null;

                var startTransformIdx = startIdx;
                var endEventNameIdx   = endIdx;
                var colonIdx          = filterAndPayloadSpec.IndexOf(':', startIdx, endIdx - startIdx);

                if (0 <= colonIdx)
                {
                    endEventNameIdx   = colonIdx;
                    startTransformIdx = colonIdx + 1;
                }

                // Parse the Source/Event name into listenerNameFilter and eventNameFilter
                var slashIdx = filterAndPayloadSpec.IndexOf('/', startIdx, endEventNameIdx - startIdx);

                if (0 <= slashIdx)
                {
                    listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, slashIdx - startIdx);

                    var atIdx = filterAndPayloadSpec.IndexOf('@', slashIdx + 1, endEventNameIdx - slashIdx - 1);
                    if (0 <= atIdx)
                    {
                        activityName    = filterAndPayloadSpec.Substring(atIdx + 1, endEventNameIdx - atIdx - 1);
                        eventNameFilter = filterAndPayloadSpec.Substring(slashIdx + 1, atIdx - slashIdx - 1);
                    }
                    else
                    {
                        eventNameFilter = filterAndPayloadSpec.Substring(slashIdx + 1, endEventNameIdx - slashIdx - 1);
                    }
                }
                else if (startIdx < endEventNameIdx)
                {
                    listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, endEventNameIdx - startIdx);
                }

                _eventSource.Message("DiagnosticSource: Enabling '" + (listenerNameFilter ?? "*") + "/" + (eventNameFilter ?? "*") + "'");

                // If the transform spec begins with a - it means you don't want implicit transforms.
                if (startTransformIdx < endIdx && filterAndPayloadSpec[startTransformIdx] == '-')
                {
                    _eventSource.Message("DiagnosticSource: suppressing implicit transforms.");
                    _noImplicitTransforms = true;
                    startTransformIdx++;
                }

                // Parse all the explicit transforms, if present
                if (startTransformIdx < endIdx)
                {
                    for (;;)
                    {
                        int specStartIdx = startTransformIdx;
                        int semiColonIdx = filterAndPayloadSpec.LastIndexOf(';', endIdx - 1, endIdx - startTransformIdx);
                        if (0 <= semiColonIdx)
                        {
                            specStartIdx = semiColonIdx + 1;
                        }

                        // Ignore empty specifications.
                        if (specStartIdx < endIdx)
                        {
                            if (_eventSource.IsEnabled(EventLevel.Informational, Keywords.Messages))
                            {
                                _eventSource.Message("DiagnosticSource: Parsing Explicit Transform '" + filterAndPayloadSpec.Substring(specStartIdx, endIdx - specStartIdx) + "'");
                            }

                            _explicitTransforms = new TransformSpec(filterAndPayloadSpec, specStartIdx, endIdx, _explicitTransforms);
                        }
                        if (startTransformIdx == specStartIdx)
                        {
                            break;
                        }
                        endIdx = semiColonIdx;
                    }
                }

                Action <string, string, IEnumerable <KeyValuePair <string, string> > > writeEvent = null;

                if (activityName != null && activityName.Contains("Activity"))
                {
                    MethodInfo writeEventMethodInfo = typeof(DiagnosticSourceEventSource).GetTypeInfo().GetDeclaredMethod(activityName);
                    if (writeEventMethodInfo != null)
                    {
                        // This looks up the activityName (which needs to be a name of an event on DiagnosticSourceEventSource
                        // like Activity1Start and returns that method).   This allows us to have a number of them and this code
                        // just works.
                        try
                        {
                            writeEvent = (Action <string, string, IEnumerable <KeyValuePair <string, string> > >)
                                         writeEventMethodInfo.CreateDelegate(typeof(Action <string, string, IEnumerable <KeyValuePair <string, string> > >), _eventSource);
                        }
                        catch (Exception) { }
                    }
                    if (writeEvent == null)
                    {
                        _eventSource.Message("DiagnosticSource: Could not find Event to log Activity " + activityName);
                    }
                }

                if (writeEvent == null)
                {
#if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT
                    writeEvent = _eventSource.Event;
#else
                    writeEvent = delegate(string sourceName, string eventName, IEnumerable <KeyValuePair <string, string> > arguments)
                    {
                        _eventSource.EventJson(sourceName, eventName, ToJson(arguments));
                    };
#endif
                }

                // Set up a subscription that watches for the given Diagnostic Sources and events which will call back
                // to the EventSource.
                _diagnosticsListenersSubscription = DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(delegate(DiagnosticListener newListener)
                {
                    if (listenerNameFilter == null || listenerNameFilter == newListener.Name)
                    {
                        _eventSource.NewDiagnosticListener(newListener.Name);
                        Predicate <string> eventNameFilterPredicate = null;
                        if (eventNameFilter != null)
                        {
                            eventNameFilterPredicate = (string eventName) => eventNameFilter == eventName;
                        }

                        var subscription = newListener.Subscribe(new CallbackObserver <KeyValuePair <string, object> >(delegate(KeyValuePair <string, object> evnt)
                        {
                            // The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected.
                            // Thus we look for any events that may have snuck through and filter them out before forwarding.
                            if (eventNameFilter != null && eventNameFilter != evnt.Key)
                            {
                                return;
                            }

                            var outputArgs = this.Morph(evnt.Value);
                            var eventName  = evnt.Key;
                            writeEvent(newListener.Name, eventName, outputArgs);
                        }), eventNameFilterPredicate);
                        _liveSubscriptions = new Subscriptions(subscription, _liveSubscriptions);
                    }
                }));
            }
Esempio n. 2
0
            /// <summary>
            /// Creates one FilterAndTransform specification from filterAndPayloadSpec starting at 'startIdx' and ending just before 'endIdx'.
            /// This FilterAndTransform will subscribe to DiagnosticSources specified by the specification and forward them to 'eventSource.
            /// For convenience, the 'Next' field is set to the 'next' parameter, so you can easily form linked lists.
            /// </summary>
            public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform next)
            {
#if DEBUG
                string spec = filterAndPayloadSpec.Substring(startIdx, endIdx - startIdx);
#endif
                Next         = next;
                _eventSource = eventSource;

                string listenerNameFilter = null;       // Means WildCard.
                string eventNameFilter    = null;       // Means WildCard.

                var startTransformIdx = startIdx;
                var endEventNameIdx   = endIdx;
                var colonIdx          = filterAndPayloadSpec.IndexOf(':', startIdx, endIdx - startIdx);
                if (0 <= colonIdx)
                {
                    endEventNameIdx   = colonIdx;
                    startTransformIdx = colonIdx + 1;
                }

                // Parse the Source/Event name into listenerNameFilter and eventNameFilter
                var slashIdx = filterAndPayloadSpec.IndexOf('/', startIdx, endEventNameIdx - startIdx);
                if (0 <= slashIdx)
                {
                    listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, slashIdx - startIdx);
                    eventNameFilter    = filterAndPayloadSpec.Substring(slashIdx + 1, endEventNameIdx - slashIdx - 1);
                }
                else if (startIdx < endEventNameIdx)
                {
                    listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, endEventNameIdx - startIdx);
                }


                _eventSource.Message("DiagnosticSource: Enabling '" + (listenerNameFilter ?? "*") + "/" + (eventNameFilter ?? "*") + "'");

                // If the transform spec begins with a - it means you don't want implicit transforms.
                if (startTransformIdx < endIdx && filterAndPayloadSpec[startTransformIdx] == '-')
                {
                    _eventSource.Message("DiagnosticSource: suppressing implicit transforms.");
                    _noImplicitTransforms = true;
                    startTransformIdx++;
                }

                // Parse all the explicit transforms, if present
                if (startTransformIdx < endIdx)
                {
                    for (;;)
                    {
                        int specStartIdx = startTransformIdx;
                        int semiColonIdx = filterAndPayloadSpec.LastIndexOf(';', endIdx - 1, endIdx - startTransformIdx);
                        if (0 <= semiColonIdx)
                        {
                            specStartIdx = semiColonIdx + 1;
                        }

                        // Ignore empty specifications.
                        if (specStartIdx < endIdx)
                        {
                            if (_eventSource.IsEnabled(EventLevel.Informational, Keywords.Messages))
                            {
                                _eventSource.Message("DiagnosticSource: Parsing Explicit Transform '" + filterAndPayloadSpec.Substring(specStartIdx, endIdx - specStartIdx) + "'");
                            }

                            _explicitTransforms = new TransformSpec(filterAndPayloadSpec, specStartIdx, endIdx, _explicitTransforms);
                        }
                        if (startTransformIdx == specStartIdx)
                        {
                            break;
                        }
                        endIdx = semiColonIdx;
                    }
                }

                // Set up a subscription that watches for the given Diagnostic Sources and events which will call back
                // to the EventSource.
                _diagnosticsListenersSubscription = DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(delegate(DiagnosticListener newListener)
                {
                    if (listenerNameFilter == null || listenerNameFilter == newListener.Name)
                    {
                        Predicate <string> eventNameFilterPredicate = null;
                        if (eventNameFilter != null)
                        {
                            eventNameFilterPredicate = (string eventName) => eventNameFilter == eventName;
                        }

                        var subscription = newListener.Subscribe(new CallbackObserver <KeyValuePair <string, object> >(delegate(KeyValuePair <string, object> evnt)
                        {
                            // The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected.
                            // Thus we look for any events that may have snuck through and filter them out before forwarding.
                            if (eventNameFilter != null && eventNameFilter != evnt.Key)
                            {
                                return;
                            }

                            var outputArgs = this.Morph(evnt.Value);
#if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT
                            _eventSource.Event(newListener.Name, evnt.Key, outputArgs);
#else
                            _eventSource.EventJson(newListener.Name, evnt.Key, ToJson(outputArgs));
#endif
                        }), eventNameFilterPredicate);
                        _liveSubscriptions = new Subscriptions(subscription, _liveSubscriptions);
                    }
                }));
            }