dotnet-trace CLI changes (#473)
authorSung Yoon Whang <suwhang@microsoft.com>
Fri, 13 Sep 2019 05:32:12 +0000 (22:32 -0700)
committerGitHub <noreply@github.com>
Fri, 13 Sep 2019 05:32:12 +0000 (22:32 -0700)
* Fix dotnet-trace CLI according to the newest spec changes

* Add some configuration strings to help users understand where providers came from

* Some typos

* More UI changes suggested from PR

* Some strange Console bug causing issues... Clear the console before printing anything to make it work better

* remove provider/profile string from enabledBy column

src/Microsoft.Diagnostics.Tools.RuntimeClient/Eventing/Provider.cs
src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs
src/Tools/dotnet-trace/CommandLine/Commands/ListProfilesCommandHandler.cs

index 1f8270d489e9b8615a97c52bf3fa00888277b91f..34ba88c43f1381f97692ef88ff43da609f82486b 100644 (file)
@@ -34,5 +34,8 @@ namespace Microsoft.Diagnostics.Tools.RuntimeClient
 
         public override string ToString() =>
             $"{Name}:0x{Keywords:X16}:{(uint)EventLevel}{(FilterData == null ? "" : $":{FilterData}")}";
+
+        public string ToDisplayString() =>
+            String.Format("{0, -40}", Name) + String.Format("0x{0, -18}", $"{Keywords:X16}") + String.Format("{0, -8}", EventLevel.ToString() + $"({(int)EventLevel})");
     }
 }
