// 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)) { await using var processor = new DiagnosticsEventPipeProcessor( PipeMode.ProcessInfo, processInfoCallback: cmdLine => { commandLine = cmdLine; return(Task.CompletedTask); }); try { await processor.Process( client, endpointInfo.ProcessId, Timeout.InfiniteTimeSpan, 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); } } } // The GetProcessInfo command will return "unknown" for values for which it does // not know the value, such as operating system and process architecture if the // process is running on one that is not predefined. Mimic the same behavior here // when the extra process information was not provided. return(new ProcessInfo( client, endpointInfo.RuntimeInstanceCookie, endpointInfo.ProcessId, processName ?? ProcessFieldUnknownValue, commandLine ?? ProcessFieldUnknownValue, endpointInfo.OperatingSystem ?? ProcessFieldUnknownValue, endpointInfo.ProcessArchitecture ?? ProcessFieldUnknownValue)); }
// 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)); }