public void Dispose() { try { _session?.Stop(); } catch (ServerNotAvailableException) { } _session?.Dispose(); }
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 async Task StartTracing(Action <string> log) { var providers = new List <EventPipeProvider>() { // Runtime Metrics new EventPipeProvider( "System.Runtime", EventLevel.Informational, 0, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } } ), // new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", EventLevel.Informational), new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational, 65536 | 32768),//ClrTraceEventParser.Keywords.Default) // Activity correlation new EventPipeProvider("System.Threading.Tasks.TplEventSource", keywords: 511, eventLevel: EventLevel.LogAlways), }; log($"Starting event pipe session for pid {Process.GetCurrentProcess().Id}"); EventPipeSession session = null; var client = new DiagnosticsClient(Process.GetCurrentProcess().Id); try { session = client.StartEventPipeSession(providers); } catch (EndOfStreamException) { } // If the process has already exited, a ServerNotAvailableException will be thrown. catch (ServerNotAvailableException) { } catch (Exception) { // We can't even start the session, wait until the process boots up again to start another metrics thread } void StopSession() { try { session.Stop(); } catch (EndOfStreamException) { // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully. } // We may time out if the process ended before we sent StopTracing command. We can just exit in that case. catch (TimeoutException) { } // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited // before dotnet-counters and got rid of a pipe that once existed. // Since we are catching this in StopMonitor() we know that the pipe once existed (otherwise the exception would've // been thrown in StartMonitor directly) catch (PlatformNotSupportedException) { } // If the process has already exited, a ServerNotAvailableException will be thrown. // This can always race with tye shutting down and a process being restarted on exiting. catch (ServerNotAvailableException) { } } var _ = _cts.Token.Register(() => StopSession()); try { using var traceOutput = File.Create("trace.nettrace"); await session.EventStream.CopyToAsync(traceOutput); } catch (DiagnosticsClientException) { } catch (Exception) { // This fails if stop is called or if the process dies } finally { session?.Dispose(); } }
public void Dispose() { _cts.Cancel(); _eventSource?.Dispose(); _listeningSession?.Dispose(); }
public void ProcessEvents( string applicationName, string serviceName, int processId, string replicaName, IDictionary <string, string> metrics, CancellationToken cancellationToken) { var hasEventPipe = false; for (var i = 0; i < 10; ++i) { if (DiagnosticsClient.GetPublishedProcesses().Contains(processId)) { hasEventPipe = true; break; } if (cancellationToken.IsCancellationRequested) { return; } Thread.Sleep(500); } if (!hasEventPipe) { _logger.LogInformation("Process id {PID}, does not support event pipe", processId); return; } _logger.LogInformation("Listening for event pipe events for {ServiceName} on process id {PID}", replicaName, processId); // Create the logger factory for this replica using var loggerFactory = LoggerFactory.Create(builder => ConfigureLogging(serviceName, replicaName, builder)); var processor = new SimpleSpanProcessor(CreateSpanExporter(serviceName, replicaName)); var providers = new List <EventPipeProvider>() { // Runtime Metrics new EventPipeProvider( SystemRuntimeEventSourceName, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } } ), new EventPipeProvider( MicrosoftAspNetCoreHostingEventSourceName, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } } ), new EventPipeProvider( GrpcAspNetCoreServer, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } } ), // Application Metrics new EventPipeProvider( applicationName, EventLevel.Informational, (long)ClrTraceEventParser.Keywords.None, new Dictionary <string, string>() { { "EventCounterIntervalSec", "1" } } ), // Logging new EventPipeProvider( MicrosoftExtensionsLoggingProviderName, EventLevel.LogAlways, (long)(LoggingEventSource.Keywords.JsonMessage | LoggingEventSource.Keywords.FormattedMessage) ), // Distributed Tracing // Activity correlation new EventPipeProvider(TplEventSource, keywords: 0x80, eventLevel: EventLevel.LogAlways), // Diagnostic source events new EventPipeProvider(DiagnosticSourceEventSource, keywords: 0x1 | 0x2, eventLevel: EventLevel.Verbose, arguments: new Dictionary <string, string> { { "FilterAndPayloadSpecs", DiagnosticFilterString } }) }; while (!cancellationToken.IsCancellationRequested) { EventPipeSession session = null; var client = new DiagnosticsClient(processId); try { session = client.StartEventPipeSession(providers); } catch (EndOfStreamException) { break; } // If the process has already exited, a ServerNotAvailableException will be thrown. catch (ServerNotAvailableException) { break; } catch (Exception ex) { if (!cancellationToken.IsCancellationRequested) { _logger.LogDebug(0, ex, "Failed to start the event pipe session"); } // We can't even start the session, wait until the process boots up again to start another metrics thread break; } void StopSession() { try { session.Stop(); } catch (EndOfStreamException) { // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully. } // We may time out if the process ended before we sent StopTracing command. We can just exit in that case. catch (TimeoutException) { } // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited // before dotnet-counters and got rid of a pipe that once existed. // Since we are catching this in StopMonitor() we know that the pipe once existed (otherwise the exception would've // been thrown in StartMonitor directly) catch (PlatformNotSupportedException) { } // If the process has already exited, a ServerNotAvailableException will be thrown. // This can always race with tye shutting down and a process being restarted on exiting. catch (ServerNotAvailableException) { } } using var _ = cancellationToken.Register(() => StopSession()); try { var source = new EventPipeEventSource(session.EventStream); // Distribued Tracing HandleDistributedTracingEvents(source, processor); // Metrics HandleEventCounters(source, metrics); // Logging HandleLoggingEvents(source, loggerFactory, replicaName); source.Process(); } catch (DiagnosticsClientException ex) { _logger.LogDebug(0, ex, "Failed to start the event pipe session"); } catch (Exception) { // This fails if stop is called or if the process dies } finally { session?.Dispose(); } } _logger.LogInformation("Event pipe collection completed for {ServiceName} on process id {PID}", replicaName, processId); }
public void Dispose() { _session?.Stop(); _session?.Dispose(); }
public async Task ProcessEvents(int processId, CancellationToken cancellationToken) { var hasEventPipe = false; for (int i = 0; i < 10; ++i) { if (DiagnosticsClient.GetPublishedProcesses().Contains(processId)) { hasEventPipe = true; break; } cancellationToken.ThrowIfCancellationRequested(); await Task.Delay(500); } if (!hasEventPipe) { _logger.LogInformation("Process id {PID}, does not support event pipe", processId); return; } _logger.LogInformation("Listening for event pipe events for {ServiceName} on process id {PID}", _dimValues[1], processId); while (!cancellationToken.IsCancellationRequested) { EventPipeSession session = null; var client = new DiagnosticsClient(processId); try { session = client.StartEventPipeSession(_sourceConfig.GetProviders()); } catch (EndOfStreamException) { break; } catch (Exception ex) { if (!cancellationToken.IsCancellationRequested) { _logger.LogDebug(0, ex, "Failed to start the event pipe session"); } // We can't even start the session, wait until the process boots up again to start another metrics thread break; } void StopSession() { try { session.Stop(); } catch (EndOfStreamException) { // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully. } // We may time out if the process ended before we sent StopTracing command. We can just exit in that case. catch (TimeoutException) { } // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited // before dotnet-counters and got rid of a pipe that once existed. // Since we are catching this in StopMonitor() we know that the pipe once existed (otherwise the exception would've // been thrown in StartMonitor directly) catch (PlatformNotSupportedException) { } } using var _ = cancellationToken.Register(() => StopSession()); try { var source = new EventPipeEventSource(session.EventStream); // Metrics HandleEventCounters(source); // Logging HandleLoggingEvents(source); source.Process(); } catch (DiagnosticsClientException ex) { _logger.LogDebug(0, ex, "Failed to start the event pipe session"); } catch (Exception) { // This fails if stop is called or if the process dies } finally { session?.Dispose(); } } _logger.LogInformation("Event pipe collection completed for {ServiceName} on process id {PID}", _dimValues[1], processId); }