appsignal 3.1.3-java → 3.1.5-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/ext/agent.yml +27 -27
- data/gemfiles/padrino.gemfile +2 -1
- data/gemfiles/que.gemfile +1 -1
- 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/lib/puma/plugin/appsignal.rb +17 -5
- 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 +30 -62
- data/spec/lib/appsignal_spec.rb +3 -23
- data/spec/lib/puma/appsignal_spec.rb +45 -6
- metadata +6 -6
- 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: 20749c0f3826167272d727c37dd1e881502a9654f8b499d4f3fcdf40dd386178
|
|
4
|
+
data.tar.gz: 90ddbe20ee5243338aefdfbefbb1989bbe1df5cc57a56a4f277bcfa789086b41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9f2133fe6f929ebbbee6b9c8f47f85bd3c895b518daf6a69b5ad8a2e9a29ebcd72ca1c25a7aef8512a8493f8941ab711fda9b0f16fff30cac73c40701376a47
|
|
7
|
+
data.tar.gz: bfe585b6c6ce5f8cc5e470c9a164e6690fc1834e40bb4bd27491f719cbdaf6ebd4b92d1f1ba2bc3001e157f5c35786f12143b29d9908e9ce73d9ca9712c7c5ef
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
|
2
2
|
|
|
3
|
+
## 3.1.5
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- [4035c3c2](https://github.com/appsignal/appsignal-ruby/commit/4035c3c2d5c0b002119054014daddd193bd820f0) patch - Bump agent to version 813a59b
|
|
8
|
+
|
|
9
|
+
- Fix http proxy config option parsing for port 80.
|
|
10
|
+
- Fix the return value for appsignal_import_opentelemetry_span extension
|
|
11
|
+
function in `appsignal.h`.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- [feb60fb8](https://github.com/appsignal/appsignal-ruby/commit/feb60fb877a2b264e587fe3d5d546e40d86c9c38) patch - Fix NoMethodError for AppSignal Puma plugin for Puma 6. Puma 5 is also still supported.
|
|
16
|
+
|
|
17
|
+
## 3.1.4
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- [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`.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- [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.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- [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.
|
|
30
|
+
|
|
3
31
|
## 3.1.3
|
|
4
32
|
|
|
5
33
|
### Added
|
data/ext/agent.yml
CHANGED
|
@@ -3,99 +3,99 @@
|
|
|
3
3
|
# appsignal-agent repository.
|
|
4
4
|
# Modifications to this file will be overwritten with the next agent release.
|
|
5
5
|
---
|
|
6
|
-
version:
|
|
6
|
+
version: 813a59b
|
|
7
7
|
mirrors:
|
|
8
8
|
- https://appsignal-agent-releases.global.ssl.fastly.net
|
|
9
9
|
- https://d135dj0rjqvssy.cloudfront.net
|
|
10
10
|
triples:
|
|
11
11
|
x86_64-darwin:
|
|
12
12
|
static:
|
|
13
|
-
checksum:
|
|
13
|
+
checksum: c8919a19a28950f726221829ea4d2b3312f1595a5e28ea134f8c41ed0814d7cd
|
|
14
14
|
filename: appsignal-x86_64-darwin-all-static.tar.gz
|
|
15
15
|
dynamic:
|
|
16
|
-
checksum:
|
|
16
|
+
checksum: 1c10139bc4df56048a71766b64eba76462ee38d3cc814dc230e0fdb3c7e4fba3
|
|
17
17
|
filename: appsignal-x86_64-darwin-all-dynamic.tar.gz
|
|
18
18
|
universal-darwin:
|
|
19
19
|
static:
|
|
20
|
-
checksum:
|
|
20
|
+
checksum: c8919a19a28950f726221829ea4d2b3312f1595a5e28ea134f8c41ed0814d7cd
|
|
21
21
|
filename: appsignal-x86_64-darwin-all-static.tar.gz
|
|
22
22
|
dynamic:
|
|
23
|
-
checksum:
|
|
23
|
+
checksum: 1c10139bc4df56048a71766b64eba76462ee38d3cc814dc230e0fdb3c7e4fba3
|
|
24
24
|
filename: appsignal-x86_64-darwin-all-dynamic.tar.gz
|
|
25
25
|
aarch64-darwin:
|
|
26
26
|
static:
|
|
27
|
-
checksum:
|
|
27
|
+
checksum: 40a38896132f418362af9fb2e9796eb4479e13cc0691b61f0f0b81b77e66ded6
|
|
28
28
|
filename: appsignal-aarch64-darwin-all-static.tar.gz
|
|
29
29
|
dynamic:
|
|
30
|
-
checksum:
|
|
30
|
+
checksum: 40ec0c7db246cfc9b8eeebc882b07ba625948f376a53d8e24add7148d0f8c067
|
|
31
31
|
filename: appsignal-aarch64-darwin-all-dynamic.tar.gz
|
|
32
32
|
arm64-darwin:
|
|
33
33
|
static:
|
|
34
|
-
checksum:
|
|
34
|
+
checksum: 40a38896132f418362af9fb2e9796eb4479e13cc0691b61f0f0b81b77e66ded6
|
|
35
35
|
filename: appsignal-aarch64-darwin-all-static.tar.gz
|
|
36
36
|
dynamic:
|
|
37
|
-
checksum:
|
|
37
|
+
checksum: 40ec0c7db246cfc9b8eeebc882b07ba625948f376a53d8e24add7148d0f8c067
|
|
38
38
|
filename: appsignal-aarch64-darwin-all-dynamic.tar.gz
|
|
39
39
|
arm-darwin:
|
|
40
40
|
static:
|
|
41
|
-
checksum:
|
|
41
|
+
checksum: 40a38896132f418362af9fb2e9796eb4479e13cc0691b61f0f0b81b77e66ded6
|
|
42
42
|
filename: appsignal-aarch64-darwin-all-static.tar.gz
|
|
43
43
|
dynamic:
|
|
44
|
-
checksum:
|
|
44
|
+
checksum: 40ec0c7db246cfc9b8eeebc882b07ba625948f376a53d8e24add7148d0f8c067
|
|
45
45
|
filename: appsignal-aarch64-darwin-all-dynamic.tar.gz
|
|
46
46
|
aarch64-linux:
|
|
47
47
|
static:
|
|
48
|
-
checksum:
|
|
48
|
+
checksum: c73b6e9de849a40290a0d90eaad43ea41a9a0293ba4b8bf99f69965c45c85514
|
|
49
49
|
filename: appsignal-aarch64-linux-all-static.tar.gz
|
|
50
50
|
dynamic:
|
|
51
|
-
checksum:
|
|
51
|
+
checksum: 90226eefe2e2f66833ca3e31c69ce70763ed57916bd0b5c1809bd99d61ff3429
|
|
52
52
|
filename: appsignal-aarch64-linux-all-dynamic.tar.gz
|
|
53
53
|
i686-linux:
|
|
54
54
|
static:
|
|
55
|
-
checksum:
|
|
55
|
+
checksum: 6741b9a068dc405b3d6d07953fab7fc876c21b4add1cbb2b4c4c4dfdeca5d387
|
|
56
56
|
filename: appsignal-i686-linux-all-static.tar.gz
|
|
57
57
|
dynamic:
|
|
58
|
-
checksum:
|
|
58
|
+
checksum: 1af902b37af378a06251365fb637f86298380d3627c54f2945a85c1b7f075fda
|
|
59
59
|
filename: appsignal-i686-linux-all-dynamic.tar.gz
|
|
60
60
|
x86-linux:
|
|
61
61
|
static:
|
|
62
|
-
checksum:
|
|
62
|
+
checksum: 6741b9a068dc405b3d6d07953fab7fc876c21b4add1cbb2b4c4c4dfdeca5d387
|
|
63
63
|
filename: appsignal-i686-linux-all-static.tar.gz
|
|
64
64
|
dynamic:
|
|
65
|
-
checksum:
|
|
65
|
+
checksum: 1af902b37af378a06251365fb637f86298380d3627c54f2945a85c1b7f075fda
|
|
66
66
|
filename: appsignal-i686-linux-all-dynamic.tar.gz
|
|
67
67
|
x86_64-linux:
|
|
68
68
|
static:
|
|
69
|
-
checksum:
|
|
69
|
+
checksum: 8355b017093db606014023cc617d84d6375d503d7ffa54f62c7b3dc56fb64ead
|
|
70
70
|
filename: appsignal-x86_64-linux-all-static.tar.gz
|
|
71
71
|
dynamic:
|
|
72
|
-
checksum:
|
|
72
|
+
checksum: 7c239a7ffe18cb173120bd67fb96563f4a81f0744bbbb47082f077a38ccbe5f1
|
|
73
73
|
filename: appsignal-x86_64-linux-all-dynamic.tar.gz
|
|
74
74
|
x86_64-linux-musl:
|
|
75
75
|
static:
|
|
76
|
-
checksum:
|
|
76
|
+
checksum: e9d98ed23b872dbf1e67a081473918cf88c4af775b1caadbfd93deda2635d9f8
|
|
77
77
|
filename: appsignal-x86_64-linux-musl-all-static.tar.gz
|
|
78
78
|
dynamic:
|
|
79
|
-
checksum:
|
|
79
|
+
checksum: 5538172a95dfca1a4cf8e111ba61eab5e9c16314fa902259711cb9e8e0d2f85e
|
|
80
80
|
filename: appsignal-x86_64-linux-musl-all-dynamic.tar.gz
|
|
81
81
|
aarch64-linux-musl:
|
|
82
82
|
static:
|
|
83
|
-
checksum:
|
|
83
|
+
checksum: 0fb3eacfb8c8bc01c4acc8916327626720de376bcdd95104be71bb11a4ff9215
|
|
84
84
|
filename: appsignal-aarch64-linux-musl-all-static.tar.gz
|
|
85
85
|
dynamic:
|
|
86
|
-
checksum:
|
|
86
|
+
checksum: b87bcedaa2aa886acf3a93ce6e32762a843f3bee1ca7a8f9e0d17ca32f7a7d39
|
|
87
87
|
filename: appsignal-aarch64-linux-musl-all-dynamic.tar.gz
|
|
88
88
|
x86_64-freebsd:
|
|
89
89
|
static:
|
|
90
|
-
checksum:
|
|
90
|
+
checksum: b7d3c244b7068213840f5970df2e318d98f7909eb3b2b4ab42441d064ffb19ee
|
|
91
91
|
filename: appsignal-x86_64-freebsd-all-static.tar.gz
|
|
92
92
|
dynamic:
|
|
93
|
-
checksum:
|
|
93
|
+
checksum: 0a739134f11d50318d14f247df1f8cc0f8aec1fbcb70a8bc48d5e1f22dc4aaba
|
|
94
94
|
filename: appsignal-x86_64-freebsd-all-dynamic.tar.gz
|
|
95
95
|
amd64-freebsd:
|
|
96
96
|
static:
|
|
97
|
-
checksum:
|
|
97
|
+
checksum: b7d3c244b7068213840f5970df2e318d98f7909eb3b2b4ab42441d064ffb19ee
|
|
98
98
|
filename: appsignal-x86_64-freebsd-all-static.tar.gz
|
|
99
99
|
dynamic:
|
|
100
|
-
checksum:
|
|
100
|
+
checksum: 0a739134f11d50318d14f247df1f8cc0f8aec1fbcb70a8bc48d5e1f22dc4aaba
|
|
101
101
|
filename: appsignal-x86_64-freebsd-all-dynamic.tar.gz
|
data/gemfiles/padrino.gemfile
CHANGED
data/gemfiles/que.gemfile
CHANGED
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"
|
|
@@ -11,9 +11,9 @@ require "json"
|
|
|
11
11
|
Puma::Plugin.create do # rubocop:disable Metrics/BlockLength
|
|
12
12
|
def start(launcher)
|
|
13
13
|
@launcher = launcher
|
|
14
|
-
|
|
14
|
+
log_debug "AppSignal: Puma plugin start."
|
|
15
15
|
in_background do
|
|
16
|
-
|
|
16
|
+
log_debug "AppSignal: Start Puma stats collection loop."
|
|
17
17
|
plugin = AppsignalPumaPlugin.new
|
|
18
18
|
|
|
19
19
|
loop do
|
|
@@ -24,12 +24,12 @@ Puma::Plugin.create do # rubocop:disable Metrics/BlockLength
|
|
|
24
24
|
# metrics.
|
|
25
25
|
sleep sleep_time
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
log_debug "AppSignal: Collecting Puma stats."
|
|
28
28
|
stats = fetch_puma_stats
|
|
29
29
|
if stats
|
|
30
30
|
plugin.call(stats)
|
|
31
31
|
else
|
|
32
|
-
|
|
32
|
+
log_debug "AppSignal: No Puma stats to report."
|
|
33
33
|
end
|
|
34
34
|
rescue StandardError => error
|
|
35
35
|
log_error "Error while processing metrics.", error
|
|
@@ -44,8 +44,20 @@ Puma::Plugin.create do # rubocop:disable Metrics/BlockLength
|
|
|
44
44
|
60 # seconds
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def logger
|
|
48
|
+
if @launcher.respond_to? :log_writer
|
|
49
|
+
@launcher.log_writer
|
|
50
|
+
else
|
|
51
|
+
@launcher.events
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def log_debug(message)
|
|
56
|
+
logger.debug message
|
|
57
|
+
end
|
|
58
|
+
|
|
47
59
|
def log_error(message, error)
|
|
48
|
-
|
|
60
|
+
logger.error "AppSignal: #{message}\n" \
|
|
49
61
|
"#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
|
|
50
62
|
end
|
|
51
63
|
|
|
@@ -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(
|
|
@@ -683,43 +683,36 @@ describe Appsignal::Transaction do
|
|
|
683
683
|
end
|
|
684
684
|
|
|
685
685
|
describe "#sample_data" do
|
|
686
|
-
|
|
687
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
688
|
-
"environment",
|
|
689
|
-
Appsignal::Utils::Data.generate(
|
|
690
|
-
"CONTENT_LENGTH" => "0",
|
|
691
|
-
"REQUEST_METHOD" => "GET",
|
|
692
|
-
"SERVER_NAME" => "example.org",
|
|
693
|
-
"SERVER_PORT" => "80",
|
|
694
|
-
"PATH_INFO" => "/blog"
|
|
695
|
-
)
|
|
696
|
-
).once
|
|
697
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
698
|
-
"session_data",
|
|
699
|
-
Appsignal::Utils::Data.generate({})
|
|
700
|
-
).once
|
|
701
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
702
|
-
"params",
|
|
703
|
-
Appsignal::Utils::Data.generate(
|
|
704
|
-
"controller" => "blog_posts",
|
|
705
|
-
"action" => "show",
|
|
706
|
-
"id" => "1"
|
|
707
|
-
)
|
|
708
|
-
).once
|
|
709
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
710
|
-
"metadata",
|
|
711
|
-
Appsignal::Utils::Data.generate("key" => "value")
|
|
712
|
-
).once
|
|
713
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
714
|
-
"tags",
|
|
715
|
-
Appsignal::Utils::Data.generate({})
|
|
716
|
-
).once
|
|
717
|
-
expect(transaction.ext).to receive(:set_sample_data).with(
|
|
718
|
-
"breadcrumbs",
|
|
719
|
-
Appsignal::Utils::Data.generate([])
|
|
720
|
-
).once
|
|
686
|
+
let(:env) { { "rack.session" => { "session" => "value" } } }
|
|
721
687
|
|
|
688
|
+
it "sets sample data" do
|
|
689
|
+
transaction.set_tags "tag" => "value"
|
|
690
|
+
transaction.add_breadcrumb "category", "action", "message", "key" => "value"
|
|
722
691
|
transaction.sample_data
|
|
692
|
+
|
|
693
|
+
sample_data = transaction.to_h["sample_data"]
|
|
694
|
+
expect(sample_data["environment"]).to include(
|
|
695
|
+
"CONTENT_LENGTH" => "0",
|
|
696
|
+
"REQUEST_METHOD" => "GET",
|
|
697
|
+
"SERVER_NAME" => "example.org",
|
|
698
|
+
"SERVER_PORT" => "80",
|
|
699
|
+
"PATH_INFO" => "/blog"
|
|
700
|
+
)
|
|
701
|
+
expect(sample_data["session_data"]).to eq("session" => "value")
|
|
702
|
+
expect(sample_data["params"]).to eq(
|
|
703
|
+
"controller" => "blog_posts",
|
|
704
|
+
"action" => "show",
|
|
705
|
+
"id" => "1"
|
|
706
|
+
)
|
|
707
|
+
expect(sample_data["metadata"]).to eq("key" => "value")
|
|
708
|
+
expect(sample_data["tags"]).to eq("tag" => "value")
|
|
709
|
+
expect(sample_data["breadcrumbs"]).to contain_exactly(
|
|
710
|
+
"action" => "action",
|
|
711
|
+
"category" => "category",
|
|
712
|
+
"message" => "message",
|
|
713
|
+
"metadata" => { "key" => "value" },
|
|
714
|
+
"time" => kind_of(Integer)
|
|
715
|
+
)
|
|
723
716
|
end
|
|
724
717
|
end
|
|
725
718
|
|
|
@@ -792,23 +785,6 @@ describe Appsignal::Transaction do
|
|
|
792
785
|
end
|
|
793
786
|
end
|
|
794
787
|
|
|
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
788
|
describe "#start_event" do
|
|
813
789
|
it "starts the event in the extension" do
|
|
814
790
|
expect(transaction.ext).to receive(:start_event).with(0).and_call_original
|
|
@@ -827,11 +803,7 @@ describe Appsignal::Transaction do
|
|
|
827
803
|
end
|
|
828
804
|
|
|
829
805
|
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
|
|
806
|
+
let(:fake_gc_time) { 0 }
|
|
835
807
|
|
|
836
808
|
it "should finish the event in the extension" do
|
|
837
809
|
expect(transaction.ext).to receive(:finish_event).with(
|
|
@@ -878,11 +850,7 @@ describe Appsignal::Transaction do
|
|
|
878
850
|
end
|
|
879
851
|
|
|
880
852
|
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
|
|
853
|
+
let(:fake_gc_time) { 0 }
|
|
886
854
|
|
|
887
855
|
it "should record the event in the extension" do
|
|
888
856
|
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
|
-
expect(Appsignal::
|
|
80
|
+
expect(Appsignal::Extension).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
|
|
@@ -2,14 +2,14 @@ RSpec.describe "Puma plugin" do
|
|
|
2
2
|
include WaitForHelper
|
|
3
3
|
|
|
4
4
|
class MockPumaLauncher
|
|
5
|
-
def
|
|
6
|
-
return @
|
|
5
|
+
def log_writer
|
|
6
|
+
return @log_writer if defined?(@log_writer)
|
|
7
7
|
|
|
8
|
-
@
|
|
8
|
+
@log_writer = MockPumaLogWriter.new
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class MockPumaLogWriter
|
|
13
13
|
attr_reader :logs
|
|
14
14
|
|
|
15
15
|
def initialize
|
|
@@ -153,7 +153,7 @@ RSpec.describe "Puma plugin" do
|
|
|
153
153
|
end
|
|
154
154
|
|
|
155
155
|
def logs
|
|
156
|
-
launcher.
|
|
156
|
+
launcher.log_writer.logs
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
def messages
|
|
@@ -281,7 +281,7 @@ RSpec.describe "Puma plugin" do
|
|
|
281
281
|
it "does not fetch metrics" do
|
|
282
282
|
run_plugin(appsignal_plugin) do
|
|
283
283
|
expect(logs).to_not include([:error, kind_of(String)])
|
|
284
|
-
expect(logs).to include([:
|
|
284
|
+
expect(logs).to include([:debug, "AppSignal: No Puma stats to report."])
|
|
285
285
|
expect(messages).to be_empty
|
|
286
286
|
end
|
|
287
287
|
end
|
|
@@ -296,4 +296,43 @@ RSpec.describe "Puma plugin" do
|
|
|
296
296
|
end
|
|
297
297
|
end
|
|
298
298
|
end
|
|
299
|
+
|
|
300
|
+
context "with Puma < 6 Events class" do
|
|
301
|
+
class MockPumaEvents
|
|
302
|
+
attr_reader :logs
|
|
303
|
+
|
|
304
|
+
def initialize
|
|
305
|
+
@logs = []
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def log(message)
|
|
309
|
+
@logs << [:log, message]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def debug(message)
|
|
313
|
+
@logs << [:debug, message]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def error(message)
|
|
317
|
+
@logs << [:error, message]
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
let(:launcher) do
|
|
322
|
+
Class.new do
|
|
323
|
+
def events
|
|
324
|
+
return @events if defined?(@events)
|
|
325
|
+
|
|
326
|
+
@events = MockPumaEvents.new
|
|
327
|
+
end
|
|
328
|
+
end.new
|
|
329
|
+
end
|
|
330
|
+
let(:stats_data) { { :max_threads => 5 } }
|
|
331
|
+
|
|
332
|
+
it "logs messages to the events class" do
|
|
333
|
+
run_plugin(appsignal_plugin) do
|
|
334
|
+
expect(launcher.events.logs).to_not be_empty
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
end
|
|
299
338
|
end
|
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.5
|
|
5
5
|
platform: java
|
|
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-
|
|
13
|
+
date: 2022-10-18 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rack
|
|
@@ -218,7 +218,7 @@ files:
|
|
|
218
218
|
- lib/appsignal/event_formatter/sequel/sql_formatter.rb
|
|
219
219
|
- lib/appsignal/extension.rb
|
|
220
220
|
- lib/appsignal/extension/jruby.rb
|
|
221
|
-
- lib/appsignal/
|
|
221
|
+
- lib/appsignal/garbage_collection.rb
|
|
222
222
|
- lib/appsignal/helpers/instrumentation.rb
|
|
223
223
|
- lib/appsignal/helpers/metrics.rb
|
|
224
224
|
- lib/appsignal/hooks.rb
|
|
@@ -319,7 +319,7 @@ files:
|
|
|
319
319
|
- spec/lib/appsignal/extension/jruby_spec.rb
|
|
320
320
|
- spec/lib/appsignal/extension_install_failure_spec.rb
|
|
321
321
|
- spec/lib/appsignal/extension_spec.rb
|
|
322
|
-
- spec/lib/appsignal/
|
|
322
|
+
- spec/lib/appsignal/garbage_collection_spec.rb
|
|
323
323
|
- spec/lib/appsignal/hooks/action_cable_spec.rb
|
|
324
324
|
- spec/lib/appsignal/hooks/action_mailer_spec.rb
|
|
325
325
|
- spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb
|
|
@@ -441,7 +441,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
441
441
|
- !ruby/object:Gem::Version
|
|
442
442
|
version: '0'
|
|
443
443
|
requirements: []
|
|
444
|
-
rubygems_version: 3.3.
|
|
444
|
+
rubygems_version: 3.3.7
|
|
445
445
|
signing_key:
|
|
446
446
|
specification_version: 4
|
|
447
447
|
summary: Logs performance and exception data from your app to appsignal.com
|
|
@@ -471,7 +471,7 @@ test_files:
|
|
|
471
471
|
- spec/lib/appsignal/extension/jruby_spec.rb
|
|
472
472
|
- spec/lib/appsignal/extension_install_failure_spec.rb
|
|
473
473
|
- spec/lib/appsignal/extension_spec.rb
|
|
474
|
-
- spec/lib/appsignal/
|
|
474
|
+
- spec/lib/appsignal/garbage_collection_spec.rb
|
|
475
475
|
- spec/lib/appsignal/hooks/action_cable_spec.rb
|
|
476
476
|
- spec/lib/appsignal/hooks/action_mailer_spec.rb
|
|
477
477
|
- 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
|