appsignal 3.1.5 → 3.1.6
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 +6 -0
- data/lib/appsignal/probes/sidekiq.rb +46 -5
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +212 -106
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a3a10bbc00539eeb5809a449c341151d7fdd87bdeb81c85e9a7778ef4b49857
|
4
|
+
data.tar.gz: a5e646a6124dd3a9173d3a30ec19463076a50b96e8b4320ef54c909fdc2aad22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0038a47accbfd1d2f69bb7c9b1db650bb974d416674285afddf2570e9ea19bd9958dfeb3b24d8f950f058af0a9d63ba212920e632ea5dbb5a2ece55b237e1fe
|
7
|
+
data.tar.gz: 3761cf3f55137ac16e63a740d917e0f83a75d8d72ad93cbd52aa1de09a61bd3631dc8e6f537ada82d36c7e8a0395b1e05f5d76084508dd00169a2ef67c77a83d
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
2
2
|
|
3
|
+
## 3.1.6
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
|
7
|
+
- [a03b7246](https://github.com/appsignal/appsignal-ruby/commit/a03b72461f5f3b047ca81368cf2bdbeadf078e08) patch - Support Sidekiq 7 in the Sidekiq minutely probe. It will now report metrics to Sidekiq magic dashboard for Sidekiq version 7 and newer.
|
8
|
+
|
3
9
|
## 3.1.5
|
4
10
|
|
5
11
|
### Changed
|
@@ -3,17 +3,59 @@ module Appsignal
|
|
3
3
|
class SidekiqProbe
|
4
4
|
include Helpers
|
5
5
|
|
6
|
+
class Sidekiq7Adapter
|
7
|
+
def self.redis_info
|
8
|
+
redis_info = nil
|
9
|
+
::Sidekiq.redis { |c| redis_info = c.info }
|
10
|
+
redis_info
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.hostname
|
14
|
+
host = nil
|
15
|
+
::Sidekiq.redis do |c|
|
16
|
+
host = c.config.host
|
17
|
+
end
|
18
|
+
host
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Sidekiq6Adapter
|
23
|
+
def self.redis_info
|
24
|
+
return unless ::Sidekiq.respond_to?(:redis_info)
|
25
|
+
|
26
|
+
::Sidekiq.redis_info
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.hostname
|
30
|
+
host = nil
|
31
|
+
::Sidekiq.redis do |c|
|
32
|
+
host = c.connection[:host] if c.respond_to? :connection
|
33
|
+
end
|
34
|
+
host
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
6
38
|
# @api private
|
7
39
|
attr_reader :config
|
8
40
|
|
41
|
+
def self.sidekiq7_and_greater?
|
42
|
+
Gem::Version.new(::Sidekiq::VERSION) >= Gem::Version.new("7.0.0")
|
43
|
+
end
|
44
|
+
|
9
45
|
# @api private
|
10
46
|
def self.dependencies_present?
|
47
|
+
return true if sidekiq7_and_greater?
|
48
|
+
return unless defined?(::Redis::VERSION) # Sidekiq <= 6
|
49
|
+
|
11
50
|
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
|
12
51
|
end
|
13
52
|
|
14
53
|
def initialize(config = {})
|
15
54
|
@config = config
|
16
55
|
@cache = {}
|
56
|
+
is_sidekiq7 = self.class.sidekiq7_and_greater?
|
57
|
+
@adapter = is_sidekiq7 ? Sidekiq7Adapter : Sidekiq6Adapter
|
58
|
+
|
17
59
|
config_string = " with config: #{config}" unless config.empty?
|
18
60
|
Appsignal.logger.debug("Initializing Sidekiq probe#{config_string}")
|
19
61
|
require "sidekiq/api"
|
@@ -28,11 +70,11 @@ module Appsignal
|
|
28
70
|
|
29
71
|
private
|
30
72
|
|
31
|
-
attr_reader :cache
|
73
|
+
attr_reader :adapter, :cache
|
32
74
|
|
33
75
|
def track_redis_info
|
34
|
-
|
35
|
-
|
76
|
+
redis_info = adapter.redis_info
|
77
|
+
return unless redis_info
|
36
78
|
|
37
79
|
gauge "connection_count", redis_info.fetch("connected_clients")
|
38
80
|
gauge "memory_usage", redis_info.fetch("used_memory")
|
@@ -81,8 +123,7 @@ module Appsignal
|
|
81
123
|
return @hostname
|
82
124
|
end
|
83
125
|
|
84
|
-
host =
|
85
|
-
::Sidekiq.redis { |c| host = c.connection[:host] }
|
126
|
+
host = adapter.hostname
|
86
127
|
Appsignal.logger.debug "Sidekiq probe: Using Redis server hostname " \
|
87
128
|
"#{host.inspect} as hostname"
|
88
129
|
@hostname = host
|
data/lib/appsignal/version.rb
CHANGED
@@ -7,114 +7,177 @@ describe Appsignal::Probes::SidekiqProbe do
|
|
7
7
|
let(:expected_default_tags) { { :hostname => "localhost" } }
|
8
8
|
before do
|
9
9
|
Appsignal.config = project_fixture_config
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
|
11
|
+
class SidekiqStats
|
12
|
+
class << self
|
13
|
+
attr_reader :calls
|
14
|
+
|
15
|
+
def count_call
|
16
|
+
@calls ||= -1
|
17
|
+
@calls += 1
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
+
def workers_size
|
22
|
+
# First method called, so count it towards a call
|
23
|
+
self.class.count_call
|
24
|
+
24
|
21
25
|
end
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
{ :host => "localhost" }
|
26
|
-
end
|
27
|
+
def processes_size
|
28
|
+
25
|
27
29
|
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
# Return two different values for two separate calls.
|
32
|
+
# This allows us to test the delta of the value send as a gauge.
|
33
|
+
def processed
|
34
|
+
[10, 15][self.class.calls]
|
35
|
+
end
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
# Return two different values for two separate calls.
|
38
|
+
# This allows us to test the delta of the value send as a gauge.
|
39
|
+
def failed
|
40
|
+
[10, 13][self.class.calls]
|
41
|
+
end
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
24
|
43
|
-
end
|
43
|
+
def retry_size
|
44
|
+
12
|
45
|
+
end
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
-
|
47
|
+
# Return two different values for two separate calls.
|
48
|
+
# This allows us to test the delta of the value send as a gauge.
|
49
|
+
def dead_size
|
50
|
+
[10, 12][self.class.calls]
|
51
|
+
end
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
[10, 15][self.class.calls]
|
53
|
-
end
|
53
|
+
def scheduled_size
|
54
|
+
14
|
55
|
+
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
57
|
+
def enqueued
|
58
|
+
15
|
59
|
+
end
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
class SidekiqQueue
|
63
|
+
Queue = Struct.new(:name, :size, :latency)
|
64
|
+
|
65
|
+
def self.all
|
66
|
+
[
|
67
|
+
Queue.new("default", 10, 12),
|
68
|
+
Queue.new("critical", 1, 2)
|
69
|
+
]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
module Sidekiq7Mock
|
74
|
+
VERSION = "7.0.0".freeze
|
75
|
+
|
76
|
+
def self.redis
|
77
|
+
yield Client.new
|
78
|
+
end
|
64
79
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
[10, 12][self.class.calls]
|
80
|
+
class Client
|
81
|
+
def config
|
82
|
+
Config.new
|
69
83
|
end
|
70
84
|
|
71
|
-
def
|
72
|
-
|
85
|
+
def info
|
86
|
+
{
|
87
|
+
"connected_clients" => 2,
|
88
|
+
"used_memory" => 1024,
|
89
|
+
"used_memory_rss" => 512
|
90
|
+
}
|
73
91
|
end
|
92
|
+
end
|
74
93
|
|
75
|
-
|
76
|
-
|
94
|
+
class Config
|
95
|
+
def host
|
96
|
+
"localhost"
|
77
97
|
end
|
78
98
|
end
|
79
99
|
|
80
|
-
|
81
|
-
|
100
|
+
Stats = ::SidekiqStats
|
101
|
+
Queue = ::SidekiqQueue
|
102
|
+
end
|
103
|
+
|
104
|
+
module Sidekiq6Mock
|
105
|
+
VERSION = "6.9.9".freeze
|
106
|
+
|
107
|
+
def self.redis_info
|
108
|
+
{
|
109
|
+
"connected_clients" => 2,
|
110
|
+
"used_memory" => 1024,
|
111
|
+
"used_memory_rss" => 512
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.redis
|
116
|
+
yield Client.new
|
117
|
+
end
|
82
118
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
Queue.new("critical", 1, 2)
|
87
|
-
]
|
119
|
+
class Client
|
120
|
+
def connection
|
121
|
+
{ :host => "localhost" }
|
88
122
|
end
|
89
123
|
end
|
124
|
+
|
125
|
+
Stats = ::SidekiqStats
|
126
|
+
Queue = ::SidekiqQueue
|
90
127
|
end
|
91
|
-
stub_const("Sidekiq", SidekiqMock)
|
92
128
|
end
|
93
|
-
after
|
129
|
+
after do
|
130
|
+
Object.send(:remove_const, :SidekiqStats)
|
131
|
+
Object.send(:remove_const, :SidekiqQueue)
|
132
|
+
Object.send(:remove_const, :Sidekiq6Mock)
|
133
|
+
Object.send(:remove_const, :Sidekiq7Mock)
|
134
|
+
end
|
135
|
+
|
136
|
+
def with_sidekiq7!
|
137
|
+
stub_const("Sidekiq", Sidekiq7Mock)
|
138
|
+
end
|
139
|
+
# Version not relevant, but requires any version for tests
|
140
|
+
alias_method :with_sidekiq!, :with_sidekiq7!
|
141
|
+
|
142
|
+
def with_sidekiq6!
|
143
|
+
stub_const("Sidekiq", Sidekiq6Mock)
|
144
|
+
end
|
94
145
|
|
95
146
|
describe ".dependencies_present?" do
|
96
|
-
|
97
|
-
|
147
|
+
context "when Sidekiq 7" do
|
148
|
+
before { with_sidekiq7! }
|
149
|
+
|
150
|
+
it "starts the probe" do
|
151
|
+
expect(described_class.dependencies_present?).to be_truthy
|
152
|
+
end
|
98
153
|
end
|
99
154
|
|
100
|
-
context "when
|
101
|
-
|
155
|
+
context "when Sidekiq 6" do
|
156
|
+
before do
|
157
|
+
with_sidekiq6!
|
158
|
+
stub_const("Redis::VERSION", version)
|
159
|
+
end
|
160
|
+
|
161
|
+
context "when Redis version is < 3.3.5" do
|
162
|
+
let(:version) { "3.3.4" }
|
102
163
|
|
103
|
-
|
104
|
-
|
164
|
+
it "does not start probe" do
|
165
|
+
expect(described_class.dependencies_present?).to be_falsy
|
166
|
+
end
|
105
167
|
end
|
106
|
-
end
|
107
168
|
|
108
|
-
|
109
|
-
|
169
|
+
context "when Redis version is >= 3.3.5" do
|
170
|
+
let(:version) { "3.3.5" }
|
110
171
|
|
111
|
-
|
112
|
-
|
172
|
+
it "starts the probe" do
|
173
|
+
expect(described_class.dependencies_present?).to be_truthy
|
174
|
+
end
|
113
175
|
end
|
114
176
|
end
|
115
177
|
end
|
116
178
|
|
117
179
|
it "loads Sidekiq::API" do
|
180
|
+
with_sidekiq!
|
118
181
|
# Hide the Sidekiq constant if it was already loaded. It will be
|
119
182
|
# redefined by loading "sidekiq/api" in the probe.
|
120
183
|
hide_const "Sidekiq::Stats"
|
@@ -125,53 +188,94 @@ describe Appsignal::Probes::SidekiqProbe do
|
|
125
188
|
end
|
126
189
|
|
127
190
|
it "logs config on initialize" do
|
191
|
+
with_sidekiq!
|
128
192
|
log = capture_logs { probe }
|
129
193
|
expect(log).to contains_log(:debug, "Initializing Sidekiq probe\n")
|
130
194
|
end
|
131
195
|
|
132
|
-
|
133
|
-
|
134
|
-
expect(log).to contains_log(
|
135
|
-
:debug,
|
136
|
-
%(Sidekiq probe: Using Redis server hostname "localhost" as hostname)
|
137
|
-
)
|
138
|
-
log = capture_logs { probe.call }
|
139
|
-
# Match more logs with incompelete message
|
140
|
-
expect(log).to_not contains_log(:debug, %(Sidekiq probe: ))
|
141
|
-
end
|
196
|
+
context "with Sidekiq 7" do
|
197
|
+
before { with_sidekiq7! }
|
142
198
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
199
|
+
it "logs used hostname on call once" do
|
200
|
+
log = capture_logs { probe.call }
|
201
|
+
expect(log).to contains_log(
|
202
|
+
:debug,
|
203
|
+
%(Sidekiq probe: Using Redis server hostname "localhost" as hostname)
|
204
|
+
)
|
205
|
+
log = capture_logs { probe.call }
|
206
|
+
# Match more logs with incompelete message
|
207
|
+
expect(log).to_not contains_log(:debug, %(Sidekiq probe: ))
|
208
|
+
end
|
209
|
+
|
210
|
+
it "collects custom metrics" do
|
211
|
+
expect_gauge("worker_count", 24).twice
|
212
|
+
expect_gauge("process_count", 25).twice
|
213
|
+
expect_gauge("connection_count", 2).twice
|
214
|
+
expect_gauge("memory_usage", 1024).twice
|
215
|
+
expect_gauge("memory_usage_rss", 512).twice
|
216
|
+
expect_gauge("job_count", 5, :status => :processed) # Gauge delta
|
217
|
+
expect_gauge("job_count", 3, :status => :failed) # Gauge delta
|
218
|
+
expect_gauge("job_count", 12, :status => :retry_queue).twice
|
219
|
+
expect_gauge("job_count", 2, :status => :died) # Gauge delta
|
220
|
+
expect_gauge("job_count", 14, :status => :scheduled).twice
|
221
|
+
expect_gauge("job_count", 15, :status => :enqueued).twice
|
222
|
+
expect_gauge("queue_length", 10, :queue => "default").twice
|
223
|
+
expect_gauge("queue_latency", 12_000, :queue => "default").twice
|
224
|
+
expect_gauge("queue_length", 1, :queue => "critical").twice
|
225
|
+
expect_gauge("queue_latency", 2_000, :queue => "critical").twice
|
226
|
+
# Call probe twice so we can calculate the delta for some gauge values
|
227
|
+
probe.call
|
228
|
+
probe.call
|
229
|
+
end
|
162
230
|
end
|
163
231
|
|
164
|
-
context "
|
165
|
-
before
|
166
|
-
|
232
|
+
context "with Sidekiq 6" do
|
233
|
+
before { with_sidekiq6! }
|
234
|
+
|
235
|
+
it "logs used hostname on call once" do
|
236
|
+
log = capture_logs { probe.call }
|
237
|
+
expect(log).to contains_log(
|
238
|
+
:debug,
|
239
|
+
%(Sidekiq probe: Using Redis server hostname "localhost" as hostname)
|
240
|
+
)
|
241
|
+
log = capture_logs { probe.call }
|
242
|
+
# Match more logs with incompelete message
|
243
|
+
expect(log).to_not contains_log(:debug, %(Sidekiq probe: ))
|
167
244
|
end
|
168
245
|
|
169
|
-
it "
|
170
|
-
expect_gauge("
|
171
|
-
expect_gauge("
|
172
|
-
expect_gauge("
|
246
|
+
it "collects custom metrics" do
|
247
|
+
expect_gauge("worker_count", 24).twice
|
248
|
+
expect_gauge("process_count", 25).twice
|
249
|
+
expect_gauge("connection_count", 2).twice
|
250
|
+
expect_gauge("memory_usage", 1024).twice
|
251
|
+
expect_gauge("memory_usage_rss", 512).twice
|
252
|
+
expect_gauge("job_count", 5, :status => :processed) # Gauge delta
|
253
|
+
expect_gauge("job_count", 3, :status => :failed) # Gauge delta
|
254
|
+
expect_gauge("job_count", 12, :status => :retry_queue).twice
|
255
|
+
expect_gauge("job_count", 2, :status => :died) # Gauge delta
|
256
|
+
expect_gauge("job_count", 14, :status => :scheduled).twice
|
257
|
+
expect_gauge("job_count", 15, :status => :enqueued).twice
|
258
|
+
expect_gauge("queue_length", 10, :queue => "default").twice
|
259
|
+
expect_gauge("queue_latency", 12_000, :queue => "default").twice
|
260
|
+
expect_gauge("queue_length", 1, :queue => "critical").twice
|
261
|
+
expect_gauge("queue_latency", 2_000, :queue => "critical").twice
|
262
|
+
# Call probe twice so we can calculate the delta for some gauge values
|
263
|
+
probe.call
|
173
264
|
probe.call
|
174
265
|
end
|
266
|
+
|
267
|
+
context "when Sidekiq `redis_info` is not defined" do
|
268
|
+
before do
|
269
|
+
allow(Sidekiq).to receive(:respond_to?).with(:redis_info).and_return(false)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "does not collect redis metrics" do
|
273
|
+
expect_gauge("connection_count", 2).never
|
274
|
+
expect_gauge("memory_usage", 1024).never
|
275
|
+
expect_gauge("memory_usage_rss", 512).never
|
276
|
+
probe.call
|
277
|
+
end
|
278
|
+
end
|
175
279
|
end
|
176
280
|
|
177
281
|
context "when hostname is configured for probe" do
|
@@ -179,6 +283,8 @@ describe Appsignal::Probes::SidekiqProbe do
|
|
179
283
|
let(:probe) { described_class.new(:hostname => redis_hostname) }
|
180
284
|
|
181
285
|
it "uses the redis hostname for the hostname tag" do
|
286
|
+
with_sidekiq!
|
287
|
+
|
182
288
|
allow(Appsignal).to receive(:set_gauge).and_call_original
|
183
289
|
log = capture_logs { probe }
|
184
290
|
expect(log).to contains_log(
|
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.6
|
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-
|
13
|
+
date: 2022-11-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|