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(); }
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)); }
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); }
public async ValueTask DisposeAsync() { lock (_lock) { if (_disposed) { return; } _disposed = true; } _sessionStarted.TrySetCanceled(); try { await _sessionStarted.Task; } catch { } _eventSource?.Dispose(); }
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); }
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(); }
/// <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); } }