[dotnet-trace] Allow user to specify text version of event level (#540)
authorSung Yoon Whang <suwhang@microsoft.com>
Tue, 8 Oct 2019 02:16:20 +0000 (19:16 -0700)
committerGitHub <noreply@github.com>
Tue, 8 Oct 2019 02:16:20 +0000 (19:16 -0700)
* Allow user to specify text version of event level

* Throw on unknown event level

* add tests

* docs change

* more docs change

* make case insensitive comparison

documentation/design-docs/dotnet-tools.md
src/Tools/dotnet-trace/Extensions.cs
src/tests/dotnet-trace/ProviderParsing.cs

index 557eaf7e0cfd757616c4e3b4cf4068fb3c59e29d..5d100ae7b0623ef82fd0138516c31ba8bf154143 100644 (file)
@@ -291,7 +291,7 @@ COLLECT
             Provider format: KnownProviderName[:Keywords[:Level][:KeyValueArgs]]
                 KnownProviderName       - The provider's name
                 Keywords                - 8 character hex number bit mask
-                Level                   - A number in the range [0, 5]
+                Level                   - A number in the range [0, 5], or their corresponding text values (refer to https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.tracing.eventlevel?view=netframework-4.8).
                 KeyValueArgs            - A semicolon separated list of key=value
             KeyValueArgs format: '[key1=value1][;key2=value2]'
 
@@ -303,12 +303,22 @@ COLLECT
 
 
     Examples:
+      
+      To perform a default `cpu-tracing` profiling:
+
       > dotnet trace collect --process-id 1902
       No profile or providers specified, defaulting to trace profile 'cpu-sampling'
       Recording trace 38MB
 
       's' - stop tracing
 
+
+      To collect just the GC keyword events from the .NET runtime at informational level:
+
+      > dotnet trace collect --process-id 1902 --providers Microsoft-Windows-DotNETRuntime:0x1:Informational
+
+
+
 CONVERT
 
     dotnet-trace convert [-h|--help]
index fbaf43847f8d671afa1bcd51408ab9003024de97..a1055eeeb33f1c4477611be2a67f4568e72a84e6 100644 (file)
@@ -12,6 +12,8 @@ namespace Microsoft.Diagnostics.Tools.Trace
 {
     internal static class Extensions
     {
+        private static EventLevel defaultEventLevel = EventLevel.Verbose;
+
         public static List<Provider> ToProviders(string providers)
         {
             if (providers == null)
@@ -20,6 +22,35 @@ namespace Microsoft.Diagnostics.Tools.Trace
                 new List<Provider>() : providers.Split(',').Select(ToProvider).ToList();
         }
 
+        private static EventLevel GetEventLevel(string token)
+        {
+            if (Int32.TryParse(token, out int level) && level >= 0)
+            {
+                return level > (int)EventLevel.Verbose ? EventLevel.Verbose : (EventLevel)level;
+            }
+
+            else
+            {
+                switch (token.ToLower())
+                {
+                    case "critical":
+                        return EventLevel.Critical;
+                    case "error":
+                        return EventLevel.Error;
+                    case "informational":
+                        return EventLevel.Informational;
+                    case "logalways":
+                        return EventLevel.LogAlways;
+                    case "verbose":
+                        return EventLevel.Verbose;
+                    case "warning":
+                        return EventLevel.Warning;
+                    default:
+                        throw new ArgumentException($"Unknown EventLevel: {token}");
+                }
+            }
+        }
+
         private static Provider ToProvider(string provider)
         {
             if (string.IsNullOrWhiteSpace(provider))
@@ -44,10 +75,8 @@ namespace Microsoft.Diagnostics.Tools.Trace
                 Convert.ToUInt64(tokens[1], 16) : ulong.MaxValue;
 
             // Level
-            uint level = tokens.Length > 2 && !string.IsNullOrWhiteSpace(tokens[2]) ?
-                Convert.ToUInt32(tokens[2]) : (uint)EventLevel.Verbose;
-            EventLevel eventLevel = level > (uint)EventLevel.Verbose ?
-                EventLevel.Verbose : (EventLevel)level; // TODO: Should we throw here?
+            EventLevel eventLevel = tokens.Length > 2 && !string.IsNullOrWhiteSpace(tokens[2]) ?
+                GetEventLevel(tokens[2]) : defaultEventLevel;
 
             // Event counters
             string filterData = tokens.Length > 3 ? tokens[3] : null;
index 9b84140b59c9495c07ba06135a000ad07b419fdb..8d1930d4b957f81bec434e3bf62011150bcfbc8f 100644 (file)
@@ -178,5 +178,84 @@ namespace Microsoft.Diagnostics.Tools.Trace
             Assert.True(providerThree.EventLevel == System.Diagnostics.Tracing.EventLevel.Warning);
             Assert.True(providerThree.FilterData == "FilterAndPayloadSpecs=\"QuotedValue:-\r\nQuoted/Value:-A=B;C=D;\"");
         }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:Verbose")]
+        [InlineData("ProviderOne:0x1:verbose")]
+        public void TextLevelProviderSpecVerbose_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.Verbose);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:Informational")]
+        [InlineData("ProviderOne:0x1:INFORMATIONAL")]
+        public void TextLevelProviderSpecInformational_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.Informational);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:LogAlways")]
+        [InlineData("ProviderOne:0x1:LogAlwayS")]        
+        public void TextLevelProviderSpecLogAlways_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.LogAlways);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:Error")]
+        [InlineData("ProviderOne:0x1:ERRor")]
+        public void TextLevelProviderSpecError_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.Error);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:Critical")]
+        [InlineData("ProviderOne:0x1:CRITICAL")]
+        public void TextLevelProviderSpecCritical_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.Critical);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:Warning")]
+        [InlineData("ProviderOne:0x1:warning")]
+        public void TextLevelProviderSpecWarning_CorrectlyParse(string providerToParse)
+        {
+            List<Provider> parsedProviders = Extensions.ToProviders(providerToParse);
+            Assert.True(parsedProviders.Count == 1);
+            Assert.True(parsedProviders[0].Name == "ProviderOne");
+            Assert.True(parsedProviders[0].Keywords == 1);
+            Assert.True(parsedProviders[0].EventLevel == System.Diagnostics.Tracing.EventLevel.Warning);
+        }
+
+        [Theory]
+        [InlineData("ProviderOne:0x1:UnknownLevel")]
+        public void TextLevelProviderSpec_CorrectlyThrows(string providerToParse)
+        {
+            Assert.Throws<ArgumentException>(() => Extensions.ToProviders(providerToParse));
+        }
     }
 }
\ No newline at end of file