public static DiagProcessFilter FromConfiguration(IEnumerable <ProcessFilterDescriptor> filters) { var filter = new DiagProcessFilter(); foreach (ProcessFilterDescriptor processFilter in filters) { filter.Filters.Add(TransformDescriptor(processFilter)); } return(filter); }
public static DiagProcessFilter FromProcessKey(ProcessKey processKey) { var filter = new DiagProcessFilter(); List <DiagProcessFilterEntry> filterEntries = TransformKey(processKey); for (int index = 0; index < filterEntries.Count; ++index) { filter.Filters.Add(filterEntries[index]); } return(filter); }
public Task <IProcessInfo> GetProcessAsync(ProcessKey?processKey, CancellationToken token) { DiagProcessFilter filterOptions = null; if (processKey.HasValue) { filterOptions = DiagProcessFilter.FromProcessKey(processKey.Value); } else { filterOptions = DiagProcessFilter.FromConfiguration(_defaultProcessOptions.CurrentValue); } return(GetProcessAsync(filterOptions, token)); }
private async Task <IProcessInfo> GetProcessAsync(DiagProcessFilter processFilterConfig, CancellationToken token) { //Short circuit when we are missing default process config if (!processFilterConfig.Filters.Any()) { throw new InvalidOperationException(Strings.ErrorMessage_NoDefaultProcessConfig); } IEnumerable <IProcessInfo> matchingProcesses = await GetProcessesAsync(processFilterConfig, token); switch (matchingProcesses.Count()) { case 0: throw new ArgumentException(Strings.ErrorMessage_NoTargetProcess); case 1: return(matchingProcesses.First()); default: throw new ArgumentException(Strings.ErrorMessage_MultipleTargetProcesses); } }
public async Task <IEnumerable <IProcessInfo> > GetProcessesAsync(DiagProcessFilter processFilterConfig, CancellationToken token) { IEnumerable <IProcessInfo> processes = null; try { using CancellationTokenSource extendedInfoCancellation = CancellationTokenSource.CreateLinkedTokenSource(token); IList <Task <IProcessInfo> > processInfoTasks = new List <Task <IProcessInfo> >(); foreach (IEndpointInfo endpointInfo in await _endpointInfoSource.GetEndpointInfoAsync(token)) { // CONSIDER: Can this processing be pushed into the IEndpointInfoSource implementation and cached // so that extended process information doesn't have to be recalculated for every call. This would be // useful for: // - .NET Core 3.1 processes, which require issuing a brief event pipe session to get the process commmand // line information and parse out the process name // - Caching entrypoint information (when that becomes available). processInfoTasks.Add(ProcessInfoImpl.FromEndpointInfoAsync(endpointInfo, extendedInfoCancellation.Token)); } // FromEndpointInfoAsync can fill in the command line for .NET Core 3.1 processes by invoking the // event pipe and capturing the ProcessInfo event. Timebox this operation with the cancellation token // so that getting the process list does not take a long time or wait indefinitely. extendedInfoCancellation.CancelAfter(ProcessInfoImpl.ExtendedProcessInfoTimeout); await Task.WhenAll(processInfoTasks); processes = processInfoTasks.Select(t => t.Result); } catch (UnauthorizedAccessException) { throw new InvalidOperationException(Strings.ErrorMessage_ProcessEnumeratuinFailed); } if (processFilterConfig != null) { processes = processes.Where(p => processFilterConfig.Filters.All(c => c.MatchFilter(p))); } return(processes.ToArray()); }