Esempio n. 1
0
        private async Task HandleProcessInfo(EventPipeEventSource source, Func <Task> stopFunc, CancellationToken token)
        {
            string commandLine = null;
            Action <TraceEvent, Action> processInfoHandler = (TraceEvent traceEvent, Action taskComplete) =>
            {
                commandLine = (string)traceEvent.PayloadByName("CommandLine");
                taskComplete();
            };

            // Completed when the ProcessInfo event of the Microsoft-DotNETCore-EventPipe event provider is handled
            using var processInfoTaskSource = new EventTaskSource <Action <TraceEvent> >(
                      taskComplete => traceEvent => processInfoHandler(traceEvent, taskComplete),
                      handler => source.Dynamic.AddCallbackForProviderEvent(MonitoringSourceConfiguration.EventPipeProviderName, "ProcessInfo", handler),
                      handler => source.Dynamic.RemoveCallback(handler),
                      token);

            // Completed when any trace event is handled
            using var anyEventTaskSource = new EventTaskSource <Action <TraceEvent> >(
                      taskComplete => traceEvent => taskComplete(),
                      handler => source.Dynamic.All += handler,
                      handler => source.Dynamic.All -= handler,
                      token);

            // Wait for any trace event to be processed
            await anyEventTaskSource.Task;

            // Stop the event pipe session
            await stopFunc();

            // Wait for the ProcessInfo event to be processed
            await processInfoTaskSource.Task;

            // Notify of command line information
            await _processInfoCallback(commandLine, token);
        }
Esempio n. 2
0
        protected override async Task OnEventSourceAvailable(EventPipeEventSource eventSource, Func <Task> stopSessionAsync, CancellationToken token)
        {
            ExecuteCounterLoggerAction((metricLogger) => metricLogger.PipelineStarted());

            eventSource.Dynamic.All += traceEvent =>
            {
                try
                {
                    if (traceEvent.TryGetCounterPayload(_filter, out ICounterPayload counterPayload))
                    {
                        ExecuteCounterLoggerAction((metricLogger) => metricLogger.Log(counterPayload));
                    }
                }
                catch (Exception)
                {
                }
            };

            using var sourceCompletedTaskSource = new EventTaskSource <Action>(
                      taskComplete => taskComplete,
                      handler => eventSource.Completed += handler,
                      handler => eventSource.Completed -= handler,
                      token);

            await sourceCompletedTaskSource.Task;

            ExecuteCounterLoggerAction((metricLogger) => metricLogger.PipelineStopped());
        }
