Add keywords for two common event specficiations (asp.NET and SQL command).
authorVance Morrison <vancem@microsoft.com>
Thu, 23 Jun 2016 17:08:08 +0000 (10:08 -0700)
committerVance Morrison <vancem@microsoft.com>
Thu, 23 Jun 2016 17:08:08 +0000 (10:08 -0700)
While this is a nice shortcut, it also have the more importnat effect of allowig older ETW controllers that don't
have support for passing arguments to providers to particpate in the most important events.

Commit migrated from https://github.com/dotnet/corefx/commit/aaca69453594f6cc5718ce09e386e355b6a672d7

src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticSourceEventSource.cs
src/libraries/System.Diagnostics.DiagnosticSource/tests/DiagnosticSourceEventSourceBridgeTests.cs

index a65b45f..de09b7c 100644 (file)
@@ -137,13 +137,45 @@ namespace System.Diagnostics
             /// <summary>
             /// Indicates diagnostics messages from DiagnosticSourceEventSource should be included. 
             /// </summary>
-            public const EventKeywords Messages = (EventKeywords)1;
+            public const EventKeywords Messages = (EventKeywords)0x1;
             /// <summary>
             /// Indicates that all events from all diagnostic sources should be forwarded to the EventSource using the 'Event' event.  
             /// </summary>
-            public const EventKeywords Events = (EventKeywords)2;
+            public const EventKeywords Events = (EventKeywords)0x2;
+
+            // Some ETW logic does not support passing arguments to the EventProvider.   To get around
+            // this in common cases, we define some keywords that basically stand in for particular common argumnents
+            // That way at least the common cases can be used by everyone (and it also compresses things).
+            // We start these keywords at 0x1000.   See below for the values these keywords represent
+            // Because we want all keywords on to still mean 'dump everything by default' we have another keyword
+            // IgnoreShorcutKeywords which must be OFF in order for the shortcuts to work thus the all 1s keyword
+            // still means what you expect.   
+            public const EventKeywords IgnoreShortCutKeywords = (EventKeywords)0x0800;
+            public const EventKeywords AspNetCoreHosting = (EventKeywords)0x1000;
+            public const EventKeywords EntityFrameworkCoreCommands = (EventKeywords)0x2000;
         };
 
+        // Setting AspNetCoreHosting is like having this in the FilterAndPayloadSpecs string
+        // It turns on basic hostig events. 
+        private readonly string AspNetCoreHostingKeywordValue =
+            "Microsoft.AspNetCore/Microsoft.AspNetCore.Hosting.BeginRequest@Activity1Start:-" +
+                "httpContext.Request.Method;" +
+                "httpContext.Request.Host;" +
+                "httpContext.Request.Path;" +
+                "httpContext.Request.QueryString" +
+            "\r\n" +
+            "Microsoft.AspNetCore/Microsoft.AspNetCore.Hosting.EndRequest@Activity1Stop:-";
+
+        // Setting EntityFrameworkCoreCommands is like having this in the FilterAndPayloadSpecs string
+        // It turns on basic SQL commands.
+        private readonly string EntityFrameworkCoreCommandsKeywordValue =
+            "Microsoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.BeforeExecuteCommand@Activity2Start:-" +
+                "Command.Connection.DataSource;" +
+                "Command.Connection.Database;" +
+                "Command.CommandText" +
+            "\r\n" +
+            "Microsoft.EntityFrameworkCore/Microsoft.EntityFrameworkCore.AfterExecuteCommand@Activity2Stop:-";
+
         /// <summary>
         /// Used to send ad-hoc diagnostics to humans.   
         /// </summary>
@@ -309,6 +341,14 @@ namespace System.Diagnostics
                 {
                     string filterAndPayloadSpecs;
                     command.Arguments.TryGetValue("FilterAndPayloadSpecs", out filterAndPayloadSpecs);
+
+                    if (!IsEnabled(EventLevel.Informational, Keywords.IgnoreShortCutKeywords))
+                    {
+                        if (IsEnabled(EventLevel.Informational, Keywords.AspNetCoreHosting))
+                            filterAndPayloadSpecs = NewLineSeparate(filterAndPayloadSpecs, AspNetCoreHostingKeywordValue);
+                        if (IsEnabled(EventLevel.Informational, Keywords.EntityFrameworkCoreCommands))
+                            filterAndPayloadSpecs = NewLineSeparate(filterAndPayloadSpecs, EntityFrameworkCoreCommandsKeywordValue);
+                    }
                     FilterAndTransform.CreateFilterAndTransformList(ref _specs, filterAndPayloadSpecs, this);
                 }
                 else if (command.Command == EventCommand.Update || command.Command == EventCommand.Disable)
