/// <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); } })); }
/// <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); } })); }