Skip to content

Commit

Permalink
Store delta gauge of Garbage Collection counts (#865)
Browse files Browse the repository at this point in the history
The `gc_count` metric will continuously report an growing
value, which resets on every restart or new deploy. Creating a lot of
highs and lows.

This makes it difficult to track if the app is doing more or less
garbage collection between deploys, other than tracking how steep the
increase is visually.

The delta of this metric reports the difference between probe runs,
which should result in a more stable graph that shows more heavy garbage
collection as a spike.
  • Loading branch information
tombruijn authored Jul 28, 2022
1 parent cacd649 commit 547f925
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .changesets/report-gauge-delta-value-for-gc_count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
bump: "patch"
type: "change"
---

Report gauge delta value for Garbage Collection counts. This reports a more user friendly metric that doesn't always goes up until the app restarts or gets a new deploy.
15 changes: 12 additions & 3 deletions lib/appsignal/probes/mri.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,18 @@ def call
@appsignal.set_gauge("allocated_objects", allocated_objects)
end

@appsignal.add_distribution_value("gc_count", GC.count, :metric => :gc_count)
@appsignal.add_distribution_value("gc_count", gc_stats[:minor_gc_count], :metric => :minor_gc_count)
@appsignal.add_distribution_value("gc_count", gc_stats[:major_gc_count], :metric => :major_gc_count)
gc_count = gauge_delta(:gc_count, GC.count)
if gc_count
@appsignal.add_distribution_value("gc_count", gc_count, :metric => :gc_count)
end
minor_gc_count = gauge_delta(:minor_gc_count, gc_stats[:minor_gc_count])
if minor_gc_count
@appsignal.add_distribution_value("gc_count", minor_gc_count, :metric => :minor_gc_count)
end
major_gc_count = gauge_delta(:major_gc_count, gc_stats[:major_gc_count])
if major_gc_count
@appsignal.add_distribution_value("gc_count", major_gc_count, :metric => :major_gc_count)
end

@appsignal.add_distribution_value("heap_slots", gc_stats[:heap_live_slots] || gc_stats[:heap_live_slot], :metric => :heap_live)
@appsignal.add_distribution_value("heap_slots", gc_stats[:heap_free_slots] || gc_stats[:heap_free_slot], :metric => :heap_free)
Expand Down
22 changes: 16 additions & 6 deletions spec/lib/appsignal/probes/mri_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@ def set_gauge(*args) # rubocop:disable Naming/AccessorMethodName
expect_gauge_value("gc_total_time")
end

it "tracks GC runs" do
it "tracks GC run count" do
expect(GC).to receive(:count).and_return(10, 15)
expect(GC).to receive(:stat).and_return(
{ :minor_gc_count => 10, :major_gc_count => 10 },
:minor_gc_count => 16, :major_gc_count => 17
)
probe.call
expect_distribution_value("gc_count", :gc_count)
expect_distribution_value("gc_count", :major_gc_count)
expect_distribution_value("gc_count", :minor_gc_count)
probe.call
expect_distribution_value("gc_count", :gc_count, 5)
expect_distribution_value("gc_count", :minor_gc_count, 6)
expect_distribution_value("gc_count", :major_gc_count, 7)
end

it "tracks object allocation" do
Expand All @@ -75,11 +81,15 @@ def set_gauge(*args) # rubocop:disable Naming/AccessorMethodName
end
end

def expect_distribution_value(expected_key, metric)
def expect_distribution_value(expected_key, metric, expected_value = nil)
expect(appsignal_mock.distribution_values).to satisfy do |distribution_values|
distribution_values.any? do |distribution_value|
key, value, metadata = distribution_value
key == expected_key && !value.nil? && metadata == { :metric => metric }
next unless key == expected_key
next unless expected_value ? expected_value == value : !value.nil?
next unless metadata == { :metric => metric }

true
end
end
end
Expand Down

0 comments on commit 547f925

Please sign in to comment.