@@ -318,6 +358,13 @@ namespace System.Diagnostics
             }
         }
 
+        private static string NewLineSeparate(string str1, string str2)
+        {
+            if (string.IsNullOrEmpty(str1))
+                return str2;
+            return str1 + "\r\n" + str2;
+        }
+
         #region debugger hooks 
         private volatile bool _false;       // A value that is always false but the compiler does not know this. 
 
@@ -444,7 +491,7 @@ namespace System.Diagnostics
                 {
                     listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, slashIdx - startIdx);
 
-                    var atIdx = filterAndPayloadSpec.IndexOf('@', slashIdx+1, endEventNameIdx - slashIdx - 1);
+                    var atIdx = filterAndPayloadSpec.IndexOf('@', slashIdx + 1, endEventNameIdx - slashIdx - 1);
                     if (0 <= atIdx)
                     {
                         activityName = filterAndPayloadSpec.Substring(atIdx + 1, endEventNameIdx - atIdx - 1);
index 86b381f..5b3a07f 100644 (file)
@@ -440,9 +440,9 @@ namespace System.Diagnostics.Tests
                 Assert.Equal(0, eventSourceListener.EventCount);
                 eventSourceListener.Enable(
                     "TestActivitiesSource/TestActivity1Start@Activity1Start\r\n" +
-                    "TestActivitiesSource/TestActivity1Stop@Activity1Stop\r\n" + 
+                    "TestActivitiesSource/TestActivity1Stop@Activity1Stop\r\n" +
                     "TestActivitiesSource/TestActivity2Start@Activity2Start\r\n" +
-                    "TestActivitiesSource/TestActivity2Stop@Activity2Stop\r\n" + 
+                    "TestActivitiesSource/TestActivity2Stop@Activity2Stop\r\n" +
                     "TestActivitiesSource/TestEvent\r\n"
                     );
 
@@ -497,6 +497,99 @@ namespace System.Diagnostics.Tests
                 eventSourceListener.ResetEventCountAndLastEvent();
             }
         }
