// parses a comma separated list of providers internal void ParseProviderList(string providerListText, CounterSet counters) { bool inParen = false; int startIdx = -1; int i = 0; for (; i < providerListText.Length; i++) { if (!inParen) { if (providerListText[i] == '[') { inParen = true; continue; } else if (providerListText[i] == ',') { if (startIdx < 0) { throw new FormatException("Expected non-empty counter_provider"); } ParseCounterProvider(providerListText.Substring(startIdx, i - startIdx), counters); startIdx = -1; } else if (startIdx == -1 && providerListText[i] != ' ') { startIdx = i; } } else if (inParen && providerListText[i] == ']') { inParen = false; } } if (inParen) { throw new FormatException("Expected to find closing ']' in counter_provider"); } if (startIdx < 0) { throw new FormatException("Expected non-empty counter_provider"); } ParseCounterProvider(providerListText.Substring(startIdx, i - startIdx), counters); }
internal CounterSet ConfigureCounters(string commaSeparatedProviderListText, List <string> providerList) { CounterSet counters = new CounterSet(); try { if (commaSeparatedProviderListText != null) { ParseProviderList(commaSeparatedProviderListText, counters); } } catch (FormatException e) { // the FormatException message strings thrown by ParseProviderList are controlled // by us and anticipate being integrated into the command-line error text. throw new CommandLineErrorException("Error parsing --counters argument: " + e.Message); } if (providerList != null) { try { foreach (string providerText in providerList) { ParseCounterProvider(providerText, counters); } } catch (FormatException e) { // the FormatException message strings thrown by ParseCounterProvider are controlled // by us and anticipate being integrated into the command-line error text. throw new CommandLineErrorException("Error parsing counter_list: " + e.Message); } } if (counters.IsEmpty) { _console.Out.WriteLine($"--counters is unspecified. Monitoring System.Runtime counters by default."); counters.AddAllProviderCounters("System.Runtime"); } return(counters); }
public async Task <int> Collect( CancellationToken ct, List <string> counter_list, string counters, IConsole console, int processId, int refreshInterval, CountersExportFormat format, string output, string name, string diagnosticPort, bool resumeRuntime, int maxHistograms, int maxTimeSeries) { try { // System.CommandLine does have an option to specify arguments as uint and it would validate they are non-negative. However the error // message is "Cannot parse argument '-1' for option '--maxTimeSeries' as expected type System.UInt32" which is not as user friendly. // If there was another option to leverage System.CommandLine that provides a little more user friendly error message we could switch // to it. ValidateNonNegative(maxHistograms, nameof(maxHistograms)); ValidateNonNegative(maxTimeSeries, nameof(maxTimeSeries)); if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ValidateArgumentsForAttach(processId, name, diagnosticPort, out _processId)) { return(ReturnCode.ArgumentError); } _ct.Register(() => _shouldExit.TrySetResult(ReturnCode.Ok)); DiagnosticsClientBuilder builder = new DiagnosticsClientBuilder("dotnet-counters", 10); using (DiagnosticsClientHolder holder = await builder.Build(ct, _processId, diagnosticPort, showChildIO: false, printLaunchCommand: false)) { if (holder == null) { return(ReturnCode.Ok); } try { _console = console; // the launch command may misinterpret app arguments as the old space separated // provider list so we need to ignore it in that case _counterList = ConfigureCounters(counters, _processId != 0 ? counter_list : null); _ct = ct; _interval = refreshInterval; _maxHistograms = maxHistograms; _maxTimeSeries = maxTimeSeries; _output = output; _diagnosticsClient = holder.Client; if (_output.Length == 0) { _console.Error.WriteLine("Output cannot be an empty string"); return(ReturnCode.ArgumentError); } if (format == CountersExportFormat.csv) { _renderer = new CSVExporter(output); } else if (format == CountersExportFormat.json) { // Try getting the process name. string processName = ""; try { if (ProcessLauncher.Launcher.HasChildProc) { _processId = ProcessLauncher.Launcher.ChildProc.Id; } processName = Process.GetProcessById(_processId).ProcessName; } catch (Exception) { } _renderer = new JSONExporter(output, processName); } else { _console.Error.WriteLine($"The output format {format} is not a valid output format."); return(ReturnCode.ArgumentError); } _resumeRuntime = resumeRuntime; int ret = await Start(); return(ret); } catch (OperationCanceledException) { try { _session.Stop(); } catch (Exception) { } // session.Stop() can throw if target application already stopped before we send the stop command. return(ReturnCode.Ok); } } } catch (CommandLineErrorException e) { console.Error.WriteLine(e.Message); return(ReturnCode.ArgumentError); } }
public async Task <int> Monitor( CancellationToken ct, List <string> counter_list, string counters, IConsole console, int processId, int refreshInterval, string name, string diagnosticPort, bool resumeRuntime, int maxHistograms, int maxTimeSeries) { try { // System.CommandLine does have an option to specify arguments as uint and it would validate they are non-negative. However the error // message is "Cannot parse argument '-1' for option '--maxTimeSeries' as expected type System.UInt32" which is not as user friendly. // If there was another option to leverage System.CommandLine that provides a little more user friendly error message we could switch // to it. ValidateNonNegative(maxHistograms, nameof(maxHistograms)); ValidateNonNegative(maxTimeSeries, nameof(maxTimeSeries)); if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ValidateArgumentsForAttach(processId, name, diagnosticPort, out _processId)) { return(ReturnCode.ArgumentError); } _ct.Register(() => _shouldExit.TrySetResult(ReturnCode.Ok)); DiagnosticsClientBuilder builder = new DiagnosticsClientBuilder("dotnet-counters", 10); using (DiagnosticsClientHolder holder = await builder.Build(ct, _processId, diagnosticPort, showChildIO: false, printLaunchCommand: false)) { if (holder == null) { return(ReturnCode.Ok); } try { _console = console; // the launch command may misinterpret app arguments as the old space separated // provider list so we need to ignore it in that case _counterList = ConfigureCounters(counters, _processId != 0 ? counter_list : null); _ct = ct; _interval = refreshInterval; _maxHistograms = maxHistograms; _maxTimeSeries = maxTimeSeries; _renderer = new ConsoleWriter(); _diagnosticsClient = holder.Client; _resumeRuntime = resumeRuntime; int ret = await Start(); ProcessLauncher.Launcher.Cleanup(); return(ret); } catch (OperationCanceledException) { try { _session.Stop(); } catch (Exception) { } // Swallow all exceptions for now. console.Out.WriteLine($"Complete"); return(ReturnCode.Ok); } } } catch (CommandLineErrorException e) { console.Error.WriteLine(e.Message); return(ReturnCode.ArgumentError); } }