index 09c364b889099829f3502ee6545c25ca99ebe879..ca46abe1e9912d2762aa4377ff33e450fc9037be 100644 (file)
@@ -38,49 +38,66 @@ namespace Microsoft.Diagnostics.Tools.Trace
             {
                 Debug.Assert(output != null);
                 Debug.Assert(profile != null);
+                Console.Clear();
                 if (processId <= 0)
                 {
                     Console.Error.WriteLine("Process ID should not be negative.");
                     return ErrorCodes.ArgumentError;
                 }
 
-                var selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
-                    .FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
-                if (selectedProfile == null)
+                if (profile.Length == 0 && providers.Length == 0)
                 {
-                    Console.Error.WriteLine($"Invalid profile name: {profile}");
-                    return ErrorCodes.ArgumentError;
+                    Console.Out.WriteLine("No profile or providers specified, defaulting to trace profile 'cpu-sampling'");
+                    profile = "cpu-sampling";
                 }
 
+                Dictionary<string, string> enabledBy = new Dictionary<string, string>();
+
                 var providerCollection = Extensions.ToProviders(providers);
-                var profileProviders = new List<Provider>();
+                foreach (Provider providerCollectionProvider in providerCollection)
+                {
+                    enabledBy[providerCollectionProvider.Name] = "--providers ";
+                }
 
-                // If user defined a different key/level on the same provider via --providers option that was specified via --profile option,
-                // --providers option takes precedence. Go through the list of providers specified and only add it if it wasn't specified
-                // via --providers options.
-                if (selectedProfile.Providers != null)
+                if (profile.Length != 0)
                 {
-                    foreach (Provider selectedProfileProvider in selectedProfile.Providers)
+                    var profileProviders = new List<Provider>();
+                    var selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
+                        .FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
+                    if (selectedProfile == null)
                     {
-                        bool shouldAdd = true;
+                        Console.Error.WriteLine($"Invalid profile name: {profile}");
+                        return ErrorCodes.ArgumentError;
+                    }
 
-                        foreach (Provider providerCollectionProvider in providerCollection)
+                    // If user defined a different key/level on the same provider via --providers option that was specified via --profile option,
+                    // --providers option takes precedence. Go through the list of providers specified and only add it if it wasn't specified
+                    // via --providers options.
+                    if (selectedProfile.Providers != null)
+                    {
+                        foreach (Provider selectedProfileProvider in selectedProfile.Providers)
                         {
-                            if (providerCollectionProvider.Name.Equals(selectedProfileProvider.Name))
+                            bool shouldAdd = true;
+
+                            foreach (Provider providerCollectionProvider in providerCollection)
                             {
-                                shouldAdd = false;
-                                break;
+                                if (providerCollectionProvider.Name.Equals(selectedProfileProvider.Name))
+                                {
+                                    shouldAdd = false;
+                                    break;
+                                }
                             }
-                        }
 
-                        if (shouldAdd)
-                        {
-                            profileProviders.Add(selectedProfileProvider);
+                            if (shouldAdd)
+                            {
+                                enabledBy[selectedProfileProvider.Name] = "--profile ";
+                                profileProviders.Add(selectedProfileProvider);
+                            }
                         }
                     }
+                    providerCollection.AddRange(profileProviders);
                 }
 
-                providerCollection.AddRange(profileProviders);
 
                 if (providerCollection.Count <= 0)
                 {
@@ -88,7 +105,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
                     return ErrorCodes.ArgumentError;
                 }
 
-                PrintProviders(providerCollection);
+                PrintProviders(providerCollection, enabledBy);
 
                 var process = Process.GetProcessById(processId);
                 var configuration = new SessionConfiguration(
@@ -135,8 +152,8 @@ namespace Microsoft.Diagnostics.Tools.Trace
                                 Console.Out.WriteLine($"Output File    : {fs.Name}");
                                 if (shouldStopAfterDuration)
                                     Console.Out.WriteLine($"Trace Duration : {duration.ToString(@"dd\:hh\:mm\:ss")}");
-                                Console.Out.WriteLine($"\tSession Id: 0x{sessionId:X16}\n");
-                                lineToClear = Console.CursorTop;
+
+                                Console.Out.WriteLine("\n\n");
                                 var buffer = new byte[16 * 1024];
 
                                 while (true)
@@ -145,10 +162,10 @@ namespace Microsoft.Diagnostics.Tools.Trace
                                     if (nBytesRead <= 0)
                                         break;
                                     fs.Write(buffer, 0, nBytesRead);
-
+                                    lineToClear = Console.CursorTop-1;
                                     ResetCurrentConsoleLine(vTermMode.IsEnabled);
-                                    Console.Out.Write($"[{stopwatch.Elapsed.ToString(@"dd\:hh\:mm\:ss")}]\tRecording trace {GetSize(fs.Length)}");
-
+                                    Console.Out.WriteLine($"[{stopwatch.Elapsed.ToString(@"dd\:hh\:mm\:ss")}]\tRecording trace {GetSize(fs.Length)}");
+                                    Console.Out.WriteLine("Press <Enter> or <Ctrl+C> to exit...");
                                     Debug.WriteLine($"PACKET: {Convert.ToBase64String(buffer, 0, nBytesRead)} (bytes {nBytesRead})");
                                 }
                             }
@@ -166,8 +183,6 @@ namespace Microsoft.Diagnostics.Tools.Trace
                     });
                     collectingTask.Start();
 
-                    Console.Out.WriteLine("Press <Enter> or <Ctrl+C> to exit...");
-
                     do
                     {
                         while (!Console.KeyAvailable && !shouldExit.WaitOne(250)) { }
@@ -196,12 +211,18 @@ namespace Microsoft.Diagnostics.Tools.Trace
             }
         }
 
-        [Conditional("DEBUG")]
-        private static void PrintProviders(IReadOnlyList<Provider> providers)
+        private static void PrintProviders(IReadOnlyList<Provider> providers, Dictionary<string, string> enabledBy)
         {
-            Console.Out.WriteLine("Enabling the following providers");
+            Console.Out.WriteLine("");
+            Console.Out.Write(String.Format("{0, -40}","Provider Name"));  // +4 is for the tab
+            Console.Out.Write(String.Format("{0, -20}","Keywords"));
+            Console.Out.Write(String.Format("{0, -20}","Level"));
+            Console.Out.Write("Enabled By\n");
             foreach (var provider in providers)
-                Console.Out.WriteLine($"\t{provider.ToString()}");
+            {
+                Console.Out.WriteLine(String.Format("{0, -80}", $"{provider.ToDisplayString()}") + $"{enabledBy[provider.Name]}");
+            }
+            Console.Out.WriteLine();
         }
 
         private static int prevBufferWidth = 0;