+
+        /// <summary>
+        /// Tests that keywords that define shortcuts work.    
+        /// </summary>
+        [Fact]
+        public void TestShortcutKeywords()
+        {
+            using (var eventSourceListener = new TestDiagnosticSourceEventListener())
+            // These are look-alikes for the real ones.  
+            using (var aspNetCoreSource = new DiagnosticListener("Microsoft.AspNetCore"))
+            using (var entityFrameworkCoreSource = new DiagnosticListener("Microsoft.EntityFrameworkCore"))
+            {
+                // These are from DiagnosticSourceEventListener.  
+                var Messages = (EventKeywords)0x1;
+                var Events = (EventKeywords)0x2;
+                var AspNetCoreHosting = (EventKeywords)0x1000;
+                var EntityFrameworkCoreCommands = (EventKeywords)0x2000;
+
+                // Turn on listener using just the keywords 
+                eventSourceListener.Enable(null, Messages | Events | AspNetCoreHosting | EntityFrameworkCoreCommands);
+
+                Assert.Equal(0, eventSourceListener.EventCount);
+
+                // Start a ASP.NET Request
+                aspNetCoreSource.Write("Microsoft.AspNetCore.Hosting.BeginRequest",
+                    new
+                    {
+                        httpContext = new
+                        {
+                            Request = new
+                            {
+                                Method = "Get",
+                                Host = "MyHost",
+                                Path = "MyPath",
+                                QueryString = "MyQuery"
+                            }
+                        }
+                    });
+                // Check that the morphs work as expected.  
+                Assert.Equal(1, eventSourceListener.EventCount); // Exactly one more event has been emitted.
+                Assert.Equal("Activity1Start", eventSourceListener.LastEvent.EventSourceEventName);
+                Assert.Equal("Microsoft.AspNetCore", eventSourceListener.LastEvent.SourceName);
+                Assert.Equal("Microsoft.AspNetCore.Hosting.BeginRequest", eventSourceListener.LastEvent.EventName);
+                Assert.True(4 <= eventSourceListener.LastEvent.Arguments.Count);
+                Debug.WriteLine("Arg Keys = " + string.Join(" ", eventSourceListener.LastEvent.Arguments.Keys));
+                Debug.WriteLine("Arg Values = " + string.Join(" ", eventSourceListener.LastEvent.Arguments.Values));
+                Assert.Equal("Get", eventSourceListener.LastEvent.Arguments["Method"]);
+                Assert.Equal("MyHost", eventSourceListener.LastEvent.Arguments["Host"]);
+                Assert.Equal("MyPath", eventSourceListener.LastEvent.Arguments["Path"]);
+                Assert.Equal("MyQuery", eventSourceListener.LastEvent.Arguments["QueryString"]);
+                eventSourceListener.ResetEventCountAndLastEvent();
+
+                // Start a SQL command 
+                entityFrameworkCoreSource.Write("Microsoft.EntityFrameworkCore.BeforeExecuteCommand",
+                    new
+                    {
+                        Command = new
+                        {
+                            Connection = new
+                            {
+                                DataSource = "MyDataSource",
+                                Database = "MyDatabase",
+                            },
+                            CommandText = "MyCommand"
+                        }
+                    });
+                Assert.Equal(1, eventSourceListener.EventCount); // Exactly one more event has been emitted.
+                Assert.Equal("Activity2Start", eventSourceListener.LastEvent.EventSourceEventName);
+                Assert.Equal("Microsoft.EntityFrameworkCore", eventSourceListener.LastEvent.SourceName);
+                Assert.Equal("Microsoft.EntityFrameworkCore.BeforeExecuteCommand", eventSourceListener.LastEvent.EventName);
+                Assert.True(3 <= eventSourceListener.LastEvent.Arguments.Count);
+                Assert.Equal("MyDataSource", eventSourceListener.LastEvent.Arguments["DataSource"]);
+                Assert.Equal("MyDatabase", eventSourceListener.LastEvent.Arguments["Database"]);
+                Assert.Equal("MyCommand", eventSourceListener.LastEvent.Arguments["CommandText"]);
+                eventSourceListener.ResetEventCountAndLastEvent();
+
+                // Stop the SQL command 
+                entityFrameworkCoreSource.Write("Microsoft.EntityFrameworkCore.AfterExecuteCommand", null);
+                Assert.Equal(1, eventSourceListener.EventCount); // Exactly one more event has been emitted.
+                Assert.Equal("Activity2Stop", eventSourceListener.LastEvent.EventSourceEventName);
+                Assert.Equal("Microsoft.EntityFrameworkCore", eventSourceListener.LastEvent.SourceName);
+                Assert.Equal("Microsoft.EntityFrameworkCore.AfterExecuteCommand", eventSourceListener.LastEvent.EventName);
+                eventSourceListener.ResetEventCountAndLastEvent();
+
+                // Stop the ASP.NET reqeust.  
+                aspNetCoreSource.Write("Microsoft.AspNetCore.Hosting.EndRequest", null);
+                Assert.Equal(1, eventSourceListener.EventCount); // Exactly one more event has been emitted.
+                Assert.Equal("Activity1Stop", eventSourceListener.LastEvent.EventSourceEventName);
+                Assert.Equal("Microsoft.AspNetCore", eventSourceListener.LastEvent.SourceName);
+                Assert.Equal("Microsoft.AspNetCore.Hosting.EndRequest", eventSourceListener.LastEvent.EventName);
+                eventSourceListener.ResetEventCountAndLastEvent();
+            }
+        }
     }
 
     /****************************************************************************/
@@ -536,7 +629,7 @@ namespace System.Diagnostics.Tests
         public DiagnosticSourceEvent LastEvent;
 #if DEBUG 
         // Here just for debugging.  Lets you see the last 3 events that were sent.  
-        public DiagnosticSourceEvent SecondLast;  
+        public DiagnosticSourceEvent SecondLast;
         public DiagnosticSourceEvent ThirdLast;
 #endif 
 
@@ -628,11 +721,12 @@ namespace System.Diagnostics.Tests
         /// </summary>
         public event Action<EventWrittenEventArgs> OtherEventWritten;
 
-        public void Enable(string filterAndPayloadSpecs)
+        public void Enable(string filterAndPayloadSpecs, EventKeywords keywords = EventKeywords.All)
         {
             var args = new Dictionary<string, string>();
-            args.Add("FilterAndPayloadSpecs", filterAndPayloadSpecs);
-            EnableEvents(_diagnosticSourceEventSource, EventLevel.Verbose, EventKeywords.All, args);
+            if (filterAndPayloadSpecs != null)
+                args.Add("FilterAndPayloadSpecs", filterAndPayloadSpecs);
+            EnableEvents(_diagnosticSourceEventSource, EventLevel.Verbose, keywords, args);
         }
 
         public void Disable()
@@ -688,8 +782,8 @@ namespace System.Diagnostics.Tests
                     wroteEvent = true;
                 }
             }
-           
-            if (eventData.EventName == "EventSourceMessage" && 0 < eventData.Payload.Count) 
+
+            if (eventData.EventName == "EventSourceMessage" && 0 < eventData.Payload.Count)
                 System.Diagnostics.Debug.WriteLine("EventSourceMessage: " + eventData.Payload[0].ToString());
 
             var otherEventWritten = OtherEventWritten;