Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/Tools/Common/Commands/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ public static int FindProcessIdWithName(string name)
// </summary>
// <param name="dsrouter">dsrouterCommand</param>
// <returns>processId</returns>
public static int LaunchDSRouterProcess(string dsrouterCommand)
public static int LaunchDSRouterProcess(string dsrouterCommand, IReadOnlyList<string> 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);
}


Expand Down Expand Up @@ -80,9 +80,10 @@ public static bool ValidateArgumentsForChildProcess(int processId, string name,
/// <param name="name">name</param>
/// <param name="port">port</param>
/// <param name="dsrouter">dsrouter</param>
/// <param name="unmatchedTokens">unmatchedTokens</param>
/// <param name="resolvedProcessId">resolvedProcessId</param>
/// <returns></returns>
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<string> unmatchedTokens, out int resolvedProcessId)
{
resolvedProcessId = -1;
if (processId == 0 && string.IsNullOrEmpty(name) && string.IsNullOrEmpty(port) && string.IsNullOrEmpty(dsrouter))
Expand Down Expand Up @@ -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)
{
Expand Down
8 changes: 7 additions & 1 deletion src/Tools/Common/DsRouterProcessLauncher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<string> unmatchedTokens, CancellationToken ct)
{
string toolsRoot = System.IO.Path.GetDirectoryName(System.Environment.ProcessPath);
string dotnetDsrouterTool = "dotnet-dsrouter";
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions src/Tools/Common/ReversedServerHelpers/ReversedServerHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -32,6 +33,16 @@ public void PrepareChildProcess(string[] args)
return;
}

PrepareChildProcess(args, unparsedTokenIdx);
}

public void PrepareChildProcess(IEnumerable<string> unmatchedTokens)
{
PrepareChildProcess([.. unmatchedTokens], 0);
}

private void PrepareChildProcess(string[] args, int unparsedTokenIdx)
{
_childProc = new Process();
_childProc.StartInfo.FileName = args[unparsedTokenIdx];
string arguments = "";
Expand Down
10 changes: 6 additions & 4 deletions src/Tools/dotnet-counters/CounterMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ public async Task<ReturnCode> Monitor(
int maxTimeSeries,
TimeSpan duration,
bool showDeltas,
string dsrouter)
string dsrouter,
IReadOnlyList<string> unmatchedTokens)
{
try
{
Expand All @@ -186,7 +187,7 @@ public async Task<ReturnCode> 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;
}
Expand Down Expand Up @@ -261,7 +262,8 @@ public async Task<ReturnCode> Collect(
int maxHistograms,
int maxTimeSeries,
TimeSpan duration,
string dsrouter)
string dsrouter,
IReadOnlyList<string> unmatchedTokens)
{
try
{
Expand All @@ -271,7 +273,7 @@ public async Task<ReturnCode> 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;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Tools/dotnet-counters/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
103 changes: 78 additions & 25 deletions src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -357,44 +358,67 @@ public async Task<int> RunIpcClientWebSocketServerRouter(CancellationToken token
}
}

public async Task<int> RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess)
public async Task<int> RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList<string> 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<int> RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess)
public async Task<int> RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList<string> 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<int> RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess)
public async Task<int> RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList<string> 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<int> RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess)
public async Task<int> RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info, string parentProcess, IReadOnlyList<string> 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)
Expand Down Expand Up @@ -501,30 +525,62 @@ 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}:");
message.AppendLine($"dotnet-trace collect -p {pid}");
}
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<string> unmatchedTokens, string deviceTcpIpAddress, string deviceTcpIpPort, string listenMode)
{
if (unmatchedTokens.Count == 0)
{
return;
}
List<string> 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)
Expand All @@ -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);
}
}
}
Expand Down
Loading
Loading