示例#1
0
        // <summary>
        // Starts the child process and returns the diagnostics client once the child proc connects to the reversed diagnostics pipe.
        // The callee needs to resume the diagnostics client at appropriate time.
        // </summary>
        public static DiagnosticsClient Build(ProcessLauncher childProcLauncher, string toolName, int timeoutInSec)
        {
            if (!childProcLauncher.HasChildProc)
            {
                throw new InvalidOperationException("Must have a valid child process to launch.");
            }
            // Create and start the reversed server
            string diagnosticTransportName   = GetTransportName(toolName);
            ReversedDiagnosticsServer server = new ReversedDiagnosticsServer(diagnosticTransportName);

            server.Start();

            // Start the child proc
            if (!childProcLauncher.Start(diagnosticTransportName))
            {
                throw new InvalidOperationException("Failed to start dotnet-counters.");
            }

            // Wait for attach
            IpcEndpointInfo endpointInfo = server.Accept(TimeSpan.FromSeconds(timeoutInSec));

            // If for some reason a different process attached to us, wait until the expected process attaches.
            while (endpointInfo.ProcessId != childProcLauncher.ChildProc.Id)
            {
                endpointInfo = server.Accept(TimeSpan.FromSeconds(timeoutInSec));
            }
            return(new DiagnosticsClient(endpointInfo.Endpoint));
        }
        public async Task <DiagnosticsClientHolder> Build(CancellationToken ct, int processId, string portName, bool showChildIO, bool printLaunchCommand)
        {
            if (ProcessLauncher.Launcher.HasChildProc)
            {
                // Create and start the reversed server
                string diagnosticTransportName   = GetTransportName(_toolName);
                ReversedDiagnosticsServer server = new ReversedDiagnosticsServer(diagnosticTransportName);
                server.Start();

                // Start the child proc
                if (!ProcessLauncher.Launcher.Start(diagnosticTransportName, ct, showChildIO, printLaunchCommand))
                {
                    throw new InvalidOperationException($"Failed to start '{ProcessLauncher.Launcher.ChildProc.StartInfo.FileName} {ProcessLauncher.Launcher.ChildProc.StartInfo.Arguments}'.");
                }
                IpcEndpointInfo endpointInfo;
                try
                {
                    // Wait for attach
                    endpointInfo = server.Accept(TimeSpan.FromSeconds(_timeoutInSec));

                    // If for some reason a different process attached to us, wait until the expected process attaches.
                    while (endpointInfo.ProcessId != ProcessLauncher.Launcher.ChildProc.Id)
                    {
                        endpointInfo = server.Accept(TimeSpan.FromSeconds(_timeoutInSec));
                    }
                }
                catch (TimeoutException)
                {
                    Console.Error.WriteLine("Unable to start tracing session - the target app failed to connect to the diagnostics port. This may happen if the target application is running .NET Core 3.1 or older versions. Attaching at startup is only available from .NET 5.0 or later.");
                    throw;
                }
                return(new DiagnosticsClientHolder(new DiagnosticsClient(endpointInfo.Endpoint), endpointInfo, server));
            }
            else if (!string.IsNullOrEmpty(portName))
            {
                ReversedDiagnosticsServer server = new ReversedDiagnosticsServer(portName);
                server.Start();
                string fullPort = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? portName : Path.GetFullPath(portName);
                Console.WriteLine($"Waiting for connection on {fullPort}");
                Console.WriteLine($"Start an application with the following environment variable: DOTNET_DiagnosticPorts={fullPort}");

                IpcEndpointInfo endpointInfo = await server.AcceptAsync(ct);

                return(new DiagnosticsClientHolder(new DiagnosticsClient(endpointInfo.Endpoint), endpointInfo, fullPort, server));
            }
            else
            {
                return(new DiagnosticsClientHolder(new DiagnosticsClient(processId)));
            }
        }
        /// <summary>
        /// Accepts endpoint infos from the reversed diagnostics server.
        /// </summary>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        private async Task ListenAsync(int maxConnections, CancellationToken token)
        {
            _server.Start(maxConnections);
            // Continuously accept endpoint infos from the reversed diagnostics server so
            // that <see cref="ReversedDiagnosticsServer.AcceptAsync(CancellationToken)"/>
            // is always awaited in order to to handle new runtime instance connections
            // as well as existing runtime instance reconnections.
            while (!token.IsCancellationRequested)
            {
                try
                {
                    IpcEndpointInfo info = await _server.AcceptAsync(token).ConfigureAwait(false);

                    _ = Task.Run(() => ResumeAndQueueEndpointInfo(info, token), token);
                }
                catch (OperationCanceledException)
                {
                }
            }
        }
示例#4
0
        public async Task RunRemoteServer()
        {
            var debuggee       = Path.GetFullPath(_debuggee);
            var diagnosticPort = $"Fusion_{Process.GetCurrentProcess().Id}";

            // 1. Start the diagnostic server
            ReversedDiagnosticsServer srv = new ReversedDiagnosticsServer(diagnosticPort);

            srv.Start();

            // 2. Start accepting connections
            using CancellationTokenSource cancellation = new CancellationTokenSource(20000);
            var acceptTask = srv.AcceptAsync(cancellation.Token);

            // 3. Run the debuggee
            Console.WriteLine("Starting child process using Diagnostic Port over Pipe");
            ProcessStartInfo psi = new(debuggee);

            psi.CreateNoWindow = false;
            psi.EnvironmentVariables[_diagPortEnvKey] = diagnosticPort;
            var process = Process.Start(psi);

            // 4. Wait for the remote CLR to connect with us
            var endpoint = await acceptTask;

            Console.WriteLine($"Remote process {endpoint.ProcessId} connected with cookie: {endpoint.RuntimeInstanceCookie}");


            // 5. Use the endpoint to start the diagnostic client
            using var fusion = new FusionTrace(endpoint.Endpoint);
            fusion.Start(e => SubscribeDynamicEvents(e), s => SubscribeRuntimeEvents(s));


            while (Console.ReadKey().Key != ConsoleKey.Q)
            {
                ;
            }
        }