@@ -239,7 +260,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
             else if (length > 1e3)
                 return String.Format("{0,-8} (KB)", $"{length / 1e3:0.00##}");
             else
-                return String.Format("{0,-8} (byte)", $"{length / 1.0:0.00##}");
+                return String.Format("{0,-8} (B)", $"{length / 1.0:0.00##}");
         }
 
         public static Command CollectCommand() =>
@@ -278,7 +299,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
         private static Option ProvidersOption() =>
             new Option(
                 alias: "--providers",
-                description: @"A list of EventPipe providers to be enabled. This is in the form 'Provider[,Provider]', where Provider is in the form: 'KnownProviderName[:Flags[:Level][:KeyValueArgs]]', and KeyValueArgs is in the form: '[key1=value1][;key2=value2]'",
+                description: @"A list of EventPipe providers to be enabled. This is in the form 'Provider[,Provider]', where Provider is in the form: 'KnownProviderName[:Flags[:Level][:KeyValueArgs]]', and KeyValueArgs is in the form: '[key1=value1][;key2=value2]'. These providers are in addition to any providers implied by the --profile argument. If there is any discrepancy for a particular provider, the configuration here takes precedence over the implicit configuration from the profile.",
                 argument: new Argument<string>(defaultValue: "") { Name = "list-of-comma-separated-providers" }, // TODO: Can we specify an actual type?
                 isHidden: false);
 
@@ -286,7 +307,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
             new Option(
                 alias: "--profile",
                 description: @"A named pre-defined set of provider configurations that allows common tracing scenarios to be specified succinctly.",
-                argument: new Argument<string>(defaultValue: "runtime-basic") { Name = "profile-name" },
+                argument: new Argument<string>(defaultValue: "") { Name = "profile-name" },
                 isHidden: false);
 
         private static Option DurationOption() =>
index c0e33ea2f56570cc43cfecd60526f03b9a74c382..f8ec9089fda5aa78c5ce585b4352784b9d3644a4 100644 (file)
@@ -42,12 +42,12 @@ namespace Microsoft.Diagnostics.Tools.Trace
         // FIXME: Read from a config file!
         internal static IEnumerable<Profile> DotNETRuntimeProfiles { get; } = new[] {
             new Profile(
-                "runtime-basic",
+                "cpu-sampling",
                 new Provider[] {
                     new Provider("Microsoft-DotNETCore-SampleProfiler"),
                     new Provider("Microsoft-Windows-DotNETRuntime", (ulong)ClrTraceEventParser.Keywords.Default, EventLevel.Informational),
                 },
-                "Useful for tracking CPU usage and general runtime information. This the default option if no profile is specified."),
+                "Useful for tracking CPU usage and general .NET runtime information. This is the default option if no profile or providers are specified."),
             new Profile(
                 "gc-verbose",
                 new Provider[] {
@@ -59,7 +59,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
                         eventLevel: EventLevel.Verbose
                     ),
                 },
-                "Tracks GC and GC handle events at verbose level, and samples the allocation events as well."),
+                "Tracks GC collections and samples object allocations."),
             new Profile(
                 "gc-collect",
                 new Provider[] {
@@ -69,11 +69,7 @@ namespace Microsoft.Diagnostics.Tools.Trace
                                     (ulong)ClrTraceEventParser.Keywords.Exception,
                         eventLevel: EventLevel.Informational),
                 },
-                "Tracks GC collection only at very low overhead."),
-            new Profile(
-                "none",
-                null,
-                "Tracks nothing. Only providers specified by the --providers option will be available."),
+                "Tracks GC collections only at very low overhead."),
         };
     }
 }