예제 #1
0
        private static void Run(string appName, IConfigurationRoot config)
        {
            var pid = FindPidByAppName(appName);

            if (pid == -1)
            {
                Console.WriteLine("Application is not running...");
                throw new Exception("Application is not running...");
            }

            var client          = new DiagnosticsClient(pid);
            var intervalSeconds = config.GetSection("SampleIntervalInSeconds").Value;

            var evtProvider =
                EventPipeProviderHelper.ToProvider(
                    $"System.Runtime:0xffffffff:5:EventCounterIntervalSec={intervalSeconds}");
            var hostingProvider =
                EventPipeProviderHelper.ToProvider(
                    $"Microsoft.AspNetCore.Hosting:0x0:4:EventCounterIntervalSec={intervalSeconds}");
            var session = client.StartEventPipeSession(new[] { evtProvider, hostingProvider }, false);
            var source  = new EventPipeEventSource(session.EventStream);

            source.Dynamic.All += Dynamic_All;
            source.Process();
            Console.ReadKey();
            session.Dispose();
            source.Dispose();
        }
예제 #2
0
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    _session?.Dispose();
                    _source?.Dispose();
                }
                disposedValue = true;
            }
        }
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    _eventPipeStream?.Dispose();
                    _source?.Dispose();
                }
                disposedValue = true;
            }
        }
        public async Task Process(int pid, TimeSpan duration, CancellationToken token)
        {
            await await Task.Factory.StartNew(async() =>
            {
                EventPipeEventSource source = null;
                DiagnosticsMonitor monitor  = null;
                try
                {
                    MonitoringSourceConfiguration config = null;
                    if (_mode == PipeMode.Logs)
                    {
                        config = new LoggingSourceConfiguration();
                    }
                    if (_mode == PipeMode.Metrics)
                    {
                        config = new MetricSourceConfiguration();
                    }

                    monitor = new DiagnosticsMonitor(config);
                    Stream sessionStream = await monitor.ProcessEvents(pid, duration, token);
                    source = new EventPipeEventSource(sessionStream);

                    if (_mode == PipeMode.Metrics)
                    {
                        // Metrics
                        HandleEventCounters(source);
                    }

                    if (_mode == PipeMode.Logs)
                    {
                        // Logging
                        HandleLoggingEvents(source);
                    }

                    source.Process();
                }
                catch (DiagnosticsClientException ex)
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }
                finally
                {
                    source?.Dispose();
                    if (monitor != null)
                    {
                        await monitor.DisposeAsync();
                    }
                }
            }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }
        public async Task TestTraceStopAsync()
        {
            Stream eventStream = null;

            await using (var testExecution = StartTraceeProcess("TraceStopTest"))
            {
                //TestRunner should account for start delay to make sure that the diagnostic pipe is available.

                var client   = new DiagnosticsClient(testExecution.TestRunner.Pid);
                var settings = new EventTracePipelineSettings()
                {
                    Duration      = Timeout.InfiniteTimeSpan,
                    Configuration = new CpuProfileConfiguration()
                };

                var foundProviderSource = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

                await using var pipeline = new EventTracePipeline(client, settings, async(s, token) =>
                {
                    eventStream = s;

                    using var eventSource = new EventPipeEventSource(s);

                    // Dispose event source when cancelled.
                    using var _ = token.Register(() => eventSource.Dispose());

                    eventSource.Dynamic.All += (TraceEvent obj) =>
                    {
                        if (string.Equals(obj.ProviderName, MonitoringSourceConfiguration.SampleProfilerProviderName, StringComparison.OrdinalIgnoreCase))
                        {
                            foundProviderSource.TrySetResult(null);
                        }
                    };

                    await Task.Run(() => Assert.True(eventSource.Process()), token);
                });

                await PipelineTestUtilities.ExecutePipelineWithDebugee(
                    _output,
                    pipeline,
                    testExecution,
                    foundProviderSource);
            }

            //Validate that the stream is only valid for the lifetime of the callback in the trace pipeline.
            Assert.Throws <ObjectDisposedException>(() => eventStream.Read(new byte[4], 0, 4));
        }
예제 #6
0
        public bool Stop()
        {
            if (!IsStarted)
            {
                return(false);
            }

            if (_source != null)
            {
                _source.Dispose(); _source = null;
            }
            if (_session != null)
            {
                _session.Dispose(); _session = null;
            }

            IsStarted = false;
            return(true);
        }
        private static async Task ValidateTrace(Stream traceStream)
        {
            using CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));

            using var eventSource = new EventPipeEventSource(traceStream);

            // Dispose event source when cancelled.
            using var _ = cancellationTokenSource.Token.Register(() => eventSource.Dispose());

            bool foundTraceObject = false;

            eventSource.Dynamic.All += (TraceEvent obj) =>
            {
                foundTraceObject = true;
            };

            await Task.Run(() => Assert.True(eventSource.Process()), cancellationTokenSource.Token);

            Assert.True(foundTraceObject);
        }
예제 #8
0
        public async ValueTask DisposeAsync()
        {
            lock (_lock)
            {
                if (_disposed)
                {
                    return;
                }
                _disposed = true;
            }

            _sessionStarted.TrySetCanceled();
            try
            {
                await _sessionStarted.Task;
            }
            catch
            {
            }

            _eventSource?.Dispose();
        }