Esempio n. 3
0
        private async Task HandleGCEvents(EventPipeEventSource source, Func <Task> stopFunc, CancellationToken token)
        {
            int gcNum = -1;

            Action <GCStartTraceData, Action> gcStartHandler = (GCStartTraceData data, Action taskComplete) =>
            {
                taskComplete();

                if (gcNum < 0 && data.Depth == 2 && data.Type != GCType.BackgroundGC)
                {
                    gcNum = data.Count;
                }
            };

            Action <GCBulkNodeTraceData, Action> gcBulkNodeHandler = (GCBulkNodeTraceData data, Action taskComplete) =>
            {
                taskComplete();
            };

            Action <GCEndTraceData, Action> gcEndHandler = (GCEndTraceData data, Action taskComplete) =>
            {
                if (data.Count == gcNum)
                {
                    taskComplete();
                }
            };

            // Register event handlers on the event source and represent their completion as tasks
            using var gcStartTaskSource = new EventTaskSource <Action <GCStartTraceData> >(
                      taskComplete => data => gcStartHandler(data, taskComplete),
                      handler => source.Clr.GCStart += handler,
                      handler => source.Clr.GCStart -= handler,
                      token);
            using var gcBulkNodeTaskSource = new EventTaskSource <Action <GCBulkNodeTraceData> >(
                      taskComplete => data => gcBulkNodeHandler(data, taskComplete),
                      handler => source.Clr.GCBulkNode += handler,
                      handler => source.Clr.GCBulkNode -= handler,
                      token);
            using var gcStopTaskSource = new EventTaskSource <Action <GCEndTraceData> >(
                      taskComplete => data => gcEndHandler(data, taskComplete),
                      handler => source.Clr.GCStop += handler,
                      handler => source.Clr.GCStop -= handler,
                      token);
            using var sourceCompletedTaskSource = new EventTaskSource <Action>(
                      taskComplete => taskComplete,
                      handler => source.Completed += handler,
                      handler => source.Completed -= handler,
                      token);

            // A task that is completed whenever GC data is received
            Task gcDataTask = Task.WhenAny(gcStartTaskSource.Task, gcBulkNodeTaskSource.Task);
            Task gcStopTask = gcStopTaskSource.Task;

            DotNetHeapDumpGraphReader dumper = new DotNetHeapDumpGraphReader(TextWriter.Null)
            {
                DotNetHeapInfo = new DotNetHeapInfo()
            };

            dumper.SetupCallbacks(_gcGraph, source);

            // The event source will not always provide the GC events when it starts listening. However,
            // they will be provided when the event source is told to stop processing events. Give the
            // event source some time to produce the events, but if it doesn't start producing them within
            // a short amount of time (5 seconds), then stop processing events to allow them to be flushed.
            Task eventsTimeoutTask = Task.Delay(TimeSpan.FromSeconds(5), token);
            Task completedTask     = await Task.WhenAny(gcDataTask, eventsTimeoutTask);

            token.ThrowIfCancellationRequested();

            // If started receiving GC events, wait for the GC Stop event.
            if (completedTask == gcDataTask)
            {
                await gcStopTask;
            }

            // Stop receiving events; if haven't received events yet, this will force flushing of events.
            await stopFunc();

            // Wait for all received events to be processed.
            await sourceCompletedTaskSource.Task;

            // Check that GC data and stop events were received. This is done by checking that the
            // associated tasks have ran to completion. If one of them has not reached the completion state, then
            // fail the GC dump operation.
            if (gcDataTask.Status != TaskStatus.RanToCompletion ||
                gcStopTask.Status != TaskStatus.RanToCompletion)
            {
                throw new InvalidOperationException("Unable to create GC dump due to incomplete GC data.");
            }

            dumper.ConvertHeapDataToGraph();

            _gcGraph.AllowReading();
        }
        protected override async Task OnEventSourceAvailable(EventPipeEventSource eventSource, Func <Task> stopSessionAsync, CancellationToken token)
        {
            ExecuteCounterLoggerAction((metricLogger) => metricLogger.PipelineStarted());

            eventSource.Dynamic.All += traceEvent =>
            {
                try
                {
                    // Metrics
                    if (traceEvent.EventName.Equals("EventCounters"))
                    {
                        IDictionary <string, object> payloadVal    = (IDictionary <string, object>)(traceEvent.PayloadValue(0));
                        IDictionary <string, object> payloadFields = (IDictionary <string, object>)(payloadVal["Payload"]);

                        //Make sure we are part of the requested series. If multiple clients request metrics, all of them get the metrics.
                        string series = payloadFields["Series"].ToString();
                        if (GetInterval(series) != CounterIntervalSeconds * 1000)
                        {
                            return;
                        }

                        string counterName = payloadFields["Name"].ToString();
                        if (!_filter.IsIncluded(traceEvent.ProviderName, counterName))
                        {
                            return;
                        }

                        float       intervalSec  = (float)payloadFields["IntervalSec"];
                        string      displayName  = payloadFields["DisplayName"].ToString();
                        string      displayUnits = payloadFields["DisplayUnits"].ToString();
                        double      value        = 0;
                        CounterType counterType  = CounterType.Metric;

                        if (payloadFields["CounterType"].Equals("Mean"))
                        {
                            value = (double)payloadFields["Mean"];
                        }
                        else if (payloadFields["CounterType"].Equals("Sum"))
                        {
                            counterType = CounterType.Rate;
                            value       = (double)payloadFields["Increment"];
                            if (string.IsNullOrEmpty(displayUnits))
                            {
                                displayUnits = "count";
                            }
                            //TODO Should we make these /sec like the dotnet-counters tool?
                        }

                        // Note that dimensional data such as pod and namespace are automatically added in prometheus and azure monitor scenarios.
                        // We no longer added it here.
                        var counterPayload = new CounterPayload(traceEvent.TimeStamp,
                                                                traceEvent.ProviderName,
                                                                counterName, displayName,
                                                                displayUnits,
                                                                value,
                                                                counterType,
                                                                intervalSec);

                        ExecuteCounterLoggerAction((metricLogger) => metricLogger.Log(counterPayload));
                    }
                }
                catch (Exception)
                {
                }
            };

            using var sourceCompletedTaskSource = new EventTaskSource <Action>(
                      taskComplete => taskComplete,
                      handler => eventSource.Completed += handler,
                      handler => eventSource.Completed -= handler,
                      token);

            await sourceCompletedTaskSource.Task;

            ExecuteCounterLoggerAction((metricLogger) => metricLogger.PipelineStopped());
        }