prometheus-net
98 строк · 4.1 Кб
1using System.Diagnostics;2
3namespace Prometheus;4
5/// <summary>
6/// Collects basic .NET metrics about the current process. This is not meant to be an especially serious collector,
7/// more of a producer of sample data so users of the library see something when they install it.
8/// </summary>
9public sealed class DotNetStats10{
11/// <summary>12/// Registers the .NET metrics in the specified registry.13/// </summary>14public static void Register(CollectorRegistry registry)15{16var instance = new DotNetStats(Metrics.WithCustomRegistry(registry));17registry.AddBeforeCollectCallback(instance.UpdateMetrics);18}19
20/// <summary>21/// Registers the .NET metrics in the default metrics factory and registry.22/// </summary>23internal static void RegisterDefault()24{25var instance = new DotNetStats(Metrics.DefaultFactory);26Metrics.DefaultRegistry.AddBeforeCollectCallback(instance.UpdateMetrics);27}28
29private readonly Process _process;30private readonly List<Counter.Child> _collectionCounts = new List<Counter.Child>();31private Gauge _totalMemory;32private Gauge _virtualMemorySize;33private Gauge _workingSet;34private Gauge _privateMemorySize;35private Counter _cpuTotal;36private Gauge _openHandles;37private Gauge _startTime;38private Gauge _numThreads;39
40private DotNetStats(IMetricFactory metricFactory)41{42_process = Process.GetCurrentProcess();43
44var collectionCountsParent = metricFactory.CreateCounter("dotnet_collection_count_total", "GC collection count", new[] { "generation" });45
46for (var gen = 0; gen <= GC.MaxGeneration; gen++)47{48_collectionCounts.Add(collectionCountsParent.Labels(gen.ToString()));49}50
51// Metrics that make sense to compare between all operating systems52// Note that old versions of pushgateway errored out if different metrics had same name but different help string.53// This is fixed in newer versions but keep the help text synchronized with the Go implementation just in case.54// See https://github.com/prometheus/pushgateway/issues/19455// and https://github.com/prometheus-net/prometheus-net/issues/8956_startTime = metricFactory.CreateGauge("process_start_time_seconds", "Start time of the process since unix epoch in seconds.");57_cpuTotal = metricFactory.CreateCounter("process_cpu_seconds_total", "Total user and system CPU time spent in seconds.");58
59_virtualMemorySize = metricFactory.CreateGauge("process_virtual_memory_bytes", "Virtual memory size in bytes.");60_workingSet = metricFactory.CreateGauge("process_working_set_bytes", "Process working set");61_privateMemorySize = metricFactory.CreateGauge("process_private_memory_bytes", "Process private memory size");62_openHandles = metricFactory.CreateGauge("process_open_handles", "Number of open handles");63_numThreads = metricFactory.CreateGauge("process_num_threads", "Total number of threads");64
65// .net specific metrics66_totalMemory = metricFactory.CreateGauge("dotnet_total_memory_bytes", "Total known allocated memory");67
68_startTime.SetToTimeUtc(_process.StartTime);69}70
71// The Process class is not thread-safe so let's synchronize the updates to avoid data tearing.72private readonly object _updateLock = new object();73
74private void UpdateMetrics()75{76try77{78lock (_updateLock)79{80_process.Refresh();81
82for (var gen = 0; gen <= GC.MaxGeneration; gen++)83_collectionCounts[gen].IncTo(GC.CollectionCount(gen));84
85_totalMemory.Set(GC.GetTotalMemory(false));86_virtualMemorySize.Set(_process.VirtualMemorySize64);87_workingSet.Set(_process.WorkingSet64);88_privateMemorySize.Set(_process.PrivateMemorySize64);89_cpuTotal.IncTo(_process.TotalProcessorTime.TotalSeconds);90_openHandles.Set(_process.HandleCount);91_numThreads.Set(_process.Threads.Count);92}93}94catch (Exception)95{96}97}98}