From: Sung Yoon Whang Date: Fri, 13 Sep 2019 05:32:12 +0000 (-0700) Subject: dotnet-trace CLI changes (#473) X-Git-Tag: submit/tizen/20191015.063341~10^2~1^2~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8ccd54cde5a7c671c44051336ee5c2500f6aff19;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git dotnet-trace CLI changes (#473) * 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 --- diff --git a/src/Microsoft.Diagnostics.Tools.RuntimeClient/Eventing/Provider.cs b/src/Microsoft.Diagnostics.Tools.RuntimeClient/Eventing/Provider.cs index 1f8270d48..34ba88c43 100644 --- a/src/Microsoft.Diagnostics.Tools.RuntimeClient/Eventing/Provider.cs +++ b/src/Microsoft.Diagnostics.Tools.RuntimeClient/Eventing/Provider.cs @@ -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})"); } } diff --git a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs index 09c364b88..ca46abe1e 100644 --- a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs +++ b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs @@ -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 enabledBy = new Dictionary(); + var providerCollection = Extensions.ToProviders(providers); - var profileProviders = new List(); + 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(); + 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 or 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 or 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 providers) + private static void PrintProviders(IReadOnlyList providers, Dictionary 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(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(defaultValue: "runtime-basic") { Name = "profile-name" }, + argument: new Argument(defaultValue: "") { Name = "profile-name" }, isHidden: false); private static Option DurationOption() => diff --git a/src/Tools/dotnet-trace/CommandLine/Commands/ListProfilesCommandHandler.cs b/src/Tools/dotnet-trace/CommandLine/Commands/ListProfilesCommandHandler.cs index c0e33ea2f..f8ec9089f 100644 --- a/src/Tools/dotnet-trace/CommandLine/Commands/ListProfilesCommandHandler.cs +++ b/src/Tools/dotnet-trace/CommandLine/Commands/ListProfilesCommandHandler.cs @@ -42,12 +42,12 @@ namespace Microsoft.Diagnostics.Tools.Trace // FIXME: Read from a config file! internal static IEnumerable 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."), }; } }