From 382e23f232be8652b4b9ac7a303facb39eac5de8 Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Thu, 14 Aug 2025 02:37:52 +0200 Subject: [PATCH] Add marking and sweeping time as Process stat (#300) * Add marking and sweeping time as Process stat Introduced in https://bugs.ruby-lang.org/issues/19437 * Do provide marking_time and sweeping_time on Ruby version bellow 3.3 --- README.md | 2 ++ .../instrumentation/process.rb | 6 ++++++ .../server/process_collector.rb | 2 ++ test/server/process_collector_test.rb | 20 +++++++++++-------- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7cbc5a0..26549ec 100644 --- a/README.md +++ b/README.md @@ -373,6 +373,8 @@ end | Counter | `major_gc_ops_total` | Major GC operations by process | | Counter | `minor_gc_ops_total` | Minor GC operations by process | | Counter | `allocated_objects_total` | Total number of allocated objects by process | +| Gauge | `marking_time` | Marking time spent (Ruby 3.3 minimum) | +| Gauge | `sweeping_time` | Sweeping time spent (Ruby 3.3 minimum) | _Metrics marked with * are only collected when `MiniRacer` is defined._ diff --git a/lib/prometheus_exporter/instrumentation/process.rb b/lib/prometheus_exporter/instrumentation/process.rb index 3129dde..fdf37c3 100644 --- a/lib/prometheus_exporter/instrumentation/process.rb +++ b/lib/prometheus_exporter/instrumentation/process.rb @@ -62,6 +62,8 @@ module PrometheusExporter::Instrumentation metric[:rss] = rss end + SWEEPING_AND_MARKING = RUBY_VERSION >= "3.3.0" + def collect_gc_stats(metric) stat = GC.stat metric[:heap_live_slots] = stat[:heap_live_slots] @@ -71,6 +73,10 @@ module PrometheusExporter::Instrumentation metric[:allocated_objects_total] = stat[:total_allocated_objects] metric[:malloc_increase_bytes_limit] = stat[:malloc_increase_bytes_limit] metric[:oldmalloc_increase_bytes_limit] = stat[:oldmalloc_increase_bytes_limit] + if SWEEPING_AND_MARKING + metric[:marking_time] = stat[:marking_time] + metric[:sweeping_time] = stat[:sweeping_time] + end end def collect_v8_stats(metric) diff --git a/lib/prometheus_exporter/server/process_collector.rb b/lib/prometheus_exporter/server/process_collector.rb index bf1ae87..9d005b1 100644 --- a/lib/prometheus_exporter/server/process_collector.rb +++ b/lib/prometheus_exporter/server/process_collector.rb @@ -16,6 +16,8 @@ module PrometheusExporter::Server "Limit before Ruby triggers a GC against current objects (bytes).", oldmalloc_increase_bytes_limit: "Limit before Ruby triggers a major GC against old objects (bytes).", + marking_time: "Time spent in GC marking.", + sweeping_time: "Time spent in GC sweeping.", } PROCESS_COUNTERS = { diff --git a/test/server/process_collector_test.rb b/test/server/process_collector_test.rb index db4732a..e21eb0a 100644 --- a/test/server/process_collector_test.rb +++ b/test/server/process_collector_test.rb @@ -27,13 +27,15 @@ class ProcessCollectorTest < Minitest::Test "major_gc_ops_total" => 4000, "minor_gc_ops_total" => 4001, "allocated_objects_total" => 4002, + "marking_time" => 4003, + "sweeping_time" => 4004, } end def test_metrics_collection collector.collect(base_data) - assert_equal 10, collector.metrics.size + assert_equal 12, collector.metrics.size assert_equal [ 'heap_free_slots{pid="1000",hostname="localhost"} 1000', 'heap_live_slots{pid="1000",hostname="localhost"} 1001', @@ -42,6 +44,8 @@ class ProcessCollectorTest < Minitest::Test 'v8_physical_size{pid="1000",hostname="localhost"} 2003', 'v8_heap_count{pid="1000",hostname="localhost"} 2004', 'rss{pid="1000",hostname="localhost"} 3000', + 'marking_time{pid="1000",hostname="localhost"} 4003', + 'sweeping_time{pid="1000",hostname="localhost"} 4004', 'major_gc_ops_total{pid="1000",hostname="localhost"} 4000', 'minor_gc_ops_total{pid="1000",hostname="localhost"} 4001', 'allocated_objects_total{pid="1000",hostname="localhost"} 4002', @@ -51,22 +55,22 @@ class ProcessCollectorTest < Minitest::Test def test_metrics_deduplication collector.collect(base_data) - assert_equal 10, collector.metrics.size - assert_equal 10, collector_metric_lines.size + assert_equal 12, collector.metrics.size + assert_equal 12, collector_metric_lines.size collector.collect(base_data) - assert_equal 10, collector.metrics.size - assert_equal 10, collector_metric_lines.size + assert_equal 12, collector.metrics.size + assert_equal 12, collector_metric_lines.size collector.collect(base_data.merge({ "hostname" => "localhost2" })) - assert_equal 10, collector.metrics.size - assert_equal 20, collector_metric_lines.size + assert_equal 12, collector.metrics.size + assert_equal 24, collector_metric_lines.size end def test_metrics_expiration stub_monotonic_clock(0) do collector.collect(base_data) - assert_equal 10, collector.metrics.size + assert_equal 12, collector.metrics.size end stub_monotonic_clock(max_metric_age + 1) { assert_equal 0, collector.metrics.size }