예제 #1
0
            // Creates a ProcessInfo object from the IEndpointInfo. Attempts to get the command line using event pipe
            // if the endpoint information doesn't provide it. The cancelation token can be used to timebox this fallback
            // mechansim.
            public static async Task <ProcessInfo> FromEndpointInfoAsync(IEndpointInfo endpointInfo, CancellationToken extendedInfoCancellationToken)
            {
                if (null == endpointInfo)
                {
                    throw new ArgumentNullException(nameof(endpointInfo));
                }

                var client = new DiagnosticsClient(endpointInfo.Endpoint);

                string commandLine = endpointInfo.CommandLine;

                if (string.IsNullOrEmpty(commandLine))
                {
                    try
                    {
                        var infoSettings = new EventProcessInfoPipelineSettings
                        {
                            Duration = Timeout.InfiniteTimeSpan,
                        };

                        await using var pipeline = new EventProcessInfoPipeline(client, infoSettings,
                                                                                (cmdLine, token) => { commandLine = cmdLine; return(Task.CompletedTask); });

                        await pipeline.RunAsync(extendedInfoCancellationToken);
                    }
                    catch
                    {
                    }
                }

                string processName = null;

                if (!string.IsNullOrEmpty(commandLine))
                {
                    // Get the process name from the command line
                    bool isWindowsProcess = false;
                    if (string.IsNullOrEmpty(endpointInfo.OperatingSystem))
                    {
                        // If operating system is null, the process is likely .NET Core 3.1 (which doesn't have the GetProcessInfo command).
                        // Since the underlying diagnostic communication channel used by the .NET runtime requires that the diagnostic process
                        // must be running on the same type of operating system as the target process (e.g. dotnet-monitor must be running on Windows
                        // if the target process is running on Windows), then checking the local operating system should be a sufficient heuristic
                        // to determine the operating system of the target process.
                        isWindowsProcess = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                    }
                    else
                    {
                        isWindowsProcess = ProcessOperatingSystemWindowsValue.Equals(endpointInfo.OperatingSystem, StringComparison.OrdinalIgnoreCase);
                    }

                    string processPath = CommandLineHelper.ExtractExecutablePath(commandLine, isWindowsProcess);
                    if (!string.IsNullOrEmpty(processPath))
                    {
                        processName = Path.GetFileName(processPath);
                        if (isWindowsProcess)
                        {
                            // Remove the extension on Windows to match the behavior of Process.ProcessName
                            processName = Path.GetFileNameWithoutExtension(processName);
                        }
                    }
                }

                return(new ProcessInfo(
                           endpointInfo,
                           commandLine,
                           processName));
            }
예제 #2
0
        // Creates an IProcessInfo object from the IEndpointInfo. Attempts to get the command line using event pipe
        // if the endpoint information doesn't provide it. The cancelation token can be used to timebox this fallback
        // mechanism.
        public static async Task <IProcessInfo> FromEndpointInfoAsync(IEndpointInfo endpointInfo, CancellationToken extendedInfoCancellationToken)
        {
            if (null == endpointInfo)
            {
                throw new ArgumentNullException(nameof(endpointInfo));
            }

            DiagnosticsClient client = new(endpointInfo.Endpoint);

            string commandLine = endpointInfo.CommandLine;

            if (string.IsNullOrEmpty(commandLine))
            {
                // The EventProcessInfoPipeline will frequently hang during disposal of its
                // EventPipeStreamProvider, which is trying to send a SessionStop command to
                // stop the event pipe session. When this happens, it waits for the 30 timeout
                // before giving up. Because this is happening during a disposal call, it is
                // not cancellable and hangs the entire operation for at least 30 seconds. To
                // mitigate, start the pipeline, get the command line, and they start the disposal
                // on a separate Task that is not awaited.
                EventProcessInfoPipeline pipeline = null;
                try
                {
                    TaskCompletionSource <string> commandLineSource =
                        new(TaskCreationOptions.RunContinuationsAsynchronously);

                    using IDisposable registration = extendedInfoCancellationToken.Register(
                              () => commandLineSource.TrySetResult(null));

                    EventProcessInfoPipelineSettings settings = new()
                    {
                        Duration = Timeout.InfiniteTimeSpan
                    };

                    pipeline = new EventProcessInfoPipeline(client, settings,
                                                            (cmdLine, token) => { commandLineSource.TrySetResult(cmdLine); return(Task.CompletedTask); });

                    await pipeline.StartAsync(extendedInfoCancellationToken);

                    commandLine = await commandLineSource.Task;
                }
                catch
                {
                }
                finally
                {
                    if (null != pipeline)
                    {
                        _ = Task.Run(() => pipeline.DisposeAsync());
                    }
                }
            }

            string processName = null;

            if (!string.IsNullOrEmpty(commandLine))
            {
                // Get the process name from the command line
                bool isWindowsProcess = false;
                if (string.IsNullOrEmpty(endpointInfo.OperatingSystem))
                {
                    // If operating system is null, the process is likely .NET Core 3.1 (which doesn't have the GetProcessInfo command).
                    // Since the underlying diagnostic communication channel used by the .NET runtime requires that the diagnostic process
                    // must be running on the same type of operating system as the target process (e.g. dotnet-monitor must be running on Windows
                    // if the target process is running on Windows), then checking the local operating system should be a sufficient heuristic
                    // to determine the operating system of the target process.
                    isWindowsProcess = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
                }
                else
                {
                    isWindowsProcess = ProcessOperatingSystemWindowsValue.Equals(endpointInfo.OperatingSystem, StringComparison.OrdinalIgnoreCase);
                }

                string processPath = CommandLineHelper.ExtractExecutablePath(commandLine, isWindowsProcess);
                if (!string.IsNullOrEmpty(processPath))
                {
                    processName = Path.GetFileName(processPath);
                    if (isWindowsProcess)
                    {
                        // Remove the extension on Windows to match the behavior of Process.ProcessName
                        processName = Path.GetFileNameWithoutExtension(processName);
                    }
                }
            }

            return(new ProcessInfoImpl(
                       endpointInfo,
                       commandLine,
                       processName));
        }