public async Task Process(DiagnosticsClient client, TimeSpan duration, CancellationToken token) { //No need to guard against reentrancy here, since the calling pipeline does this already. IDisposable registration = token.Register(() => _sessionStarted.TrySetCanceled()); await await Task.Factory.StartNew(async() => { EventPipeEventSource source = null; DiagnosticsMonitor monitor = null; Task handleEventsTask = Task.CompletedTask; try { MonitoringSourceConfiguration config = null; if (_mode == PipeMode.Logs) { config = new LoggingSourceConfiguration(_logsLevel); } else if (_mode == PipeMode.Metrics) { config = new MetricSourceConfiguration(_metricIntervalSeconds, _counterFilter.GetProviders()); } else if (_mode == PipeMode.GCDump) { config = new GCDumpSourceConfiguration(); } else if (_mode == PipeMode.ProcessInfo) { config = new SampleProfilerConfiguration(); } else if (_mode == PipeMode.Nettrace) { config = _userConfig; } monitor = new DiagnosticsMonitor(config); // Allows the event handling routines to stop processing before the duration expires. Func <Task> stopFunc = () => Task.Run(() => { monitor.StopProcessing(); }); Stream sessionStream = await monitor.ProcessEvents(client, duration, token); if (_mode == PipeMode.Nettrace) { if (!_sessionStarted.TrySetResult(true)) { token.ThrowIfCancellationRequested(); } lock (_lock) { //Save the stop function for later, so that we can stop a trace later. _stopFunc = stopFunc; } await _onStreamAvailable(sessionStream, token); return; } source = new EventPipeEventSource(sessionStream); if (_mode == PipeMode.Metrics) { // Metrics HandleEventCounters(source); } else if (_mode == PipeMode.Logs) { // Logging HandleLoggingEvents(source); } else if (_mode == PipeMode.GCDump) { // GC handleEventsTask = HandleGCEvents(source, stopFunc, token); } else if (_mode == PipeMode.ProcessInfo) { // ProcessInfo handleEventsTask = HandleProcessInfo(source, stopFunc, token); } lock (_lock) { _eventPipeSession = source; _stopFunc = stopFunc; } registration.Dispose(); if (!_sessionStarted.TrySetResult(true)) { token.ThrowIfCancellationRequested(); } source.Process(); token.ThrowIfCancellationRequested(); } catch (DiagnosticsClientException ex) { throw new InvalidOperationException("Failed to start the event pipe session", ex); } finally { ExecuteCounterLoggerAction((metricLogger) => metricLogger.PipelineStopped()); registration.Dispose(); EventPipeEventSource session = null; lock (_lock) { session = _eventPipeSession; _eventPipeSession = null; } session?.Dispose(); if (monitor != null) { await monitor.DisposeAsync(); } } // Await the task returned by the event handling method AFTER the EventPipeEventSource is disposed. // The EventPipeEventSource will only raise the Completed event when it is disposed. So if this task // is waiting for the Completed event to be raised, it will never complete until after EventPipeEventSource // is diposed. await handleEventsTask; }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
public async Task <int> Start(CancellationToken token, IConsole console, int processId, int refreshInterval, SinkType sink, IEnumerable <FileInfo> jsonConfigs, IEnumerable <FileInfo> keyFileConfigs) { //CONSIDER The console sink uses the standard AddConsole, and therefore disregards IConsole. ServiceCollection services = new ServiceCollection(); ConfigurationBuilder builder = new ConfigurationBuilder(); if (jsonConfigs != null) { foreach (FileInfo jsonFile in jsonConfigs) { builder.SetBasePath(jsonFile.DirectoryName).AddJsonFile(jsonFile.Name, optional: true); } } if (keyFileConfigs != null) { foreach (FileInfo keyFileConfig in keyFileConfigs) { console.Out.WriteLine(keyFileConfig.FullName); builder.AddKeyPerFile(keyFileConfig.FullName, optional: true); } } ConfigureNames(builder); IConfigurationRoot config = builder.Build(); services.AddSingleton <IConfiguration>(config); //Specialized logger for diagnostic output from the service itself rather than as a sink for the data services.AddSingleton <ILogger <DiagnosticsMonitor> >((sp) => new ConsoleLoggerAdapter(console)); if (sink.HasFlag(SinkType.Console)) { services.AddSingleton <IMetricsLogger, ConsoleMetricsLogger>(); } if (sink.HasFlag(SinkType.LogAnalytics)) { services.AddSingleton <IMetricsLogger, MetricsLogger>(); } services.AddLogging(builder => { if (sink.HasFlag(SinkType.Console)) { builder.AddConsole(); } if (sink.HasFlag(SinkType.LogAnalytics)) { builder.AddProvider(new LogAnalyticsLoggerProvider()); } }); services.Configure <ContextConfiguration>(config); if (sink.HasFlag(SinkType.LogAnalytics)) { services.Configure <MetricsConfiguration>(config); services.Configure <ResourceConfiguration>(config); } await using var monitor = new DiagnosticsMonitor(services.BuildServiceProvider(), new MonitoringSourceConfiguration(refreshInterval)); await monitor.ProcessEvents(processId, token); return(0); }