using System.Reflection; using System.Text; using System.Globalization; using System.Diagnostics; using System.Diagnostics.Tracing; using TelemData = System.Collections.Generic.KeyValuePair; internal class Program { static void Main(string[] args) { string methodName = "NoExceptionThrownWhenProcessingStaticActivityProperties"; Program p = new Program(); var mi = p.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public); mi.Invoke(p, null); Console.WriteLine("Done"); } public void NoExceptionThrownWhenProcessingStaticActivityProperties() { using (var eventListener = new TestDiagnosticSourceEventListener()) using (var diagnosticListener = new DiagnosticListener("MySource")) { string activityProps = "-DummyProp" + ";ActivityEvents=*Activity.DefaultIdFormat" + ";ActivityBaggage=*Activity.Current" + ";ActivityContext=*Activity.ForceDefaultIdFormat"; eventListener.Enable( "MySource/TestActivity1.Start@Activity1Start:" + activityProps + "\r\n" + "MySource/TestActivity1.Stop@Activity1Stop:" + activityProps + "\r\n" + "MySource/TestActivity2.Start@Activity2Start:" + activityProps + "\r\n" + "MySource/TestActivity2.Stop@Activity2Stop:" + activityProps + "\r\n" ); Activity activity1 = new Activity("TestActivity1"); activity1.SetIdFormat(ActivityIdFormat.W3C); activity1.TraceStateString = "hi_there"; activity1.AddTag("one", "1"); activity1.AddTag("two", "2"); var obj = new { DummyProp = "val" }; diagnosticListener.StartActivity(activity1, obj); Console.WriteLine(eventListener.EventCount); Debug.Assert(1==eventListener.EventCount); } } } internal class ObserverToList : IObserver { public ObserverToList(List output, Predicate filter = null, string name = null) { _output = output; _output.Clear(); _filter = filter; _name = name; } public bool Completed { get; private set; } public void OnCompleted() { Completed = true; } public void OnError(Exception error) { //Assert.True(false, "Error happened on IObserver"); } public void OnNext(T value) { //Assert.False(Completed); if (_filter == null || _filter(value)) _output.Add(value); } private List _output; private Predicate _filter; private string _name; // for debugging } internal sealed class TestDiagnosticSourceEventListener : DiagnosticSourceEventListener { public TestDiagnosticSourceEventListener() { EventWritten += UpdateLastEvent; } public int EventCount; public DiagnosticSourceEvent LastEvent; // Here just for debugging. Lets you see the last 3 events that were sent. public DiagnosticSourceEvent SecondLast; public DiagnosticSourceEvent ThirdLast; /// /// Sets the EventCount to 0 and LastEvents to null /// public void ResetEventCountAndLastEvent() { EventCount = 0; LastEvent = null; SecondLast = null; ThirdLast = null; } /// /// If present, will ignore events that don't cause this filter predicate to return true. /// public Predicate Filter; #region private private void UpdateLastEvent(DiagnosticSourceEvent anEvent) { if (Filter != null && !Filter(anEvent)) return; ThirdLast = SecondLast; SecondLast = LastEvent; EventCount++; LastEvent = anEvent; } #endregion } internal sealed class DiagnosticSourceEvent { public string SourceName; public string EventName; public Dictionary Arguments; // Not typically important. public string EventSourceEventName; // This is the name of the EventSourceEvent that carried the data. Only important for activities. public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendLine("{"); sb.Append(" SourceName: \"").Append(SourceName ?? "").Append("\",").AppendLine(); sb.Append(" EventName: \"").Append(EventName ?? "").Append("\",").AppendLine(); sb.Append(" Arguments: ").Append("[").AppendLine(); bool first = true; foreach (var keyValue in Arguments) { if (!first) sb.Append(",").AppendLine(); first = false; sb.Append(" ").Append(keyValue.Key).Append(": \"").Append(keyValue.Value).Append("\""); } sb.AppendLine().AppendLine(" ]"); sb.AppendLine("}"); return sb.ToString(); } } internal class DiagnosticSourceEventListener : EventListener { public DiagnosticSourceEventListener() { } /// /// Will be called when a DiagnosticSource event is fired. /// public new event Action EventWritten; /// /// It is possible that there are other events besides those that are being forwarded from /// the DiagnosticSources. These come here. /// public event Action OtherEventWritten; public void Enable(string filterAndPayloadSpecs, EventKeywords keywords = EventKeywords.All) { var args = new Dictionary(); if (filterAndPayloadSpecs != null) args.Add("FilterAndPayloadSpecs", filterAndPayloadSpecs); EnableEvents(_diagnosticSourceEventSource, EventLevel.Verbose, keywords, args); } public void Disable() { DisableEvents(_diagnosticSourceEventSource); } /// /// Cleans this class up. Among other things disables the DiagnosticSources being listened to. /// public override void Dispose() { if (_diagnosticSourceEventSource != null) { Disable(); _diagnosticSourceEventSource = null; } } #region private protected override void OnEventWritten(EventWrittenEventArgs eventData) { bool wroteEvent = false; var eventWritten = EventWritten; if (eventWritten != null) { if (eventData.Payload.Count == 3 && (eventData.EventName == "Event" || eventData.EventName.Contains("Activity"))) { Debug.Assert(eventData.PayloadNames[0] == "SourceName"); Debug.Assert(eventData.PayloadNames[1] == "EventName" || eventData.PayloadNames[1] == "ActivityName"); Debug.Assert(eventData.PayloadNames[2] == "Arguments"); var anEvent = new DiagnosticSourceEvent(); anEvent.EventSourceEventName = eventData.EventName; anEvent.SourceName = eventData.Payload[0].ToString(); anEvent.EventName = eventData.Payload[1].ToString(); anEvent.Arguments = new Dictionary(); var asKeyValueList = eventData.Payload[2] as IEnumerable; if (asKeyValueList != null) { foreach (IDictionary keyvalue in asKeyValueList) { object key; keyvalue.TryGetValue("Key", out key); object value; keyvalue.TryGetValue("Value", out value); if (key != null && value != null) anEvent.Arguments[key.ToString()] = value.ToString(); } } eventWritten(anEvent); wroteEvent = true; } } if (eventData.EventName == "EventSourceMessage" && 0 < eventData.Payload.Count) System.Diagnostics.Debug.WriteLine("EventSourceMessage: " + eventData.Payload[0].ToString()); var otherEventWritten = OtherEventWritten; if (otherEventWritten != null && !wroteEvent) otherEventWritten(eventData); } protected override void OnEventSourceCreated(EventSource eventSource) { if (eventSource.Name == "Microsoft-Diagnostics-DiagnosticSource") _diagnosticSourceEventSource = eventSource; } EventSource _diagnosticSourceEventSource; #endregion }