appsignal 3.1.3 → 3.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/appsignal/config.rb +0 -3
- data/lib/appsignal/garbage_collection.rb +90 -0
- data/lib/appsignal/probes/mri.rb +5 -3
- data/lib/appsignal/transaction.rb +5 -12
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -6
- data/spec/lib/appsignal/config_spec.rb +0 -1
- data/spec/lib/appsignal/{garbage_collection_profiler_spec.rb → garbage_collection_spec.rb} +28 -6
- data/spec/lib/appsignal/probes/mri_spec.rb +35 -0
- data/spec/lib/appsignal/transaction_spec.rb +2 -27
- data/spec/lib/appsignal_spec.rb +2 -22
- metadata +5 -5
- data/lib/appsignal/garbage_collection_profiler.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c21e4e80dd54b8a0f6619a40b7c046e6bc132634ce26666b281fdd4298c72c3f
|
4
|
+
data.tar.gz: 53743646f5cf821ab45559817cf65c2bf9ed483184725fca2413b3606fad6e1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36a34d74cf16e5f274e3485471833f516e34227546017d14f24d70fc75ca824b68261a7048924391135a3c0d815d7ef605b60ac19396bdeb9b9b46f1d4911daa
|
7
|
+
data.tar.gz: b03a309a6c8649397e6f5d9b62a65324e4b4e39a3a1eee77b6cb60280758838212e2de7ca3eb28c8f10b3b59cb5b02ca7d88347cc9f3995be0308bf5249cae70
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
2
2
|
|
3
|
+
## 3.1.4
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- [ffe49cfe](https://github.com/appsignal/appsignal-ruby/commit/ffe49cfe94f5269e59d6f168a73114f7a3914f79) patch - Support temporarily disabling GC profiling without reporting inaccurate `gc_time` metric durations. The MRI probe's `gc_time` will not report any value when the `GC::Profiler.enabled?` returns `false`.
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- [af7e666c](https://github.com/appsignal/appsignal-ruby/commit/af7e666cf173ec1f42e9cf3fce2ab6c8e658440c) patch - Listen if the Ruby Garbage Collection profiler is enabled and collect how long the GC is running for the Ruby VM magic dashboard. An app will need to call `GC::Profiler.enable` to enable the GC profiler. Do not enable this in production environments, or at least not for long, because this can negatively impact performance of apps.
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
- [b3a163be](https://github.com/appsignal/appsignal-ruby/commit/b3a163be154796e1f358c5061eaee99845c960ee) patch - Fix the MRI probe using the Garbage Collection profiler instead of the NilProfiler when garbage collection instrumentation is not enabled for MRI probe. This caused unnecessary overhead.
|
16
|
+
|
3
17
|
## 3.1.3
|
4
18
|
|
5
19
|
### Added
|
data/lib/appsignal/config.rb
CHANGED
@@ -15,7 +15,6 @@ module Appsignal
|
|
15
15
|
:debug => false,
|
16
16
|
:dns_servers => [],
|
17
17
|
:enable_allocation_tracking => true,
|
18
|
-
:enable_gc_instrumentation => false,
|
19
18
|
:enable_host_metrics => true,
|
20
19
|
:enable_minutely_probes => true,
|
21
20
|
:enable_statsd => true,
|
@@ -63,7 +62,6 @@ module Appsignal
|
|
63
62
|
"APPSIGNAL_DEBUG" => :debug,
|
64
63
|
"APPSIGNAL_DNS_SERVERS" => :dns_servers,
|
65
64
|
"APPSIGNAL_ENABLE_ALLOCATION_TRACKING" => :enable_allocation_tracking,
|
66
|
-
"APPSIGNAL_ENABLE_GC_INSTRUMENTATION" => :enable_gc_instrumentation,
|
67
65
|
"APPSIGNAL_ENABLE_HOST_METRICS" => :enable_host_metrics,
|
68
66
|
"APPSIGNAL_ENABLE_MINUTELY_PROBES" => :enable_minutely_probes,
|
69
67
|
"APPSIGNAL_ENABLE_STATSD" => :enable_statsd,
|
@@ -114,7 +112,6 @@ module Appsignal
|
|
114
112
|
APPSIGNAL_ACTIVE
|
115
113
|
APPSIGNAL_DEBUG
|
116
114
|
APPSIGNAL_ENABLE_ALLOCATION_TRACKING
|
117
|
-
APPSIGNAL_ENABLE_GC_INSTRUMENTATION
|
118
115
|
APPSIGNAL_ENABLE_HOST_METRICS
|
119
116
|
APPSIGNAL_ENABLE_MINUTELY_PROBES
|
120
117
|
APPSIGNAL_ENABLE_STATSD
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
# @api private
|
5
|
+
module GarbageCollection
|
6
|
+
# Return the GC profiler wrapper.
|
7
|
+
#
|
8
|
+
# Returns {Profiler} if the Ruby Garbage Collection profiler is enabled.
|
9
|
+
# This is checked by calling `GC::Profiler.enabled?`.
|
10
|
+
#
|
11
|
+
# GC profiling is disabled by default due to the overhead it causes. Do not
|
12
|
+
# enable this in production for long periods of time.
|
13
|
+
def self.profiler
|
14
|
+
# Cached instances so it doesn't create a new object every time this
|
15
|
+
# method is called. Especially necessary for the {Profiler} because a new
|
16
|
+
# instance will have a new internal time counter.
|
17
|
+
@real_profiler ||= Profiler.new
|
18
|
+
@nil_profiler ||= NilProfiler.new
|
19
|
+
|
20
|
+
enabled? ? @real_profiler : @nil_profiler
|
21
|
+
end
|
22
|
+
|
23
|
+
# Check if Garbage Collection is enabled at the moment.
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
26
|
+
def self.enabled?
|
27
|
+
GC::Profiler.enabled?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Unset the currently cached profilers.
|
31
|
+
#
|
32
|
+
# @return [void]
|
33
|
+
def self.clear_profiler!
|
34
|
+
@real_profiler = nil
|
35
|
+
@nil_profiler = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# A wrapper around Ruby's `GC::Profiler` that tracks garbage collection
|
39
|
+
# time, while clearing `GC::Profiler`'s total_time to make sure it doesn't
|
40
|
+
# leak memory by keeping garbage collection run samples in memory.
|
41
|
+
class Profiler
|
42
|
+
def self.lock
|
43
|
+
@lock ||= Mutex.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@total_time = 0
|
48
|
+
end
|
49
|
+
|
50
|
+
# Whenever {#total_time} is called, the current `GC::Profiler#total_time`
|
51
|
+
# gets added to `@total_time`, after which `GC::Profiler.clear` is called
|
52
|
+
# to prevent it from leaking memory. A class-level lock is used to make
|
53
|
+
# sure garbage collection time is never counted more than once.
|
54
|
+
#
|
55
|
+
# Whenever `@total_time` gets above two billion milliseconds (about 23
|
56
|
+
# days), it's reset to make sure the result fits in a signed 32-bit
|
57
|
+
# integer.
|
58
|
+
#
|
59
|
+
# @return [Integer]
|
60
|
+
def total_time
|
61
|
+
lock.synchronize do
|
62
|
+
@total_time += (internal_profiler.total_time * 1000).round
|
63
|
+
internal_profiler.clear
|
64
|
+
end
|
65
|
+
|
66
|
+
@total_time = 0 if @total_time > 2_000_000_000
|
67
|
+
|
68
|
+
@total_time
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def internal_profiler
|
74
|
+
GC::Profiler
|
75
|
+
end
|
76
|
+
|
77
|
+
def lock
|
78
|
+
self.class.lock
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# A dummy profiler that always returns 0 as the total time. Used when GC
|
83
|
+
# profiler is disabled.
|
84
|
+
class NilProfiler
|
85
|
+
def total_time
|
86
|
+
0
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/appsignal/probes/mri.rb
CHANGED
@@ -8,7 +8,7 @@ module Appsignal
|
|
8
8
|
defined?(::RubyVM) && ::RubyVM.respond_to?(:stat)
|
9
9
|
end
|
10
10
|
|
11
|
-
def initialize(appsignal: Appsignal, gc_profiler: Appsignal::
|
11
|
+
def initialize(appsignal: Appsignal, gc_profiler: Appsignal::GarbageCollection.profiler)
|
12
12
|
Appsignal.logger.debug("Initializing VM probe")
|
13
13
|
@appsignal = appsignal
|
14
14
|
@gc_profiler = gc_profiler
|
@@ -31,8 +31,10 @@ module Appsignal
|
|
31
31
|
)
|
32
32
|
|
33
33
|
set_gauge("thread_count", Thread.list.size)
|
34
|
-
|
35
|
-
|
34
|
+
if Appsignal::GarbageCollection.enabled?
|
35
|
+
gauge_delta(:gc_time, @gc_profiler.total_time) do |gc_time|
|
36
|
+
set_gauge("gc_time", gc_time) if gc_time > 0
|
37
|
+
end
|
36
38
|
end
|
37
39
|
|
38
40
|
gc_stats = GC.stat
|
@@ -66,11 +66,6 @@ module Appsignal
|
|
66
66
|
def clear_current_transaction!
|
67
67
|
Thread.current[:appsignal_transaction] = nil
|
68
68
|
end
|
69
|
-
|
70
|
-
def garbage_collection_profiler
|
71
|
-
@garbage_collection_profiler ||=
|
72
|
-
Appsignal.config[:enable_gc_instrumentation] ? Appsignal::GarbageCollectionProfiler.new : NilGarbageCollectionProfiler.new
|
73
|
-
end
|
74
69
|
end
|
75
70
|
|
76
71
|
attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options, :discarded, :breadcrumbs
|
@@ -103,7 +98,7 @@ module Appsignal
|
|
103
98
|
@ext = Appsignal::Extension.start_transaction(
|
104
99
|
@transaction_id,
|
105
100
|
@namespace,
|
106
|
-
|
101
|
+
0
|
107
102
|
) || Appsignal::Extension::MockTransaction.new
|
108
103
|
end
|
109
104
|
|
@@ -117,9 +112,7 @@ module Appsignal
|
|
117
112
|
"because it was manually discarded."
|
118
113
|
return
|
119
114
|
end
|
120
|
-
if @ext.finish(
|
121
|
-
sample_data
|
122
|
-
end
|
115
|
+
sample_data if @ext.finish(0)
|
123
116
|
@ext.complete
|
124
117
|
end
|
125
118
|
|
@@ -355,7 +348,7 @@ module Appsignal
|
|
355
348
|
|
356
349
|
def start_event
|
357
350
|
return if paused?
|
358
|
-
@ext.start_event(
|
351
|
+
@ext.start_event(0)
|
359
352
|
end
|
360
353
|
|
361
354
|
def finish_event(name, title, body, body_format = Appsignal::EventFormatter::DEFAULT)
|
@@ -365,7 +358,7 @@ module Appsignal
|
|
365
358
|
title || BLANK,
|
366
359
|
body || BLANK,
|
367
360
|
body_format || Appsignal::EventFormatter::DEFAULT,
|
368
|
-
|
361
|
+
0
|
369
362
|
)
|
370
363
|
end
|
371
364
|
|
@@ -377,7 +370,7 @@ module Appsignal
|
|
377
370
|
body || BLANK,
|
378
371
|
body_format || Appsignal::EventFormatter::DEFAULT,
|
379
372
|
duration,
|
380
|
-
|
373
|
+
0
|
381
374
|
)
|
382
375
|
end
|
383
376
|
|
data/lib/appsignal/version.rb
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -115,11 +115,6 @@ module Appsignal
|
|
115
115
|
Appsignal::Environment.report_enabled("allocation_tracking")
|
116
116
|
end
|
117
117
|
|
118
|
-
if config[:enable_gc_instrumentation]
|
119
|
-
GC::Profiler.enable
|
120
|
-
Appsignal::Environment.report_enabled("gc_instrumentation")
|
121
|
-
end
|
122
|
-
|
123
118
|
Appsignal::Minutely.start if config[:enable_minutely_probes]
|
124
119
|
|
125
120
|
collect_environment_metadata
|
@@ -298,7 +293,7 @@ require "appsignal/hooks"
|
|
298
293
|
require "appsignal/probes"
|
299
294
|
require "appsignal/marker"
|
300
295
|
require "appsignal/minutely"
|
301
|
-
require "appsignal/
|
296
|
+
require "appsignal/garbage_collection"
|
302
297
|
require "appsignal/integrations/railtie" if defined?(::Rails)
|
303
298
|
require "appsignal/transaction"
|
304
299
|
require "appsignal/version"
|
@@ -156,7 +156,6 @@ describe Appsignal::Config do
|
|
156
156
|
:debug => false,
|
157
157
|
:dns_servers => [],
|
158
158
|
:enable_allocation_tracking => true,
|
159
|
-
:enable_gc_instrumentation => false,
|
160
159
|
:enable_host_metrics => true,
|
161
160
|
:enable_minutely_probes => true,
|
162
161
|
:enable_statsd => true,
|
@@ -1,11 +1,33 @@
|
|
1
|
-
describe Appsignal::
|
1
|
+
describe Appsignal::GarbageCollection do
|
2
|
+
describe ".profiler" do
|
3
|
+
before do
|
4
|
+
# Unset the internal memoized variable to avoid state leaking
|
5
|
+
described_class.clear_profiler!
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when GC instrumentation is disabled" do
|
9
|
+
it "returns the NilProfiler" do
|
10
|
+
expect(described_class.profiler).to be_a(Appsignal::GarbageCollection::NilProfiler)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when GC profiling is enabled" do
|
15
|
+
before { GC::Profiler.enable }
|
16
|
+
after { GC::Profiler.disable }
|
17
|
+
|
18
|
+
it "returns the Profiler" do
|
19
|
+
expect(described_class.profiler).to be_a(Appsignal::GarbageCollection::Profiler)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Appsignal::GarbageCollection::Profiler do
|
2
26
|
let(:internal_profiler) { FakeGCProfiler.new }
|
3
27
|
let(:profiler) { described_class.new }
|
4
28
|
|
5
29
|
before do
|
6
|
-
|
7
|
-
.to receive(:internal_profiler)
|
8
|
-
.and_return(internal_profiler)
|
30
|
+
stub_const("GC::Profiler", internal_profiler)
|
9
31
|
end
|
10
32
|
|
11
33
|
context "on initialization" do
|
@@ -54,7 +76,7 @@ describe Appsignal::GarbageCollectionProfiler do
|
|
54
76
|
|
55
77
|
2.times do
|
56
78
|
threads << Thread.new do
|
57
|
-
profiler = Appsignal::
|
79
|
+
profiler = Appsignal::GarbageCollection::Profiler.new
|
58
80
|
results << profiler.total_time
|
59
81
|
end
|
60
82
|
end
|
@@ -65,7 +87,7 @@ describe Appsignal::GarbageCollectionProfiler do
|
|
65
87
|
end
|
66
88
|
end
|
67
89
|
|
68
|
-
describe Appsignal::
|
90
|
+
describe Appsignal::GarbageCollection::NilProfiler do
|
69
91
|
let(:profiler) { described_class.new }
|
70
92
|
|
71
93
|
describe "#total_time" do
|
@@ -39,6 +39,7 @@ describe Appsignal::Probes::MriProbe do
|
|
39
39
|
let(:hostname) { nil }
|
40
40
|
before do
|
41
41
|
allow(gc_profiler_mock).to receive(:total_time)
|
42
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
42
43
|
end
|
43
44
|
|
44
45
|
it "should track vm metrics" do
|
@@ -70,6 +71,40 @@ describe Appsignal::Probes::MriProbe do
|
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
74
|
+
context "when GC profiling is disabled" do
|
75
|
+
it "does not report a gc_time metric" do
|
76
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(false)
|
77
|
+
expect(gc_profiler_mock).to_not receive(:total_time)
|
78
|
+
probe.call # Normal call, create a cache
|
79
|
+
probe.call # Report delta value based on cached value
|
80
|
+
metrics = appsignal_mock.gauges.map { |(key)| key }
|
81
|
+
expect(metrics).to_not include("gc_time")
|
82
|
+
end
|
83
|
+
|
84
|
+
it "does not report a gc_time metric while temporarily disabled" do
|
85
|
+
# While enabled
|
86
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
87
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(10, 15)
|
88
|
+
probe.call # Normal call, create a cache
|
89
|
+
probe.call # Report delta value based on cached value
|
90
|
+
expect_gauges([["gc_time", 5]])
|
91
|
+
|
92
|
+
# While disabled
|
93
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(false)
|
94
|
+
probe.call # Call twice to make sure any caches resets wouldn't mess up the assertion
|
95
|
+
probe.call
|
96
|
+
# Does not include any newly reported metrics
|
97
|
+
expect_gauges([["gc_time", 5]])
|
98
|
+
|
99
|
+
# When enabled after being disabled for a while, it only reports the
|
100
|
+
# newly reported time since it was renabled
|
101
|
+
allow(GC::Profiler).to receive(:enabled?).and_return(true)
|
102
|
+
expect(gc_profiler_mock).to receive(:total_time).and_return(25)
|
103
|
+
probe.call
|
104
|
+
expect_gauges([["gc_time", 5], ["gc_time", 10]])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
73
108
|
it "tracks GC run count" do
|
74
109
|
expect(GC).to receive(:count).and_return(10, 15)
|
75
110
|
expect(GC).to receive(:stat).and_return(
|
@@ -792,23 +792,6 @@ describe Appsignal::Transaction do
|
|
792
792
|
end
|
793
793
|
end
|
794
794
|
|
795
|
-
describe "#garbage_collection_profiler" do
|
796
|
-
before { Appsignal::Transaction.instance_variable_set(:@garbage_collection_profiler, nil) }
|
797
|
-
|
798
|
-
it "returns the NilGarbageCollectionProfiler" do
|
799
|
-
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::NilGarbageCollectionProfiler)
|
800
|
-
end
|
801
|
-
|
802
|
-
context "when gc profiling is enabled" do
|
803
|
-
before { Appsignal.config.config_hash[:enable_gc_instrumentation] = true }
|
804
|
-
after { Appsignal.config.config_hash[:enable_gc_instrumentation] = false }
|
805
|
-
|
806
|
-
it "returns the GarbageCollectionProfiler" do
|
807
|
-
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::GarbageCollectionProfiler)
|
808
|
-
end
|
809
|
-
end
|
810
|
-
end
|
811
|
-
|
812
795
|
describe "#start_event" do
|
813
796
|
it "starts the event in the extension" do
|
814
797
|
expect(transaction.ext).to receive(:start_event).with(0).and_call_original
|
@@ -827,11 +810,7 @@ describe Appsignal::Transaction do
|
|
827
810
|
end
|
828
811
|
|
829
812
|
describe "#finish_event" do
|
830
|
-
let(:fake_gc_time) {
|
831
|
-
before do
|
832
|
-
expect(described_class.garbage_collection_profiler)
|
833
|
-
.to receive(:total_time).at_least(:once).and_return(fake_gc_time)
|
834
|
-
end
|
813
|
+
let(:fake_gc_time) { 0 }
|
835
814
|
|
836
815
|
it "should finish the event in the extension" do
|
837
816
|
expect(transaction.ext).to receive(:finish_event).with(
|
@@ -878,11 +857,7 @@ describe Appsignal::Transaction do
|
|
878
857
|
end
|
879
858
|
|
880
859
|
describe "#record_event" do
|
881
|
-
let(:fake_gc_time) {
|
882
|
-
before do
|
883
|
-
expect(described_class.garbage_collection_profiler)
|
884
|
-
.to receive(:total_time).at_least(:once).and_return(fake_gc_time)
|
885
|
-
end
|
860
|
+
let(:fake_gc_time) { 0 }
|
886
861
|
|
887
862
|
it "should record the event in the extension" do
|
888
863
|
expect(transaction.ext).to receive(:record_event).with(
|
data/spec/lib/appsignal_spec.rb
CHANGED
@@ -54,20 +54,12 @@ describe Appsignal do
|
|
54
54
|
Appsignal.start
|
55
55
|
end
|
56
56
|
|
57
|
-
context "when allocation tracking
|
57
|
+
context "when allocation tracking has been enabled" do
|
58
58
|
before do
|
59
|
-
allow(GC::Profiler).to receive(:enable)
|
60
59
|
Appsignal.config.config_hash[:enable_allocation_tracking] = true
|
61
|
-
Appsignal.config.config_hash[:enable_gc_instrumentation] = true
|
62
60
|
capture_environment_metadata_report_calls
|
63
61
|
end
|
64
62
|
|
65
|
-
it "should enable Ruby's GC::Profiler" do
|
66
|
-
expect(GC::Profiler).to receive(:enable)
|
67
|
-
Appsignal.start
|
68
|
-
expect_environment_metadata("ruby_gc_instrumentation_enabled", "true")
|
69
|
-
end
|
70
|
-
|
71
63
|
unless DependencyHelper.running_jruby?
|
72
64
|
it "installs the allocation event hook" do
|
73
65
|
expect(Appsignal::Extension).to receive(:install_allocation_event_hook)
|
@@ -78,29 +70,17 @@ describe Appsignal do
|
|
78
70
|
end
|
79
71
|
end
|
80
72
|
|
81
|
-
context "when allocation tracking
|
73
|
+
context "when allocation tracking has been disabled" do
|
82
74
|
before do
|
83
75
|
Appsignal.config.config_hash[:enable_allocation_tracking] = false
|
84
|
-
Appsignal.config.config_hash[:enable_gc_instrumentation] = false
|
85
76
|
capture_environment_metadata_report_calls
|
86
77
|
end
|
87
78
|
|
88
|
-
it "should not enable Ruby's GC::Profiler" do
|
89
|
-
expect(GC::Profiler).not_to receive(:enable)
|
90
|
-
Appsignal.start
|
91
|
-
end
|
92
|
-
|
93
79
|
it "should not install the allocation event hook" do
|
94
80
|
expect(Appsignal::Minutely).not_to receive(:install_allocation_event_hook)
|
95
81
|
Appsignal.start
|
96
82
|
expect_not_environment_metadata("ruby_allocation_tracking_enabled")
|
97
83
|
end
|
98
|
-
|
99
|
-
it "should not add the gc probe to minutely" do
|
100
|
-
expect(Appsignal::Minutely).not_to receive(:register_garbage_collection_probe)
|
101
|
-
Appsignal.start
|
102
|
-
expect_not_environment_metadata("ruby_gc_instrumentation_enabled")
|
103
|
-
end
|
104
84
|
end
|
105
85
|
|
106
86
|
context "when minutely metrics has been enabled" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appsignal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Beekman
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-08-
|
13
|
+
date: 2022-08-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -204,7 +204,7 @@ files:
|
|
204
204
|
- lib/appsignal/event_formatter/sequel/sql_formatter.rb
|
205
205
|
- lib/appsignal/extension.rb
|
206
206
|
- lib/appsignal/extension/jruby.rb
|
207
|
-
- lib/appsignal/
|
207
|
+
- lib/appsignal/garbage_collection.rb
|
208
208
|
- lib/appsignal/helpers/instrumentation.rb
|
209
209
|
- lib/appsignal/helpers/metrics.rb
|
210
210
|
- lib/appsignal/hooks.rb
|
@@ -305,7 +305,7 @@ files:
|
|
305
305
|
- spec/lib/appsignal/extension/jruby_spec.rb
|
306
306
|
- spec/lib/appsignal/extension_install_failure_spec.rb
|
307
307
|
- spec/lib/appsignal/extension_spec.rb
|
308
|
-
- spec/lib/appsignal/
|
308
|
+
- spec/lib/appsignal/garbage_collection_spec.rb
|
309
309
|
- spec/lib/appsignal/hooks/action_cable_spec.rb
|
310
310
|
- spec/lib/appsignal/hooks/action_mailer_spec.rb
|
311
311
|
- spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb
|
@@ -457,7 +457,7 @@ test_files:
|
|
457
457
|
- spec/lib/appsignal/extension/jruby_spec.rb
|
458
458
|
- spec/lib/appsignal/extension_install_failure_spec.rb
|
459
459
|
- spec/lib/appsignal/extension_spec.rb
|
460
|
-
- spec/lib/appsignal/
|
460
|
+
- spec/lib/appsignal/garbage_collection_spec.rb
|
461
461
|
- spec/lib/appsignal/hooks/action_cable_spec.rb
|
462
462
|
- spec/lib/appsignal/hooks/action_mailer_spec.rb
|
463
463
|
- spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appsignal
|
4
|
-
# {Appsignal::GarbageCollectionProfiler} wraps Ruby's `GC::Profiler` to be
|
5
|
-
# able to track garbage collection time for multiple transactions, while
|
6
|
-
# constantly clearing `GC::Profiler`'s total_time to make sure it doesn't
|
7
|
-
# leak memory by keeping garbage collection run samples in memory.
|
8
|
-
#
|
9
|
-
# @api private
|
10
|
-
class GarbageCollectionProfiler
|
11
|
-
def self.lock
|
12
|
-
@lock ||= Mutex.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@total_time = 0
|
17
|
-
end
|
18
|
-
|
19
|
-
# Whenever {#total_time} is called, the current `GC::Profiler#total_time`
|
20
|
-
# gets added to `@total_time`, after which `GC::Profiler.clear` is called
|
21
|
-
# to prevent it from leaking memory. A class-level lock is used to make
|
22
|
-
# sure garbage collection time is never counted more than once.
|
23
|
-
#
|
24
|
-
# Whenever `@total_time` gets above two billion milliseconds (about 23
|
25
|
-
# days), it's reset to make sure the result fits in a signed 32-bit
|
26
|
-
# integer.
|
27
|
-
#
|
28
|
-
# @return [Integer]
|
29
|
-
def total_time
|
30
|
-
lock.synchronize do
|
31
|
-
@total_time += (internal_profiler.total_time * 1000).round
|
32
|
-
internal_profiler.clear
|
33
|
-
end
|
34
|
-
|
35
|
-
@total_time = 0 if @total_time > 2_000_000_000
|
36
|
-
|
37
|
-
@total_time
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def internal_profiler
|
43
|
-
GC::Profiler
|
44
|
-
end
|
45
|
-
|
46
|
-
def lock
|
47
|
-
self.class.lock
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# {Appsignal::NilGarbageCollectionProfiler} is a dummy profiler
|
52
|
-
# that always returns 0 as the total time.
|
53
|
-
# Used when we don't want any profile information
|
54
|
-
#
|
55
|
-
# @api private
|
56
|
-
class NilGarbageCollectionProfiler
|
57
|
-
def total_time
|
58
|
-
0
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|