Improve dotnet-dsrouter log levels and info. (#4199)
authorJohan Lorensson <lateralusx.github@gmail.com>
Mon, 2 Oct 2023 09:25:27 +0000 (11:25 +0200)
committerGitHub <noreply@github.com>
Mon, 2 Oct 2023 09:25:27 +0000 (11:25 +0200)
* Add support for -v none, suppressing all logging making
dotnet-dsrouter quiet.
* Add support for --info option for new iOS/Android preconfig commands,
outputs details on how to configure app and diagnostic tools to connect
to current running dsrouter instance.
*  Improve error handling when failing to find or execute adb binary.
*  Specify and validate supported verbose logging levels.

src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsServerRouter/DiagnosticsServerRouterFactory.cs
src/Tools/dotnet-dsrouter/ADBTcpRouterFactory.cs
src/Tools/dotnet-dsrouter/DiagnosticsServerRouterCommands.cs
src/Tools/dotnet-dsrouter/Program.cs

index a8f09868ed41ee00add91bef0aa88d03d49782b4..124d7bb333db671dd51905016fdba62f9d92566a 100644 (file)
@@ -406,6 +406,8 @@ namespace Microsoft.Diagnostics.NETCore.Client
 
         protected int TcpClientRetryTimeoutMs { get; set; } = 500;
 
+        protected ILogger Logger => _logger;
+
         public delegate TcpClientRouterFactory CreateInstanceDelegate(string tcpClient, int runtimeTimeoutMs, ILogger logger);
 
         public static TcpClientRouterFactory CreateDefaultInstance(string tcpClient, int runtimeTimeoutMs, ILogger logger)
index 5177e6b30711eea67750b0cab164ae0b1846b039..95c3abf28fd9cdc2ba7981a2a569c170acdccafd 100644 (file)
@@ -13,12 +13,12 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 {
     internal static class ADBCommandExec
     {
-        public static bool AdbAddPortForward(int port, ILogger logger)
+        public static bool AdbAddPortForward(int port, bool rethrow, ILogger logger)
         {
             bool ownsPortForward = false;
-            if (!RunAdbCommandInternal($"forward --list", $"tcp:{port}", 0, logger))
+            if (!RunAdbCommandInternal($"forward --list", $"tcp:{port}", 0, rethrow, logger))
             {
-                ownsPortForward = RunAdbCommandInternal($"forward tcp:{port} tcp:{port}", "", 0, logger);
+                ownsPortForward = RunAdbCommandInternal($"forward tcp:{port} tcp:{port}", "", 0, rethrow, logger);
                 if (!ownsPortForward)
                 {
                     logger?.LogError($"Failed setting up port forward for tcp:{port}.");
@@ -27,12 +27,12 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             return ownsPortForward;
         }
 
-        public static bool AdbAddPortReverse(int port, ILogger logger)
+        public static bool AdbAddPortReverse(int port, bool rethrow, ILogger logger)
         {
             bool ownsPortForward = false;
-            if (!RunAdbCommandInternal($"reverse --list", $"tcp:{port}", 0, logger))
+            if (!RunAdbCommandInternal($"reverse --list", $"tcp:{port}", 0, rethrow, logger))
             {
-                ownsPortForward = RunAdbCommandInternal($"reverse tcp:{port} tcp:{port}", "", 0, logger);
+                ownsPortForward = RunAdbCommandInternal($"reverse tcp:{port} tcp:{port}", "", 0, rethrow, logger);
                 if (!ownsPortForward)
                 {
                     logger?.LogError($"Failed setting up port forward for tcp:{port}.");
@@ -41,36 +41,36 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             return ownsPortForward;
         }
 
-        public static void AdbRemovePortForward(int port, bool ownsPortForward, ILogger logger)
+        public static void AdbRemovePortForward(int port, bool ownsPortForward, bool rethrow, ILogger logger)
         {
             if (ownsPortForward)
             {
-                if (!RunAdbCommandInternal($"forward --remove tcp:{port}", "", 0, logger))
+                if (!RunAdbCommandInternal($"forward --remove tcp:{port}", "", 0, rethrow, logger))
                 {
                     logger?.LogError($"Failed removing port forward for tcp:{port}.");
                 }
             }
         }
 
-        public static void AdbRemovePortReverse(int port, bool ownsPortForward, ILogger logger)
+        public static void AdbRemovePortReverse(int port, bool ownsPortForward, bool rethrow, ILogger logger)
         {
             if (ownsPortForward)
             {
-                if (!RunAdbCommandInternal($"reverse --remove tcp:{port}", "", 0, logger))
+                if (!RunAdbCommandInternal($"reverse --remove tcp:{port}", "", 0, rethrow, logger))
                 {
                     logger?.LogError($"Failed removing port forward for tcp:{port}.");
                 }
             }
         }
 
-        public static bool RunAdbCommandInternal(string command, string expectedOutput, int expectedExitCode, ILogger logger)
+        public static bool RunAdbCommandInternal(string command, string expectedOutput, int expectedExitCode, bool rethrow, ILogger logger)
         {
             string sdkRoot = Environment.GetEnvironmentVariable("ANDROID_SDK_ROOT");
             string adbTool = "adb";
 
             if (!string.IsNullOrEmpty(sdkRoot))
             {
-                adbTool = sdkRoot + Path.DirectorySeparatorChar + "platform-tools" + Path.DirectorySeparatorChar + adbTool;
+                adbTool = Path.Combine(sdkRoot, "platform-tools", adbTool);
             }
 
             logger?.LogDebug($"Executing {adbTool} {command}.");
@@ -94,7 +94,11 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             }
             catch (Exception ex)
             {
-                logger.LogError($"Failed executing {adbTool} {command}. Error: {ex.Message}.");
+                logger.LogError($"Failed executing {adbTool} {command}. Error: {ex.Message}");
+                if (rethrow)
+                {
+                    throw ex;
+                }
             }
 
             if (processStartedResult)
@@ -116,10 +120,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 {
                     logger.LogError($"stderr: {stderr.TrimEnd()}");
                 }
-            }
 
-            if (processStartedResult)
-            {
                 process.WaitForExit();
                 expectedExitCodeResult = (expectedExitCode != -1) ? (process.ExitCode == expectedExitCode) : true;
             }
@@ -149,7 +150,19 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
         public override void Start()
         {
             // Enable port reverse.
-            _ownsPortReverse = ADBCommandExec.AdbAddPortReverse(_port, Logger);
+            try
+            {
+                _ownsPortReverse = ADBCommandExec.AdbAddPortReverse(_port, true, Logger);
+            }
+            catch
+            {
+                _ownsPortReverse = false;
+                Logger.LogError("Failed setting up adb port reverse." +
+                    " This might lead to problems communicating with Android application." +
+                    " Make sure env variable ANDROID_SDK_ROOT is set and points to an Android SDK." +
+                    $" Executing with unknown adb status for port {_port}.");
+                return;
+            }
 
             _portReverseTaskCancelToken = new CancellationTokenSource();
             _portReverseTask = Task.Run(async () => {
@@ -157,7 +170,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 while (await timer.WaitForNextTickAsync(_portReverseTaskCancelToken.Token).ConfigureAwait(false) && !_portReverseTaskCancelToken.Token.IsCancellationRequested)
                 {
                     // Make sure reverse port configuration is still active.
-                    if (ADBCommandExec.AdbAddPortReverse(_port, Logger) && !_ownsPortReverse)
+                    if (ADBCommandExec.AdbAddPortReverse(_port, false, Logger) && !_ownsPortReverse)
                     {
                         _ownsPortReverse = true;
                     }
@@ -179,7 +192,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             catch { }
 
             // Disable port reverse.
-            ADBCommandExec.AdbRemovePortReverse(_port, _ownsPortReverse, Logger);
+            ADBCommandExec.AdbRemovePortReverse(_port, _ownsPortReverse, false, Logger);
             _ownsPortReverse = false;
         }
     }
@@ -205,7 +218,19 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
         public override void Start()
         {
             // Enable port forwarding.
-            _ownsPortForward = ADBCommandExec.AdbAddPortForward(_port, _logger);
+            try
+            {
+                _ownsPortForward = ADBCommandExec.AdbAddPortForward(_port, true, Logger);
+            }
+            catch
+            {
+                _ownsPortForward = false;
+                Logger.LogError("Failed setting up adb port forward." +
+                    " This might lead to problems communicating with Android application." +
+                    " Make sure env variable ANDROID_SDK_ROOT is set and points to an Android SDK." +
+                    $" Executing with unknown adb status for port {_port}.");
+                return;
+            }
 
             _portForwardTaskCancelToken = new CancellationTokenSource();
             _portForwardTask = Task.Run(async () => {
@@ -213,7 +238,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 while (await timer.WaitForNextTickAsync(_portForwardTaskCancelToken.Token).ConfigureAwait(false) && !_portForwardTaskCancelToken.Token.IsCancellationRequested)
                 {
                     // Make sure forward port configuration is still active.
-                    if (ADBCommandExec.AdbAddPortForward(_port, _logger) && !_ownsPortForward)
+                    if (ADBCommandExec.AdbAddPortForward(_port, false, Logger) && !_ownsPortForward)
                     {
                         _ownsPortForward = true;
                     }
@@ -231,7 +256,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             catch { }
 
             // Disable port forwarding.
-            ADBCommandExec.AdbRemovePortForward(_port, _ownsPortForward, _logger);
+            ADBCommandExec.AdbRemovePortForward(_port, _ownsPortForward, false, Logger);
             _ownsPortForward = false;
         }
     }
index 5b83ceda81fcbf7564a1e632daeef8682aa429fa..20fd5b312b32c65a5755377a2f440eef43eeb0c3 100644 (file)
@@ -72,27 +72,8 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 LogLevel = logLevel;
             }
 
-            protected SpecificRunnerBase(string logLevel) : this(ParseLogLevel(logLevel))
-            {
-            }
-
             public abstract void ConfigureLauncher(CancellationToken cancellationToken);
 
-            protected static LogLevel ParseLogLevel(string verbose)
-            {
-                LogLevel logLevel = LogLevel.Information;
-                if (string.Equals(verbose, "debug", StringComparison.OrdinalIgnoreCase))
-                {
-                    logLevel = LogLevel.Debug;
-                }
-                else if (string.Equals(verbose, "trace", StringComparison.OrdinalIgnoreCase))
-                {
-                    logLevel = LogLevel.Trace;
-                }
-
-                return logLevel;
-            }
-
             // The basic run loop: configure logging and the launcher, then create the router and run it until it exits or the user interrupts
             public async Task<int> CommonRunLoop(Func<ILogger, DiagnosticsServerRouterRunner.ICallbacks, CancellationTokenSource, Task<int>> createRouterTask, CancellationToken token)
             {
@@ -103,9 +84,11 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
                 ConfigureLauncher(token);
 
-                ILogger logger = loggerFactory.CreateLogger("dotnet-dsrouter");
+                int pid = Process.GetCurrentProcess().Id;
+
+                ILogger logger = loggerFactory.CreateLogger($"dotnet-dsrouter-{pid}");
 
-                logger.LogInformation($"Starting dotnet-dsrouter using pid={Process.GetCurrentProcess().Id}");
+                logger.LogInformation($"Starting dotnet-dsrouter using pid={pid}");
 
                 Task<int> routerTask = createRouterTask(logger, Launcher, linkedCancelToken);
 
@@ -147,13 +130,13 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcClientTcpServerRunner : SpecificRunnerBase
         {
-            public IpcClientTcpServerRunner(string verbose) : base(verbose) { }
+            public IpcClientTcpServerRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = true;
                 Launcher.ConnectMode = true;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
 
@@ -169,9 +152,11 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         public async Task<int> RunIpcClientTcpServerRouter(CancellationToken token, string ipcClient, string tcpServer, int runtimeTimeout, string verbose, string forwardPort)
         {
-            checkLoopbackOnly(tcpServer);
+            LogLevel logLevel = ParseLogLevel(verbose);
 
-            IpcClientTcpServerRunner runner = new(verbose);
+            checkLoopbackOnly(tcpServer, logLevel);
+
+            IpcClientTcpServerRunner runner = new(logLevel);
 
             return await runner.CommonRunLoop((logger, launcherCallbacks, linkedCancelToken) => {
                 NetServerRouterFactory.CreateInstanceDelegate tcpServerRouterFactory = ChooseTcpServerRouterFactory(forwardPort, logger);
@@ -183,22 +168,24 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcServerTcpServerRunner : SpecificRunnerBase
         {
-            public IpcServerTcpServerRunner(string verbose) : base(verbose) { }
+            public IpcServerTcpServerRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = false;
                 Launcher.ConnectMode = true;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
         }
 
         public async Task<int> RunIpcServerTcpServerRouter(CancellationToken token, string ipcServer, string tcpServer, int runtimeTimeout, string verbose, string forwardPort)
         {
-            checkLoopbackOnly(tcpServer);
+            LogLevel logLevel = ParseLogLevel(verbose);
+
+            checkLoopbackOnly(tcpServer, logLevel);
 
-            IpcServerTcpServerRunner runner = new(verbose);
+            IpcServerTcpServerRunner runner = new(logLevel);
 
             return await runner.CommonRunLoop((logger, launcherCallbacks, linkedCancelToken) => {
                 NetServerRouterFactory.CreateInstanceDelegate tcpServerRouterFactory = ChooseTcpServerRouterFactory(forwardPort, logger);
@@ -215,20 +202,20 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcServerTcpClientRunner : SpecificRunnerBase
         {
-            public IpcServerTcpClientRunner(string verbose) : base(verbose) { }
+            public IpcServerTcpClientRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = false;
                 Launcher.ConnectMode = false;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
         }
 
         public async Task<int> RunIpcServerTcpClientRouter(CancellationToken token, string ipcServer, string tcpClient, int runtimeTimeout, string verbose, string forwardPort)
         {
-            IpcServerTcpClientRunner runner = new(verbose);
+            IpcServerTcpClientRunner runner = new(ParseLogLevel(verbose));
             return await runner.CommonRunLoop((logger, launcherCallbacks, linkedCancelToken) => {
                 TcpClientRouterFactory.CreateInstanceDelegate tcpClientRouterFactory = ChooseTcpClientRouterFactory(forwardPort, logger);
 
@@ -244,20 +231,20 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcClientTcpClientRunner : SpecificRunnerBase
         {
-            public IpcClientTcpClientRunner(string verbose) : base(verbose) { }
+            public IpcClientTcpClientRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = true;
                 Launcher.ConnectMode = false;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
         }
 
         public async Task<int> RunIpcClientTcpClientRouter(CancellationToken token, string ipcClient, string tcpClient, int runtimeTimeout, string verbose, string forwardPort)
         {
-            IpcClientTcpClientRunner runner = new(verbose);
+            IpcClientTcpClientRunner runner = new(ParseLogLevel(verbose));
             return await runner.CommonRunLoop((logger, launcherCallbacks, linkedCancelToken) => {
                 TcpClientRouterFactory.CreateInstanceDelegate tcpClientRouterFactory = ChooseTcpClientRouterFactory(forwardPort, logger);
 
@@ -268,20 +255,20 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcServerWebSocketServerRunner : SpecificRunnerBase
         {
-            public IpcServerWebSocketServerRunner(string verbose) : base(verbose) { }
+            public IpcServerWebSocketServerRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = false;
                 Launcher.ConnectMode = true;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
         }
 
         public async Task<int> RunIpcServerWebSocketServerRouter(CancellationToken token, string ipcServer, string webSocket, int runtimeTimeout, string verbose)
         {
-            IpcServerWebSocketServerRunner runner = new(verbose);
+            IpcServerWebSocketServerRunner runner = new(ParseLogLevel(verbose));
 
             WebSocketServer.WebSocketServerImpl server = new(runner.LogLevel);
 
@@ -311,20 +298,20 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private sealed class IpcClientWebSocketServerRunner : SpecificRunnerBase
         {
-            public IpcClientWebSocketServerRunner(string verbose) : base(verbose) { }
+            public IpcClientWebSocketServerRunner(LogLevel logLevel) : base(logLevel) { }
 
             public override void ConfigureLauncher(CancellationToken cancellationToken)
             {
                 Launcher.SuspendProcess = true;
                 Launcher.ConnectMode = true;
-                Launcher.Verbose = LogLevel != LogLevel.Information;
+                Launcher.Verbose = LogLevel < LogLevel.Information;
                 Launcher.CommandToken = cancellationToken;
             }
         }
 
         public async Task<int> RunIpcClientWebSocketServerRouter(CancellationToken token, string ipcClient, string webSocket, int runtimeTimeout, string verbose)
         {
-            IpcClientWebSocketServerRunner runner = new(verbose);
+            IpcClientWebSocketServerRunner runner = new(ParseLogLevel(verbose));
 
             WebSocketServer.WebSocketServerImpl server = new(runner.LogLevel);
 
@@ -347,27 +334,43 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             }
         }
 
-        public async Task<int> RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose)
+        public async Task<int> RunIpcServerIOSSimulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info)
         {
-            logDiagnosticPortsConfiguration("ios simulator", "127.0.0.1:9000", false, verbose);
-            return await RunIpcServerTcpServerRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "").ConfigureAwait(false);
+            if (info)
+            {
+                logRouterUsageInfo("ios simulator", "127.0.0.1:9000", true);
+            }
+
+            return await RunIpcServerTcpClientRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "").ConfigureAwait(false);
         }
 
-        public async Task<int> RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose)
+        public async Task<int> RunIpcServerIOSRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info)
         {
-            logDiagnosticPortsConfiguration("ios device", "127.0.0.1:9000", true, verbose);
+            if (info)
+            {
+                logRouterUsageInfo("ios device", "127.0.0.1:9000", true);
+            }
+
             return await RunIpcServerTcpClientRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "iOS").ConfigureAwait(false);
         }
 
-        public async Task<int> RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose)
+        public async Task<int> RunIpcServerAndroidEmulatorRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info)
         {
-            logDiagnosticPortsConfiguration("android emulator", "10.0.2.2:9000", false, verbose);
+            if (info)
+            {
+                logRouterUsageInfo("android emulator", "10.0.2.2:9000", false);
+            }
+
             return await RunIpcServerTcpServerRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "").ConfigureAwait(false);
         }
 
-        public async Task<int> RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose)
+        public async Task<int> RunIpcServerAndroidRouter(CancellationToken token, int runtimeTimeout, string verbose, bool info)
         {
-            logDiagnosticPortsConfiguration("android emulator", "127.0.0.1:9000", false, verbose);
+            if (info)
+            {
+                logRouterUsageInfo("android device", "127.0.0.1:9000", false);
+            }
+
             return await RunIpcServerTcpServerRouter(token, "", "127.0.0.1:9000", runtimeTimeout, verbose, "Android").ConfigureAwait(false);
         }
 
@@ -436,26 +439,71 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
             return tcpServerRouterFactory;
         }
 
-        private static void logDiagnosticPortsConfiguration(string deviceName, string deviceTcpIpAddress, bool deviceListenMode, string verbose)
+        private static LogLevel ParseLogLevel(string verbose)
         {
-            StringBuilder message = new();
-
-            if (!string.IsNullOrEmpty(verbose))
+            LogLevel logLevel;
+            if (string.Equals(verbose, "none", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.None;
+            }
+            else if (string.Equals(verbose, "critical", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Critical;
+            }
+            else if (string.Equals(verbose, "error", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Error;
+            }
+            else if (string.Equals(verbose, "warning", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Warning;
+            }
+            else if (string.Equals(verbose, "info", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Information;
+            }
+            else if (string.Equals(verbose, "debug", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Debug;
+            }
+            else if (string.Equals(verbose, "trace", StringComparison.OrdinalIgnoreCase))
+            {
+                logLevel = LogLevel.Trace;
+            }
+            else
             {
-                deviceName = !string.IsNullOrEmpty(deviceName) ? $" on {deviceName} " : " ";
-                message.AppendLine($"Start an application{deviceName}with one of the following environment variables set:");
+                throw new ArgumentException($"Unknown verbose log level, {verbose}");
             }
 
-            string listenMode = deviceListenMode ? ",listen" : ",connect";
-            message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},nosuspend{listenMode}");
-            message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},suspend{listenMode}");
+            return logLevel;
+        }
+
+        private static void logRouterUsageInfo(string deviceName, string deviceTcpIpAddress, bool deviceListenMode)
+        {
+            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("[Default Tracing]");
+            message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},nosuspend,{listenMode}");
+            message.AppendLine("[Startup Tracing]");
+            message.AppendLine($"DOTNET_DiagnosticPorts={deviceTcpIpAddress},suspend,{listenMode}");
+            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.");
+
+            ConsoleColor currentColor = Console.ForegroundColor;
+            Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine(message.ToString());
+            Console.ForegroundColor = currentColor;
         }
 
-        private static void checkLoopbackOnly(string tcpServer)
+        private static void checkLoopbackOnly(string tcpServer, LogLevel logLevel)
         {
-            if (!string.IsNullOrEmpty(tcpServer) && !DiagnosticsServerRouterRunner.isLoopbackOnly(tcpServer))
+            if (logLevel != LogLevel.None && !string.IsNullOrEmpty(tcpServer) && !DiagnosticsServerRouterRunner.isLoopbackOnly(tcpServer))
             {
                 StringBuilder message = new();
 
index 4ed1a3ee98c8963054305ebc6269def02ef0d86d..bc3b53281ddeba7fa19393b48b07a7322d9008a9 100644 (file)
@@ -27,13 +27,13 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
 
         private delegate Task<int> DiagnosticsServerIpcClientWebSocketServerRouterDelegate(CancellationToken ct, string ipcClient, string webSocket, int runtimeTimeoutS, string verbose);
 
-        private delegate Task<int> DiagnosticsServerIpcServerIOSSimulatorRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose);
+        private delegate Task<int> DiagnosticsServerIpcServerIOSSimulatorRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose, bool info);
 
-        private delegate Task<int> DiagnosticsServerIpcServerIOSRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose);
+        private delegate Task<int> DiagnosticsServerIpcServerIOSRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose, bool info);
 
-        private delegate Task<int> DiagnosticsServerIpcServerAndroidEmulatorRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose);
+        private delegate Task<int> DiagnosticsServerIpcServerAndroidEmulatorRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose, bool info);
 
-        private delegate Task<int> DiagnosticsServerIpcServerAndroidRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose);
+        private delegate Task<int> DiagnosticsServerIpcServerAndroidRouterDelegate(CancellationToken ct, int runtimeTimeoutS, string verbose, bool info);
 
         private static Command IpcClientTcpServerRouterCommand() =>
             new(
@@ -122,7 +122,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 // Handler
                 HandlerDescriptor.FromDelegate((DiagnosticsServerIpcServerIOSSimulatorRouterDelegate)new DiagnosticsServerRouterCommands().RunIpcServerIOSSimulatorRouter).GetCommandHandler(),
                 // Options
-                RuntimeTimeoutOption(), VerboseOption()
+                RuntimeTimeoutOption(), VerboseOption(), InfoOption()
             };
 
         private static Command IOSRouterCommand() =>
@@ -135,7 +135,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                         // Handler
                         HandlerDescriptor.FromDelegate((DiagnosticsServerIpcServerIOSRouterDelegate)new DiagnosticsServerRouterCommands().RunIpcServerIOSRouter).GetCommandHandler(),
                         // Options
-                        RuntimeTimeoutOption(), VerboseOption()
+                        RuntimeTimeoutOption(), VerboseOption(), InfoOption()
             };
 
         private static Command AndroidEmulatorRouterCommand() =>
@@ -148,7 +148,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                         // Handler
                         HandlerDescriptor.FromDelegate((DiagnosticsServerIpcServerAndroidEmulatorRouterDelegate)new DiagnosticsServerRouterCommands().RunIpcServerAndroidEmulatorRouter).GetCommandHandler(),
                         // Options
-                        RuntimeTimeoutOption(), VerboseOption()
+                        RuntimeTimeoutOption(), VerboseOption(), InfoOption()
             };
 
         private static Command AndroidRouterCommand() =>
@@ -161,7 +161,7 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                         // Handler
                         HandlerDescriptor.FromDelegate((DiagnosticsServerIpcServerAndroidRouterDelegate)new DiagnosticsServerRouterCommands().RunIpcServerAndroidRouter).GetCommandHandler(),
                         // Options
-                        RuntimeTimeoutOption(), VerboseOption()
+                        RuntimeTimeoutOption(), VerboseOption(), InfoOption()
             };
 
         private static Option IpcClientAddressOption() =>
@@ -226,9 +226,9 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
         private static Option VerboseOption() =>
             new(
                 aliases: new[] { "--verbose", "-v" },
-                description: "Enable verbose logging (debug|trace)")
+                description: "Enable verbose logging (none|critical|error|warning|info|debug|trace)")
             {
-                Argument = new Argument<string>(name: "verbose", getDefaultValue: () => "")
+                Argument = new Argument<string>(name: "verbose", getDefaultValue: () => "info")
             };
 
         private static Option ForwardPortOption() =>
@@ -239,13 +239,16 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 Argument = new Argument<string>(name: "forwardPort", getDefaultValue: () => "")
             };
 
+        private static Option InfoOption() =>
+            new(
+                aliases: new[] { "--info", "-i" },
+                description: "Print info on how to use current dotnet-dsrouter instance with application and diagnostic tooling.")
+            {
+                Argument = new Argument<bool>(name: "info", getDefaultValue: () => false)
+            };
+
         private static int Main(string[] args)
         {
-            ConsoleColor currentColor = Console.ForegroundColor;
-            Console.ForegroundColor = ConsoleColor.Yellow;
-            Console.WriteLine("WARNING: dotnet-dsrouter is a development tool not intended for production environments." + Environment.NewLine);
-            Console.ForegroundColor = currentColor;
-
             Parser parser = new CommandLineBuilder()
                 .AddCommand(IpcClientTcpServerRouterCommand())
                 .AddCommand(IpcServerTcpServerRouterCommand())
@@ -267,6 +270,15 @@ namespace Microsoft.Diagnostics.Tools.DiagnosticsServerRouter
                 ProcessLauncher.Launcher.PrepareChildProcess(args);
             }
 
+            string verbose = parseResult.ValueForOption<string>("-v");
+            if (!string.Equals(verbose, "none", StringComparison.OrdinalIgnoreCase))
+            {
+                ConsoleColor currentColor = Console.ForegroundColor;
+                Console.ForegroundColor = ConsoleColor.Yellow;
+                Console.WriteLine("WARNING: dotnet-dsrouter is a development tool not intended for production environments." + Environment.NewLine);
+                Console.ForegroundColor = currentColor;
+            }
+
             return parser.InvokeAsync(args).Result;
         }
     }