예제 #9
0
        public async Task Process(int pid, TimeSpan duration, CancellationToken token)
        {
            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();
                    }
                    if (_mode == PipeMode.Metrics)
                    {
                        config = new MetricSourceConfiguration(_metricIntervalSeconds);
                    }
                    if (_mode == PipeMode.GCDump)
                    {
                        config = new GCDumpSourceConfiguration();
                    }

                    monitor = new DiagnosticsMonitor(config);
                    Stream sessionStream = await monitor.ProcessEvents(pid, duration, token);
                    source = new EventPipeEventSource(sessionStream);

                    // Allows the event handling routines to stop processing before the duration expires.
                    Func <Task> stopFunc = () => Task.Run(() => { monitor.StopProcessing(); });

                    if (_mode == PipeMode.Metrics)
                    {
                        // Metrics
                        HandleEventCounters(source);
                    }

                    if (_mode == PipeMode.Logs)
                    {
                        // Logging
                        HandleLoggingEvents(source);
                    }

                    if (_mode == PipeMode.GCDump)
                    {
                        // GC
                        handleEventsTask = HandleGCEvents(source, pid, stopFunc, token);
                    }

                    source.Process();

                    token.ThrowIfCancellationRequested();
                }
                catch (DiagnosticsClientException ex)
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }
                finally
                {
                    source?.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);
        }
예제 #10
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 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(() => TryCancelCompletionSources(token));
            await await Task.Factory.StartNew(async() =>
            {
                EventPipeEventSource source            = null;
                EventPipeStreamProvider streamProvider = null;
                Task handleEventsTask = Task.CompletedTask;
                try
                {
                    streamProvider = new EventPipeStreamProvider(_configuration);
                    // Allows the event handling routines to stop processing before the duration expires.
                    Func <Task> stopFunc = () => Task.Run(() => { streamProvider.StopProcessing(); });

                    Stream sessionStream = await streamProvider.ProcessEvents(client, duration, token);

                    if (!_sessionStarted.TrySetResult(true))
                    {
                        token.ThrowIfCancellationRequested();
                    }

                    source = new EventPipeEventSource(sessionStream);

                    handleEventsTask = _onEventSourceAvailable(source, stopFunc, token);

                    lock (_lock)
                    {
                        _eventSource = source;
                        _stopFunc    = stopFunc;
                    }
                    registration.Dispose();
                    if (!_initialized.TrySetResult(true))
                    {
                        token.ThrowIfCancellationRequested();
                    }

                    source.Process();
                    token.ThrowIfCancellationRequested();
                }
                catch (DiagnosticsClientException ex)
                {
                    InvalidOperationException wrappingException = new("Failed to start the event pipe session", ex);
                    TryFailCompletionSourcesReturnFalse(wrappingException);
                    throw wrappingException;
                }
                catch (Exception ex) when(TryFailCompletionSourcesReturnFalse(ex))
                {
                    throw;
                }
                finally
                {
                    registration.Dispose();
                    EventPipeEventSource eventSource = null;
                    lock (_lock)
                    {
                        eventSource  = _eventSource;
                        _eventSource = null;
                    }

                    eventSource?.Dispose();
                    if (streamProvider != null)
                    {
                        await streamProvider.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 void Dispose()
 {
     _cts.Cancel();
     _eventSource?.Dispose();
     _listeningSession?.Dispose();
 }
예제 #13
0
        /// <summary>
        /// Application to take a process dump if CPU utilization exceeds specified percentage
        /// </summary>
        /// <param name="processId">Process Id of the the tracee process</param>
        /// <param name="cpu">The CPU utilization percentage on which to trigger a dump. The default value is 10%</param>
        static async Task Main(int?processId, int cpu = 10)
        {
            if (processId ! == null)
            {
                throw new ArgumentNullException(nameof(processId));
            }
            if (!DiagnosticsClient.GetPublishedProcesses().Contains(processId.Value))
            {
                throw new ArgumentException($"{nameof(processId)} is not a valid .NET process");
            }

            var providerList = new List <EventPipeProvider>()
            {
                new EventPipeProvider(name: "System.Runtime",
                                      keywords: long.MaxValue,
                                      eventLevel: EventLevel.Informational,
                                      arguments: new Dictionary <string, string>()
                {
                    { "EventCounterIntervalSec", "1" }
                }),
                new EventPipeProvider(name: "Microsoft-Windows-DotNETRuntime",
                                      keywords: (long)ClrTraceEventParser.Keywords.GC,
                                      eventLevel: EventLevel.Verbose)
            };
            var diagnosticsClient = new DiagnosticsClient(processId.Value);
            var session           = diagnosticsClient.StartEventPipeSession(
                providers: providerList,
                requestRundown: false);

            var source = new EventPipeEventSource(session.EventStream);
            var tcs    = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                tcs.TrySetCanceled();
            };
            source.Dynamic.AddCallbackForProviderEvent("System.Runtime", "EventCounters", (traceEvent) =>
            {
                var counter = traceEvent.GetCounter();
                if (counter.GetName() == "cpu-usage")
                {
                    Console.WriteLine($"{counter.GetName()}\t{counter.GetValue()}");
                    if (Int32.Parse(counter.GetValue()) >= cpu)
                    {
                        source.StopProcessing();
                        tcs.SetResult(true);
                    }
                }
            });
            _ = Task.Run(() => source.Process());
            try
            {
                _ = await tcs.Task;
            }
            catch (Exception e) when(e is TaskCanceledException)
            {
                Console.WriteLine("Cancelled due to Ctrl+C");
            }
            finally
            {
                session.Dispose();
                source.Dispose();
            }

            if (tcs.Task.IsCompletedSuccessfully)
            {
                new Dumper().Collect(processId.Value, false, DumpTypeOption.Mini);
            }
        }