Beispiel #1
0
        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);
        }