public void ProcessEvent(EventWrittenEventArgs e) { if (e.EventId == EventIdAllocTick) { const uint lohHeapFlag = 0x1; var heapLabelValue = ((uint)e.Payload[1] & lohHeapFlag) == lohHeapFlag ? "loh" : "soh"; AllocatedBytes.TrackValue(e.Payload[0], heapLabelValue); return; } if (e.EventId == EventIdHeapStats) { GcHeapSizeBytes.TrackValue(e.Payload[0], "0"); GcHeapSizeBytes.TrackValue(e.Payload[2], "1"); GcHeapSizeBytes.TrackValue(e.Payload[4], "2"); GcHeapSizeBytes.TrackValue(e.Payload[6], "loh"); GcFinalizationQueueLength.TrackValue((ulong)e.Payload[9]); GcNumPinnedObjects.TrackValue((uint)e.Payload[10]); return; } // flags representing the "Garbage Collection" + "Preparation for garbage collection" pause reasons const uint suspendGcReasons = 0x1 | 0x6; if (e.EventId == EventIdSuspendEEStart && ((uint)e.Payload[0] & suspendGcReasons) == 0) { // Execution engine is pausing for a reason other than GC, discard event. return; } if (_gcPauseEventTimer.TryGetEventPairDuration(e, out var pauseDuration)) { GcPauseSeconds.TrackValue(pauseDuration.TotalSeconds); return; } if (e.EventId == EventIdGcStart) { var dimension = _gcReasonToLabels[(DotNetRuntimeEventSource.GCReason)e.Payload[2]]; GcCollectionReasons.TrackValue(1, dimension); } if (_gcEventTimer.TryGetEventPairDuration(e, out var gcDuration, out var gcData)) { GcCollectionSeconds.TrackValue(gcDuration.TotalSeconds, gcData.GetGenerationToString(), gcData.GetTypeToString()); } }
public void RegisterMetrics(MetricFactory metrics) { #if !NETSTANDARD2_1 AvailableMemory = metrics.CreateGauge("dotnet_gc_memory_total_available_bytes", "The upper limit on the amount of physical memory .NET can allocate to"); #endif // No registered sources available- cannot produce metrics if (!_gcInfo.Enabled && !_gcVerbose.Enabled && !_runtimeCounters.Enabled) { return; } if (_runtimeCounters.Enabled && !_gcInfo.Enabled) { GcPauseRatio = metrics.CreateGauge("dotnet_gc_pause_ratio", "The percentage of time the process spent paused for garbage collection"); _runtimeCounters.Events.TimeInGc += e => GcPauseRatio.Set(e.Mean / 100.0); GcHeapSizeBytes = metrics.CreateGauge( "dotnet_gc_heap_size_bytes", "The current size of all heaps (only updated after a garbage collection)", LabelGeneration); _runtimeCounters.Events.Gen0Size += e => GcHeapSizeBytes.Labels("0").Set(e.Mean); _runtimeCounters.Events.Gen1Size += e => GcHeapSizeBytes.Labels("1").Set(e.Mean); _runtimeCounters.Events.Gen2Size += e => GcHeapSizeBytes.Labels("2").Set(e.Mean); _runtimeCounters.Events.LohSize += e => GcHeapSizeBytes.Labels("loh").Set(e.Mean); GcCollections = metrics.CreateCounter( "dotnet_gc_collection_count_total", "Counts the number of garbage collections that have occurred, broken down by generation number.", LabelGeneration); _runtimeCounters.Events.Gen0GcCount += e => GcCollections.Labels("0").Inc(e.IncrementedBy); _runtimeCounters.Events.Gen1GcCount += e => GcCollections.Labels("1").Inc(e.IncrementedBy); _runtimeCounters.Events.Gen2GcCount += e => GcCollections.Labels("2").Inc(e.IncrementedBy); } if (_gcInfo.Enabled) { GcCollectionSeconds = metrics.CreateHistogram( "dotnet_gc_collection_seconds", "The amount of time spent running garbage collections", new HistogramConfiguration() { Buckets = _options.HistogramBuckets, LabelNames = new[] { LabelGeneration, LabelType } } ); _gcInfo.Events.CollectionComplete += (e) => GcCollectionSeconds.Labels(GetGenerationToString(e.Generation), GcTypeToLabels[e.Type]).Observe(e.Duration.TotalSeconds); GcPauseSeconds = metrics.CreateHistogram( "dotnet_gc_pause_seconds", "The amount of time execution was paused for garbage collection", new HistogramConfiguration() { Buckets = _options.HistogramBuckets } ); _gcInfo.Events.PauseComplete += (e) => GcPauseSeconds.Observe(e.PauseDuration.TotalSeconds); GcCollections = metrics.CreateCounter( "dotnet_gc_collection_count_total", "Counts the number of garbage collections that have occurred, broken down by generation number and the reason for the collection.", LabelGeneration, LabelReason); _gcInfo.Events.CollectionStart += (e) => GcCollections.Labels(GetGenerationToString(e.Generation), GcReasonToLabels[e.Reason]).Inc(); GcCpuRatio = metrics.CreateGauge("dotnet_gc_cpu_ratio", "The percentage of process CPU time spent running garbage collections"); GcPauseRatio = metrics.CreateGauge("dotnet_gc_pause_ratio", "The percentage of time the process spent paused for garbage collection"); GcHeapSizeBytes = metrics.CreateGauge( "dotnet_gc_heap_size_bytes", "The current size of all heaps (only updated after a garbage collection)", LabelGeneration); GcNumPinnedObjects = metrics.CreateGauge("dotnet_gc_pinned_objects", "The number of pinned objects"); GcFinalizationQueueLength = metrics.CreateGauge("dotnet_gc_finalization_queue_length", "The number of objects waiting to be finalized"); _gcInfo.Events.HeapStats += e => { GcHeapSizeBytes.Labels("0").Set(e.Gen0SizeBytes); GcHeapSizeBytes.Labels("1").Set(e.Gen1SizeBytes); GcHeapSizeBytes.Labels("2").Set(e.Gen2SizeBytes); GcHeapSizeBytes.Labels("loh").Set(e.LohSizeBytes); GcFinalizationQueueLength.Set(e.FinalizationQueueLength); GcNumPinnedObjects.Set(e.NumPinnedObjects); }; } if (_gcVerbose.Enabled || _runtimeCounters.Enabled) { AllocatedBytes = metrics.CreateCounter( "dotnet_gc_allocated_bytes_total", "The total number of bytes allocated on the managed heap", labelNames: _gcVerbose.Enabled ? new [] { LabelHeap } : new string[0]); if (_gcVerbose.Enabled) { _gcVerbose.Events.AllocationTick += e => AllocatedBytes.Labels(e.IsLargeObjectHeap ? "loh" : "soh").Inc(e.AllocatedBytes); } else { _runtimeCounters.Events.AllocRate += r => AllocatedBytes.Inc(r.IncrementedBy); } } }