diff --git a/src/Tools/Common/Commands/Utils.cs b/src/Tools/Common/Commands/Utils.cs index 0b28a7ff2e..6910899167 100644 --- a/src/Tools/Common/Commands/Utils.cs +++ b/src/Tools/Common/Commands/Utils.cs @@ -44,11 +44,11 @@ public static int FindProcessIdWithName(string name) // // dsrouterCommand // processId - public static int LaunchDSRouterProcess(string dsrouterCommand) + public static int LaunchDSRouterProcess(string dsrouterCommand, IReadOnlyList unmatchedTokens) { Console.WriteLine("For finer control over the dotnet-dsrouter options, run it separately and connect to it using -p" + Environment.NewLine); - return DsRouterProcessLauncher.Launcher.Start(dsrouterCommand, default); + return DsRouterProcessLauncher.Launcher.Start(dsrouterCommand, unmatchedTokens, default); } @@ -80,9 +80,10 @@ public static bool ValidateArgumentsForChildProcess(int processId, string name, /// name /// port /// dsrouter + /// unmatchedTokens /// resolvedProcessId /// - public static bool ResolveProcessForAttach(int processId, string name, string port, string dsrouter, out int resolvedProcessId) + public static bool ResolveProcessForAttach(int processId, string name, string port, string dsrouter, IReadOnlyList unmatchedTokens, out int resolvedProcessId) { resolvedProcessId = -1; if (processId == 0 && string.IsNullOrEmpty(name) && string.IsNullOrEmpty(port) && string.IsNullOrEmpty(dsrouter)) @@ -124,7 +125,7 @@ public static bool ResolveProcessForAttach(int processId, string name, string po Console.WriteLine("Invalid value for --dsrouter. Valid values are 'ios', 'ios-sim', 'android' and 'android-emu'."); return false; } - if ((processId = LaunchDSRouterProcess(dsrouter)) < 0) + if ((processId = LaunchDSRouterProcess(dsrouter, unmatchedTokens)) < 0) { if (processId == -2) { diff --git a/src/Tools/Common/DsRouterProcessLauncher.cs b/src/Tools/Common/DsRouterProcessLauncher.cs index e4c93efa30..4ef738d2d5 100644 --- a/src/Tools/Common/DsRouterProcessLauncher.cs +++ b/src/Tools/Common/DsRouterProcessLauncher.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Binding; using System.Diagnostics; @@ -117,7 +118,7 @@ private static async Task ReadAndLogAllLinesAsync(StreamReader streamToRead, Tex private Process ChildProc => _childProc; - public int Start(string dsrouterCommand, CancellationToken ct) + public int Start(string dsrouterCommand, IReadOnlyList unmatchedTokens, CancellationToken ct) { string toolsRoot = System.IO.Path.GetDirectoryName(System.Environment.ProcessPath); string dotnetDsrouterTool = "dotnet-dsrouter"; @@ -132,6 +133,11 @@ public int Start(string dsrouterCommand, CancellationToken ct) // Block SIGINT and SIGQUIT in child process. dsrouterCommand += $" --block-signals SIGINT;SIGQUIT --parentprocess \"{currentProcess.Id}:{currentProcess.ProcessName}\""; + if (unmatchedTokens.Count > 0) + { + dsrouterCommand += $" -- {string.Join(" ", unmatchedTokens)}"; + } + _childProc = new Process(); _childProc.StartInfo.FileName = dotnetDsrouterTool; diff --git a/src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs b/src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs index b51f0cb130..5b7580d214 100644 --- a/src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs +++ b/src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; @@ -32,6 +33,16 @@ public void PrepareChildProcess(string[] args) return; } + PrepareChildProcess(args, unparsedTokenIdx); + } + + public void PrepareChildProcess(IEnumerable unmatchedTokens) + { + PrepareChildProcess([.. unmatchedTokens], 0); + } + + private void PrepareChildProcess(string[] args, int unparsedTokenIdx) + { _childProc = new Process(); _childProc.StartInfo.FileName = args[unparsedTokenIdx]; string arguments = ""; diff --git a/src/Tools/dotnet-counters/CounterMonitor.cs b/src/Tools/dotnet-counters/CounterMonitor.cs index 9a6e476aae..bdb0c13431 100644 --- a/src/Tools/dotnet-counters/CounterMonitor.cs +++ b/src/Tools/dotnet-counters/CounterMonitor.cs @@ -176,7 +176,8 @@ public async Task Monitor( int maxTimeSeries, TimeSpan duration, bool showDeltas, - string dsrouter) + string dsrouter, + IReadOnlyList unmatchedTokens) { try { @@ -186,7 +187,7 @@ public async Task Monitor( // to it. ValidateNonNegative(maxHistograms, nameof(maxHistograms)); ValidateNonNegative(maxTimeSeries, nameof(maxTimeSeries)); - if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, out _processId)) + if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, unmatchedTokens, out _processId)) { return ReturnCode.ArgumentError; } @@ -261,7 +262,8 @@ public async Task Collect( int maxHistograms, int maxTimeSeries, TimeSpan duration, - string dsrouter) + string dsrouter, + IReadOnlyList unmatchedTokens) { try { @@ -271,7 +273,7 @@ public async Task Collect( // to it. ValidateNonNegative(maxHistograms, nameof(maxHistograms)); ValidateNonNegative(maxTimeSeries, nameof(maxTimeSeries)); - if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, out _processId)) + if (!ProcessLauncher.Launcher.HasChildProc && !CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, unmatchedTokens, out _processId)) { return ReturnCode.ArgumentError; } diff --git a/src/Tools/dotnet-counters/Program.cs b/src/Tools/dotnet-counters/Program.cs index b15dca5412..e1471297c2 100644 --- a/src/Tools/dotnet-counters/Program.cs +++ b/src/Tools/dotnet-counters/Program.cs @@ -50,7 +50,8 @@ private static Command MonitorCommand() maxTimeSeries: parseResult.GetValue(MaxTimeSeriesOption), duration: parseResult.GetValue(DurationOption), showDeltas: parseResult.GetValue(ShowDeltasOption), - dsrouter: string.Empty + dsrouter: string.Empty, + unmatchedTokens: parseResult.UnmatchedTokens )); return monitorCommand; @@ -90,7 +91,9 @@ private static Command CollectCommand() maxHistograms: parseResult.GetValue(MaxHistogramOption), maxTimeSeries: parseResult.GetValue(MaxTimeSeriesOption), duration: parseResult.GetValue(DurationOption), - dsrouter: string.Empty)); + dsrouter: string.Empty, + unmatchedTokens: parseResult.UnmatchedTokens + )); return collectCommand; } diff --git a/src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs b/src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs index 0f657df026..97b55f9f1a 100644 --- a/src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs +++ b/src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; @@ -357,44 +358,67 @@ public async Task RunIpcClientWebSocketServerRouter(CancellationToken token } } - public async Task RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess) + public async Task RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList unmatchedTokens) { + string deviceTcpIpAddress = "127.0.0.1"; + string deviceTcpIpPort = "9000"; + string listenMode = "listen"; + if (info || ParseLogLevel(verbose) <= LogLevel.Information) { - logRouterUsageInfo("ios simulator", "127.0.0.1:9000", true, parentProcess); + logRouterUsageInfo("ios simulator", deviceTcpIpAddress, deviceTcpIpPort, listenMode, parentProcess); } + prepareChildProcess(unmatchedTokens, deviceTcpIpAddress, deviceTcpIpPort, listenMode); - return await RunIpcServerTcpClientRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "").ConfigureAwait(false); + return await RunIpcServerTcpClientRouter(token, "", $"{deviceTcpIpAddress}:{deviceTcpIpPort}", runtimeTimeout, verbose, "").ConfigureAwait(false); } - public async Task RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess) + public async Task RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList unmatchedTokens) { + string deviceTcpIpAddress = "127.0.0.1"; + string deviceTcpIpPort = "9000"; + string listenMode = "listen"; + if (info || ParseLogLevel(verbose) <= LogLevel.Information) { - logRouterUsageInfo("ios device", "127.0.0.1:9000", true, parentProcess); + logRouterUsageInfo("ios device", deviceTcpIpAddress, deviceTcpIpPort, listenMode, parentProcess); } - return await RunIpcServerTcpClientRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "iOS").ConfigureAwait(false); + prepareChildProcess(unmatchedTokens, deviceTcpIpAddress, deviceTcpIpPort, listenMode); + + return await RunIpcServerTcpClientRouter(token, "", $"{deviceTcpIpAddress}:{deviceTcpIpPort}", runtimeTimeout, verbose, "iOS").ConfigureAwait(false); } - public async Task RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess) + public async Task RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList unmatchedTokens) { + string deviceTcpIpAddress = "10.0.2.2"; + string deviceTcpIpPort = "9000"; + string listenMode = "connect"; + if (info || ParseLogLevel(verbose) <= LogLevel.Information) { - logRouterUsageInfo("android emulator", "10.0.2.2:9000", false, parentProcess); + logRouterUsageInfo("android emulator", deviceTcpIpAddress, deviceTcpIpPort, listenMode, parentProcess); } - return await RunIpcServerTcpServerRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "").ConfigureAwait(false); + prepareChildProcess(unmatchedTokens, deviceTcpIpAddress, deviceTcpIpPort, listenMode); + + return await RunIpcServerTcpServerRouter(token, "", $"127.0.0.1:{deviceTcpIpPort}", runtimeTimeout, verbose, "").ConfigureAwait(false); } - public async Task RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess) + public async Task RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList unmatchedTokens) { + string deviceTcpIpAddress = "127.0.0.1"; + string deviceTcpIpPort = "9000"; + string listenMode = "connect"; + if (info || ParseLogLevel(verbose) <= LogLevel.Information) { - logRouterUsageInfo("android device", "127.0.0.1:9000", false, parentProcess); + logRouterUsageInfo("android device", deviceTcpIpAddress, deviceTcpIpPort, listenMode, parentProcess); } - return await RunIpcServerTcpServerRouter(token, "", "127.0.0.1:9001", runtimeTimeout, verbose, "Android").ConfigureAwait(false); + prepareChildProcess(unmatchedTokens, deviceTcpIpAddress, deviceTcpIpPort, listenMode); + + return await RunIpcServerTcpServerRouter(token, "", $"{deviceTcpIpAddress}:{deviceTcpIpPort}", runtimeTimeout, verbose, "Android").ConfigureAwait(false); } private static string GetDefaultIpcServerPath(ILogger logger) @@ -501,19 +525,17 @@ private static LogLevel ParseLogLevel(string verbose) return logLevel; } - private static void logRouterUsageInfo(string deviceName, string deviceTcpIpAddress, bool deviceListenMode, string parentProcess) + private static void logRouterUsageInfo(string deviceName, string deviceTcpIpAddress, string deviceTcpIpPort, string listenMode, string parentProcess) { StringBuilder message = new(); - - string listenMode = deviceListenMode ? "listen" : "connect"; int pid = Process.GetCurrentProcess().Id; message.AppendLine($"How to connect current dotnet-dsrouter pid={pid} with {deviceName} and diagnostics tooling."); - message.AppendLine($"Start an application on {deviceName} with ONE of the following environment variables set:"); + message.AppendLine($"Build and run your application on {deviceName} such as:"); message.AppendLine("[Default Tracing]"); - message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},nosuspend,{listenMode}"); + message.AppendLine($"dotnet build -t:Run -c Release -p:DiagnosticAddress={deviceTcpIpAddress} -p:DiagnosticPort={deviceTcpIpPort} -p:DiagnosticSuspend=false -p:DiagnosticListenMode={listenMode}"); message.AppendLine("[Startup Tracing]"); - message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},suspend,{listenMode}"); + message.AppendLine($"dotnet build -t:Run -c Release -p:DiagnosticAddress={deviceTcpIpAddress} -p:DiagnosticPort={deviceTcpIpPort} -p:DiagnosticSuspend=true -p:DiagnosticListenMode={listenMode}"); if (string.IsNullOrEmpty(parentProcess)) { message.AppendLine($"Run diagnotic tool connecting application on {deviceName} through dotnet-dsrouter pid={pid}:"); @@ -521,10 +543,44 @@ private static void logRouterUsageInfo(string deviceName, string deviceTcpIpAddr } message.AppendLine($"See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter for additional details and examples."); + logMessageWithColor(message.ToString(), ConsoleColor.Green); + } + + private static void logMessageWithColor(string message, ConsoleColor color) + { ConsoleColor currentColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine(message.ToString()); - Console.ForegroundColor = currentColor; + try + { + Console.ForegroundColor = color; + Console.WriteLine(message); + } + finally + { + Console.ForegroundColor = currentColor; + } + } + + private static void prepareChildProcess(IReadOnlyList unmatchedTokens, string deviceTcpIpAddress, string deviceTcpIpPort, string listenMode) + { + if (unmatchedTokens.Count == 0) + { + return; + } + List args = [.. unmatchedTokens]; + if (unmatchedTokens.Count > 1) + { + // Automatically add MSBuild properties for 'dotnet run' or 'dotnet build' commands + if (args[1] == "run" || args[1] == "build") + { + args.Add($"-p:DiagnosticAddress={deviceTcpIpAddress}"); + args.Add($"-p:DiagnosticPort={deviceTcpIpPort}"); + args.Add($"-p:DiagnosticListenMode={listenMode}"); + // NOTE: -p:DiagnosticSuspend has to be provided by the user + } + } + + logMessageWithColor($"Running: {string.Join(' ', args)}", ConsoleColor.Green); + ProcessLauncher.Launcher.PrepareChildProcess(args); } private static void checkLoopbackOnly(string tcpServer, LogLevel logLevel) @@ -540,10 +596,7 @@ private static void checkLoopbackOnly(string tcpServer, LogLevel logLevel) message.Append("testing environments."); message.AppendLine(); - ConsoleColor currentColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(message.ToString()); - Console.ForegroundColor = currentColor; + logMessageWithColor(message.ToString(), ConsoleColor.Yellow); } } } diff --git a/src/Tools/dotnet-dsrouter/Program.cs b/src/Tools/dotnet-dsrouter/Program.cs index bfd3deecfd..d0f0edb3c1 100644 --- a/src/Tools/dotnet-dsrouter/Program.cs +++ b/src/Tools/dotnet-dsrouter/Program.cs @@ -158,13 +158,15 @@ private static Command IOSSimulatorRouterCommand() { RuntimeTimeoutOption, VerboseOption, InfoOption, BlockedSignalsOption, ParentProcessOption }; + command.TreatUnmatchedTokensAsErrors = false; command.SetAction((parseResult, ct) => new DiagnosticsServerRouterCommands().RunIpcServerIOSSimulatorRouter( ct, runtimeTimeout: parseResult.GetValue(RuntimeTimeoutOption), verbose: parseResult.GetValue(VerboseOption), info: parseResult.GetValue(InfoOption), - parentProcess: parseResult.GetValue(ParentProcessOption) + parentProcess: parseResult.GetValue(ParentProcessOption), + unmatchedTokens: parseResult.UnmatchedTokens )); return command; @@ -180,13 +182,15 @@ private static Command IOSRouterCommand() { RuntimeTimeoutOption, VerboseOption, InfoOption, BlockedSignalsOption, ParentProcessOption }; + command.TreatUnmatchedTokensAsErrors = false; command.SetAction((parseResult, ct) => new DiagnosticsServerRouterCommands().RunIpcServerIOSRouter( ct, runtimeTimeout: parseResult.GetValue(RuntimeTimeoutOption), verbose: parseResult.GetValue(VerboseOption), info: parseResult.GetValue(InfoOption), - parentProcess: parseResult.GetValue(ParentProcessOption) + parentProcess: parseResult.GetValue(ParentProcessOption), + unmatchedTokens: parseResult.UnmatchedTokens )); return command; @@ -202,13 +206,15 @@ private static Command AndroidEmulatorRouterCommand() { RuntimeTimeoutOption, VerboseOption, InfoOption, BlockedSignalsOption, ParentProcessOption }; + command.TreatUnmatchedTokensAsErrors = false; command.SetAction((parseResult, ct) => new DiagnosticsServerRouterCommands().RunIpcServerAndroidEmulatorRouter( ct, runtimeTimeout: parseResult.GetValue(RuntimeTimeoutOption), verbose: parseResult.GetValue(VerboseOption), info: parseResult.GetValue(InfoOption), - parentProcess: parseResult.GetValue(ParentProcessOption) + parentProcess: parseResult.GetValue(ParentProcessOption), + unmatchedTokens: parseResult.UnmatchedTokens )); return command; @@ -224,13 +230,15 @@ private static Command AndroidRouterCommand() { RuntimeTimeoutOption, VerboseOption, InfoOption, BlockedSignalsOption, ParentProcessOption }; + command.TreatUnmatchedTokensAsErrors = false; command.SetAction((parseResult, ct) => new DiagnosticsServerRouterCommands().RunIpcServerAndroidRouter( ct, runtimeTimeout: parseResult.GetValue(RuntimeTimeoutOption), verbose: parseResult.GetValue(VerboseOption), info: parseResult.GetValue(InfoOption), - parentProcess: parseResult.GetValue(ParentProcessOption) + parentProcess: parseResult.GetValue(ParentProcessOption), + unmatchedTokens: parseResult.UnmatchedTokens )); return command; @@ -320,6 +328,11 @@ private static Command AndroidRouterCommand() private static Task Main(string[] args) { + Command iosCommand = IOSRouterCommand(); + Command iosSimulatorCommand = IOSSimulatorRouterCommand(); + Command androidCommand = AndroidRouterCommand(); + Command androidEmulatorCommand = AndroidEmulatorRouterCommand(); + RootCommand rootCommand = new() { IpcClientTcpServerRouterCommand(), @@ -328,15 +341,20 @@ private static Task Main(string[] args) IpcClientTcpClientRouterCommand(), IpcServerWebSocketServerRouterCommand(), IpcClientWebSocketServerRouterCommand(), - IOSSimulatorRouterCommand(), - IOSRouterCommand(), - AndroidEmulatorRouterCommand(), - AndroidRouterCommand() + iosSimulatorCommand, + iosCommand, + androidEmulatorCommand, + androidCommand }; ParseResult parseResult = rootCommand.Parse(args); - if (parseResult.UnmatchedTokens.Count > 0) + string parsedCommandName = parseResult.CommandResult.Command.Name; + if (parseResult.UnmatchedTokens.Count > 0 && + parsedCommandName != iosCommand.Name && + parsedCommandName != iosSimulatorCommand.Name && + parsedCommandName != androidCommand.Name && + parsedCommandName != androidEmulatorCommand.Name) { ProcessLauncher.Launcher.PrepareChildProcess(args); } diff --git a/src/Tools/dotnet-dump/Dumper.cs b/src/Tools/dotnet-dump/Dumper.cs index 65c30d32f3..7ed658d958 100644 --- a/src/Tools/dotnet-dump/Dumper.cs +++ b/src/Tools/dotnet-dump/Dumper.cs @@ -35,7 +35,7 @@ public int Collect(TextWriter stdOutput, TextWriter stdError, int processId, str { try { - if (CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, string.Empty, out int resolvedProcessId)) + if (CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, string.Empty, [], out int resolvedProcessId)) { processId = resolvedProcessId; } diff --git a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs index 26af23d866..865ddbce61 100644 --- a/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs +++ b/src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.CommandLine; using System.IO; using System.Threading; @@ -27,10 +28,11 @@ internal static class CollectCommandHandler /// The process name to collect the gcdump from. /// The diagnostic IPC channel to collect the gcdump from. /// The dsrouter command to use for collecting the gcdump. + /// Unmatched tokens from the command line. /// - private static async Task Collect(CancellationToken ct, int processId, string output, int timeout, bool verbose, string name, string diagnosticPort, string dsrouter) + private static async Task Collect(CancellationToken ct, int processId, string output, int timeout, bool verbose, string name, string diagnosticPort, string dsrouter, IReadOnlyList unmatchedTokens) { - if (!CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, out int resolvedProcessId)) + if (!CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, unmatchedTokens, out int resolvedProcessId)) { return -1; } @@ -155,7 +157,9 @@ public static Command CollectCommand() verbose: parseResult.GetValue(VerboseOption), name: parseResult.GetValue(NameOption), diagnosticPort: parseResult.GetValue(DiagnosticPortOption) ?? string.Empty, - dsrouter: parseResult.GetValue(DsRouterOption) ?? string.Empty)); + dsrouter: parseResult.GetValue(DsRouterOption) ?? string.Empty, + unmatchedTokens: parseResult.UnmatchedTokens + )); return collectCommand; } diff --git a/src/Tools/dotnet-gcdump/CommandLine/ReportCommandHandler.cs b/src/Tools/dotnet-gcdump/CommandLine/ReportCommandHandler.cs index c0bab3af39..3936bc050d 100644 --- a/src/Tools/dotnet-gcdump/CommandLine/ReportCommandHandler.cs +++ b/src/Tools/dotnet-gcdump/CommandLine/ReportCommandHandler.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Binding; using System.IO; @@ -91,7 +92,7 @@ private static Task HandleUnknownParam() private static Task ReportFromProcess(int processId, string diagnosticPort, string dsrouter, CancellationToken ct) { - if (!CommandUtils.ResolveProcessForAttach(processId, string.Empty, diagnosticPort, dsrouter, out int resolvedProcessId)) + if (!CommandUtils.ResolveProcessForAttach(processId, string.Empty, diagnosticPort, dsrouter, [], out int resolvedProcessId)) { return Task.FromResult(-1); } diff --git a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs index 054a6e83a7..1c60ab0379 100644 --- a/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs +++ b/src/Tools/dotnet-trace/CommandLine/Commands/CollectCommand.cs @@ -53,8 +53,10 @@ private static void ConsoleWriteLine(string str) /// A string, parsed as-is, that will stop the trace upon hitting an event with the matching event name. Requires `--stopping-event-provider-name` to be set. For a more specific stopping event, additionally provide `--stopping-event-payload-filter`. /// A string, parsed as [payload_field_name]:[payload_field_value] pairs separated by commas, that will stop the trace upon hitting an event with a matching payload. Requires `--stopping-event-provider-name` and `--stopping-event-event-name` to be set. /// Collect rundown events. + /// Path to the data collector router to be used. + /// Any unmatched tokens from the command line. /// - private static async Task Collect(CancellationToken ct, CommandLineConfiguration cliConfig, int processId, FileInfo output, uint buffersize, string providers, string profile, TraceFileFormat format, TimeSpan duration, string clrevents, string clreventlevel, string name, string diagnosticPort, bool showchildio, bool resumeRuntime, string stoppingEventProviderName, string stoppingEventEventName, string stoppingEventPayloadFilter, bool? rundown, string dsrouter) + private static async Task Collect(CancellationToken ct, CommandLineConfiguration cliConfig, int processId, FileInfo output, uint buffersize, string providers, string profile, TraceFileFormat format, TimeSpan duration, string clrevents, string clreventlevel, string name, string diagnosticPort, bool showchildio, bool resumeRuntime, string stoppingEventProviderName, string stoppingEventEventName, string stoppingEventPayloadFilter, bool? rundown, string dsrouter, IReadOnlyList unmatchedTokens) { bool collectionStopped = false; bool cancelOnEnter = true; @@ -94,7 +96,7 @@ private static async Task Collect(CancellationToken ct, CommandLineConfigur Console.WriteLine("--show-child-io must not be specified when attaching to a process"); return (int)ReturnCode.ArgumentError; } - if (CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, out int resolvedProcessId)) + if (CommandUtils.ResolveProcessForAttach(processId, name, diagnosticPort, dsrouter, unmatchedTokens, out int resolvedProcessId)) { processId = resolvedProcessId; } @@ -605,11 +607,15 @@ public static Command CollectCommand() stoppingEventEventName: parseResult.GetValue(StoppingEventEventNameOption), stoppingEventPayloadFilter: parseResult.GetValue(StoppingEventPayloadFilterOption), rundown: parseResult.GetValue(RundownOption), - dsrouter: parseResult.GetValue(DSRouterOption))); + dsrouter: GetDSRouterOption(parseResult), + unmatchedTokens: parseResult.UnmatchedTokens)); return collectCommand; } + public static string GetDSRouterOption(ParseResult parseResult) => + parseResult.GetValue(DSRouterOption) ?? string.Empty; + private const uint DefaultCircularBufferSizeInMB = 256; private static readonly Option CircularBufferOption = diff --git a/src/Tools/dotnet-trace/Program.cs b/src/Tools/dotnet-trace/Program.cs index 69c3cff0be..4e4d0eaa26 100644 --- a/src/Tools/dotnet-trace/Program.cs +++ b/src/Tools/dotnet-trace/Program.cs @@ -29,8 +29,9 @@ public static Task Main(string[] args) if (parsedCommandName == "collect") { IReadOnlyCollection unparsedTokens = parseResult.UnmatchedTokens; + string dsrouter = CollectCommandHandler.GetDSRouterOption(parseResult); // If we notice there are unparsed tokens, user might want to attach on startup. - if (unparsedTokens.Count > 0) + if (string.IsNullOrEmpty(dsrouter) && unparsedTokens.Count > 0) { ProcessLauncher.Launcher.PrepareChildProcess(args); } diff --git a/src/tests/dotnet-counters/CounterMonitorPayloadTests.cs b/src/tests/dotnet-counters/CounterMonitorPayloadTests.cs index f1f6b554c0..efb1e51d74 100644 --- a/src/tests/dotnet-counters/CounterMonitorPayloadTests.cs +++ b/src/tests/dotnet-counters/CounterMonitorPayloadTests.cs @@ -217,7 +217,9 @@ await monitor.Collect( maxHistograms: 10, maxTimeSeries: 1000, duration: TimeSpan.FromSeconds(10), - dsrouter: null)); + dsrouter: null, + unmatchedTokens: [] + )); }, testRunner, source.Token); return CreateMetricComponents();