appsignal 3.0.6-java → 3.0.10-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/.gitmodules +3 -0
- data/.rubocop.yml +2 -2
- data/.semaphore/semaphore.yml +460 -39
- data/CHANGELOG.md +23 -0
- data/README.md +22 -16
- data/Rakefile +11 -10
- data/build_matrix.yml +106 -32
- data/ext/agent.yml +24 -17
- data/ext/base.rb +7 -5
- data/lib/appsignal/cli/diagnose.rb +10 -5
- data/lib/appsignal/config.rb +1 -0
- data/lib/appsignal/hooks/puma.rb +1 -16
- data/lib/appsignal/probes.rb +0 -1
- data/lib/appsignal/system.rb +30 -3
- data/lib/appsignal/transaction.rb +1 -1
- data/lib/appsignal/version.rb +1 -1
- data/lib/puma/plugin/appsignal.rb +146 -17
- data/script/install_lintje +18 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +4 -2
- data/spec/lib/appsignal/hooks/puma_spec.rb +0 -46
- data/spec/lib/appsignal/system_spec.rb +30 -0
- data/spec/lib/appsignal/transaction_spec.rb +7 -0
- data/spec/lib/puma/appsignal_spec.rb +246 -66
- data/spec/support/helpers/wait_for_helper.rb +16 -4
- metadata +4 -5
- data/lib/appsignal/probes/puma.rb +0 -61
- data/spec/lib/appsignal/probes/puma_spec.rb +0 -180
@@ -43,6 +43,14 @@ describe Appsignal::System do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
context "when using the APPSIGNAL_BUILD_FOR_LINUX_ARM env var" do
|
47
|
+
it "returns the linux build" do
|
48
|
+
ENV["APPSIGNAL_BUILD_FOR_LINUX_ARM"] = "1"
|
49
|
+
is_expected.to eq("linux")
|
50
|
+
ENV.delete("APPSIGNAL_BUILD_FOR_LINUX_ARM")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
46
54
|
context "when on a musl system" do
|
47
55
|
let(:ldd_output) { "musl libc (x86_64)\nVersion 1.1.16" }
|
48
56
|
|
@@ -93,4 +101,26 @@ describe Appsignal::System do
|
|
93
101
|
end
|
94
102
|
end
|
95
103
|
end
|
104
|
+
|
105
|
+
describe ".agent_architecture" do
|
106
|
+
let(:architecture) { "x86_64" }
|
107
|
+
let(:ldd_output) { "" }
|
108
|
+
before do
|
109
|
+
allow(RbConfig::CONFIG).to receive(:[])
|
110
|
+
allow(RbConfig::CONFIG).to receive(:[]).with("host_cpu").and_return(architecture)
|
111
|
+
end
|
112
|
+
subject { described_class.agent_architecture }
|
113
|
+
|
114
|
+
it "returns the host CPU value" do
|
115
|
+
is_expected.to eq(architecture)
|
116
|
+
end
|
117
|
+
|
118
|
+
context "when using the APPSIGNAL_BUILD_FOR_LINUX_ARM env var" do
|
119
|
+
it "returns ARM 64 bit" do
|
120
|
+
ENV["APPSIGNAL_BUILD_FOR_LINUX_ARM"] = "1"
|
121
|
+
is_expected.to eq("aarch64")
|
122
|
+
ENV.delete("APPSIGNAL_BUILD_FOR_LINUX_ARM")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
96
126
|
end
|
@@ -1321,6 +1321,13 @@ describe Appsignal::Transaction do
|
|
1321
1321
|
expect(subject).to eq ["line 1", "line 2"]
|
1322
1322
|
end
|
1323
1323
|
|
1324
|
+
context "with Rails module but without backtrace_cleaner method" do
|
1325
|
+
it "returns the backtrace uncleaned" do
|
1326
|
+
stub_const("Rails", Module.new)
|
1327
|
+
expect(subject).to eq ["line 1", "line 2"]
|
1328
|
+
end
|
1329
|
+
end
|
1330
|
+
|
1324
1331
|
if rails_present?
|
1325
1332
|
context "with rails" do
|
1326
1333
|
it "cleans the backtrace with the Rails backtrace cleaner" do
|
@@ -10,110 +10,290 @@ RSpec.describe "Puma plugin" do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class MockPumaEvents
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
attr_reader :logs
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@logs = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def log(message)
|
20
|
+
@logs << [:log, message]
|
21
|
+
end
|
22
|
+
|
23
|
+
def debug(message)
|
24
|
+
@logs << [:debug, message]
|
25
|
+
end
|
26
|
+
|
27
|
+
def error(message)
|
28
|
+
@logs << [:error, message]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# StatsD server used for these tests.
|
33
|
+
# Open a UDPSocket and listen for messages sent by the AppSignal Puma plugin.
|
34
|
+
class StatsdServer
|
35
|
+
def start
|
36
|
+
stop
|
37
|
+
@socket = UDPSocket.new
|
38
|
+
@socket.bind("127.0.0.1", 8125)
|
39
|
+
|
40
|
+
loop do
|
41
|
+
begin
|
42
|
+
# Listen for messages and track them on the messages Array.
|
43
|
+
packet = @socket.recvfrom(1024)
|
44
|
+
track_message packet.first
|
45
|
+
rescue Errno::EBADF # rubocop:disable Lint/HandleExceptions
|
46
|
+
# Ignore error for JRuby 9.1.17.0 specifically, it doesn't appear to
|
47
|
+
# happen on 9.2.18.0. It doesn't break the tests themselves, ignoring
|
48
|
+
# this error. It's probably a timing issue where it tries to read
|
49
|
+
# from the socket after it's closed.
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop
|
55
|
+
defined?(@socket) && @socket && @socket.close
|
56
|
+
ensure
|
57
|
+
@socket = nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def messages
|
61
|
+
@messages ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def track_message(message)
|
67
|
+
@messages_mutex ||= Mutex.new
|
68
|
+
@messages_mutex.synchronize { messages << message }
|
16
69
|
end
|
17
70
|
end
|
18
71
|
|
19
72
|
let(:probe) { MockProbe.new }
|
20
73
|
let(:launcher) { MockPumaLauncher.new }
|
74
|
+
let(:hostname) { Socket.gethostname }
|
75
|
+
let(:expected_default_tags) { { "hostname" => hostname } }
|
76
|
+
let(:stats_data) { { :backlog => 1 } }
|
77
|
+
before :context do
|
78
|
+
Appsignal.stop
|
79
|
+
end
|
21
80
|
before do
|
22
81
|
module Puma
|
23
82
|
def self.stats
|
83
|
+
JSON.dump(@_stats_data)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.stats_hash
|
87
|
+
@_stats_data
|
24
88
|
end
|
25
89
|
|
26
|
-
def self.
|
27
|
-
|
28
|
-
before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
29
|
-
|
30
|
-
# An abbreviated version of what happens in Puma::Cluster#run
|
31
|
-
launcher = MockPumaLauncher.new
|
32
|
-
plugin = Plugin.plugin.new
|
33
|
-
plugin.start(launcher)
|
34
|
-
launcher.events.on_booted.call
|
35
|
-
|
36
|
-
# Wait for minutely probe thread to finish starting
|
37
|
-
sleep 0.005
|
38
|
-
|
39
|
-
# Capture any new threads running after application is preloaded.
|
40
|
-
# Any threads created during the preloading phase will not be
|
41
|
-
# carried over into the forked workers. Puma warns about these
|
42
|
-
# but the minutely probe thread should only exist in the main process.
|
43
|
-
after = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
44
|
-
$stdout.puts "! WARNING: Detected #{after.size - before.size} Thread(s) started in app boot" if after.size > before.size
|
90
|
+
def self._set_stats=(data)
|
91
|
+
@_stats_data = data
|
45
92
|
end
|
46
93
|
|
47
94
|
class Plugin
|
48
95
|
class << self
|
49
|
-
attr_reader :
|
96
|
+
attr_reader :appsignal_plugin
|
50
97
|
|
51
98
|
def create(&block)
|
52
|
-
@
|
53
|
-
@
|
99
|
+
@appsignal_plugin = Class.new(::Puma::Plugin)
|
100
|
+
@appsignal_plugin.class_eval(&block)
|
54
101
|
end
|
55
102
|
end
|
56
|
-
end
|
57
|
-
end
|
58
103
|
|
59
|
-
|
60
|
-
ENV["APPSIGNAL_ENABLE_MINUTELY_PROBES"] = "true"
|
61
|
-
Appsignal.config = project_fixture_config
|
62
|
-
# Speed up test time
|
63
|
-
allow(Appsignal::Minutely).to receive(:initial_wait_time).and_return(0.001)
|
64
|
-
allow(Appsignal::Minutely).to receive(:wait_time).and_return(0.001)
|
104
|
+
attr_reader :in_background_block
|
65
105
|
|
66
|
-
|
106
|
+
def in_background(&block)
|
107
|
+
@in_background_block = block
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
Puma._set_stats = stats_data
|
67
112
|
load File.expand_path("../lib/puma/plugin/appsignal.rb", APPSIGNAL_SPEC_DIR)
|
113
|
+
|
114
|
+
@statsd = StatsdServer.new
|
115
|
+
@server_thread = Thread.new { @statsd.start }
|
116
|
+
@server_thread.abort_on_exception = true
|
68
117
|
end
|
69
118
|
after do
|
70
|
-
|
71
|
-
|
72
|
-
Object.send
|
119
|
+
@statsd = nil
|
120
|
+
|
121
|
+
Object.send(:remove_const, :Puma)
|
122
|
+
Object.send(:remove_const, :AppsignalPumaPlugin)
|
123
|
+
end
|
124
|
+
|
125
|
+
def run_plugin(plugin, &block)
|
126
|
+
@client_thread = Thread.new { start_plugin(plugin) }
|
127
|
+
@client_thread.abort_on_exception = true
|
128
|
+
wait_for(:puma_client_wait, &block)
|
129
|
+
ensure
|
130
|
+
stop_all
|
73
131
|
end
|
74
132
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
plugin = Puma::Plugin.plugin.new
|
79
|
-
expect(launcher.events.on_booted).to be_nil
|
133
|
+
def appsignal_plugin
|
134
|
+
Puma::Plugin.appsignal_plugin
|
135
|
+
end
|
80
136
|
|
137
|
+
def start_plugin(plugin_class)
|
138
|
+
plugin = plugin_class.new
|
139
|
+
# Speed up test by not waiting for 60 seconds initial wait time and loop
|
140
|
+
# interval.
|
141
|
+
allow(plugin).to receive(:sleep_time).and_return(0.01)
|
81
142
|
plugin.start(launcher)
|
82
|
-
|
83
|
-
|
143
|
+
plugin.in_background_block.call
|
144
|
+
end
|
145
|
+
|
146
|
+
# Stop all threads in test and stop listening on the UDPSocket
|
147
|
+
def stop_all
|
148
|
+
@client_thread.kill if defined?(@client_thread) && @client_thread
|
149
|
+
@server_thread.kill if defined?(@server_thread) && @server_thread
|
150
|
+
@statsd.stop if defined?(@statsd) && @statsd
|
151
|
+
@client_thread = nil
|
152
|
+
@server_thread = nil
|
153
|
+
end
|
154
|
+
|
155
|
+
def logs
|
156
|
+
launcher.events.logs
|
157
|
+
end
|
158
|
+
|
159
|
+
def messages
|
160
|
+
@statsd.messages.map do |message|
|
161
|
+
metric, type, tags_string = message.split("|")
|
162
|
+
metric_name, metric_value = metric.split(":")
|
163
|
+
tags = {}
|
164
|
+
tags_string[1..-1].split(",").each do |tag|
|
165
|
+
key, value = tag.split(":")
|
166
|
+
tags[key] = value
|
167
|
+
end
|
168
|
+
{
|
169
|
+
:name => metric_name,
|
170
|
+
:value => metric_value.to_i,
|
171
|
+
:type => type,
|
172
|
+
:tags => tags
|
173
|
+
}
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def expect_gauge(metric_name, metric_value, tags_hash = {})
|
178
|
+
expect(messages).to include(
|
179
|
+
:name => "puma_#{metric_name}",
|
180
|
+
:value => metric_value,
|
181
|
+
:type => "g",
|
182
|
+
:tags => expected_default_tags.merge(tags_hash)
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
context "with multiple worker stats" do
|
187
|
+
let(:stats_data) do
|
188
|
+
{
|
189
|
+
:workers => 2,
|
190
|
+
:booted_workers => 2,
|
191
|
+
:old_workers => 0,
|
192
|
+
:worker_status => [
|
193
|
+
{
|
194
|
+
:last_status => {
|
195
|
+
:backlog => 0,
|
196
|
+
:running => 5,
|
197
|
+
:pool_capacity => 5,
|
198
|
+
:max_threads => 5
|
199
|
+
}
|
200
|
+
},
|
201
|
+
{
|
202
|
+
:last_status => {
|
203
|
+
:backlog => 0,
|
204
|
+
:running => 5,
|
205
|
+
:pool_capacity => 5,
|
206
|
+
:max_threads => 5
|
207
|
+
}
|
208
|
+
}
|
209
|
+
]
|
210
|
+
}
|
211
|
+
end
|
212
|
+
|
213
|
+
it "collects puma stats as guage metrics with the (summed) worker metrics" do
|
214
|
+
run_plugin(appsignal_plugin) do
|
215
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
216
|
+
expect_gauge(:workers, 2, "type" => "count")
|
217
|
+
expect_gauge(:workers, 2, "type" => "booted")
|
218
|
+
expect_gauge(:workers, 0, "type" => "old")
|
219
|
+
expect_gauge(:connection_backlog, 0)
|
220
|
+
expect_gauge(:pool_capacity, 10)
|
221
|
+
expect_gauge(:threads, 10, "type" => "running")
|
222
|
+
expect_gauge(:threads, 10, "type" => "max")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
84
226
|
|
85
|
-
|
86
|
-
|
227
|
+
context "with single worker stats" do
|
228
|
+
let(:stats_data) do
|
229
|
+
{
|
230
|
+
:backlog => 0,
|
231
|
+
:running => 5,
|
232
|
+
:pool_capacity => 5,
|
233
|
+
:max_threads => 5
|
234
|
+
}
|
235
|
+
end
|
87
236
|
|
88
|
-
|
89
|
-
|
237
|
+
it "calls `puma_gauge` with the (summed) worker metrics" do
|
238
|
+
run_plugin(appsignal_plugin) do
|
239
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
240
|
+
expect_gauge(:connection_backlog, 0)
|
241
|
+
expect_gauge(:pool_capacity, 5)
|
242
|
+
expect_gauge(:threads, 5, "type" => "running")
|
243
|
+
expect_gauge(:threads, 5, "type" => "max")
|
244
|
+
end
|
245
|
+
end
|
90
246
|
end
|
91
247
|
|
92
|
-
|
93
|
-
|
94
|
-
|
248
|
+
context "when using APPSIGNAL_HOSTNAME" do
|
249
|
+
let(:hostname) { "my-host-name" }
|
250
|
+
before { ENV["APPSIGNAL_HOSTNAME"] = hostname }
|
251
|
+
after { ENV.delete("APPSIGNAL_HOSTNAME") }
|
95
252
|
|
96
|
-
|
253
|
+
it "reports the APPSIGNAL_HOSTNAME as the hostname tag value" do
|
254
|
+
run_plugin(appsignal_plugin) do
|
255
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
256
|
+
expect_gauge(:connection_backlog, 1)
|
257
|
+
end
|
258
|
+
end
|
97
259
|
end
|
98
260
|
|
99
|
-
context "without Puma.
|
100
|
-
before
|
261
|
+
context "without Puma.stats_hash" do
|
262
|
+
before do
|
263
|
+
Puma.singleton_class.send(:remove_method, :stats_hash)
|
264
|
+
end
|
101
265
|
|
102
|
-
it "
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
266
|
+
it "fetches metrics from Puma.stats instead" do
|
267
|
+
run_plugin(appsignal_plugin) do
|
268
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
269
|
+
expect(logs).to_not include([kind_of(Symbol), "AppSignal: No Puma stats to report."])
|
270
|
+
expect_gauge(:connection_backlog, 1)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
107
274
|
|
108
|
-
|
109
|
-
|
110
|
-
|
275
|
+
context "without Puma.stats and Puma.stats_hash" do
|
276
|
+
before do
|
277
|
+
Puma.singleton_class.send(:remove_method, :stats)
|
278
|
+
Puma.singleton_class.send(:remove_method, :stats_hash)
|
279
|
+
end
|
111
280
|
|
112
|
-
|
113
|
-
|
281
|
+
it "does not fetch metrics" do
|
282
|
+
run_plugin(appsignal_plugin) do
|
283
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
284
|
+
expect(logs).to include([:log, "AppSignal: No Puma stats to report."])
|
285
|
+
expect(messages).to be_empty
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
114
289
|
|
115
|
-
|
116
|
-
|
290
|
+
context "without running StatsD server" do
|
291
|
+
it "does nothing" do
|
292
|
+
stop_all
|
293
|
+
run_plugin(appsignal_plugin) do
|
294
|
+
expect(logs).to_not include([:error, kind_of(String)])
|
295
|
+
expect(messages).to be_empty
|
296
|
+
end
|
117
297
|
end
|
118
298
|
end
|
119
299
|
end
|
@@ -16,13 +16,25 @@ module WaitForHelper
|
|
16
16
|
def wait_for(name)
|
17
17
|
max_wait = 5_000
|
18
18
|
i = 0
|
19
|
+
error = nil
|
19
20
|
while i < max_wait
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
begin
|
22
|
+
result = yield
|
23
|
+
break if result
|
24
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
25
|
+
# Capture error so we know if it exited with an error
|
26
|
+
error = e
|
27
|
+
ensure
|
28
|
+
i += 1
|
29
|
+
sleep 0.001
|
30
|
+
end
|
23
31
|
end
|
24
32
|
|
25
33
|
return unless i >= max_wait
|
26
|
-
|
34
|
+
error_message =
|
35
|
+
if error
|
36
|
+
"\nError: #{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
|
37
|
+
end
|
38
|
+
raise "Waited 5 seconds for #{name} condition, but was not met.#{error_message}"
|
27
39
|
end
|
28
40
|
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.0.
|
4
|
+
version: 3.0.10
|
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: 2021-
|
13
|
+
date: 2021-07-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rack
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
151
151
|
- ".github/ISSUE_TEMPLATE/chore.md"
|
152
152
|
- ".gitignore"
|
153
|
+
- ".gitmodules"
|
153
154
|
- ".rspec"
|
154
155
|
- ".rubocop.yml"
|
155
156
|
- ".rubocop_todo.yml"
|
@@ -263,7 +264,6 @@ files:
|
|
263
264
|
- lib/appsignal/marker.rb
|
264
265
|
- lib/appsignal/minutely.rb
|
265
266
|
- lib/appsignal/probes.rb
|
266
|
-
- lib/appsignal/probes/puma.rb
|
267
267
|
- lib/appsignal/probes/sidekiq.rb
|
268
268
|
- lib/appsignal/rack/generic_instrumentation.rb
|
269
269
|
- lib/appsignal/rack/rails_instrumentation.rb
|
@@ -285,6 +285,7 @@ files:
|
|
285
285
|
- mono.yml
|
286
286
|
- resources/appsignal.yml.erb
|
287
287
|
- resources/cacert.pem
|
288
|
+
- script/install_lintje
|
288
289
|
- spec/.rubocop.yml
|
289
290
|
- spec/lib/appsignal/auth_check_spec.rb
|
290
291
|
- spec/lib/appsignal/capistrano2_spec.rb
|
@@ -349,7 +350,6 @@ files:
|
|
349
350
|
- spec/lib/appsignal/logger_spec.rb
|
350
351
|
- spec/lib/appsignal/marker_spec.rb
|
351
352
|
- spec/lib/appsignal/minutely_spec.rb
|
352
|
-
- spec/lib/appsignal/probes/puma_spec.rb
|
353
353
|
- spec/lib/appsignal/probes/sidekiq_spec.rb
|
354
354
|
- spec/lib/appsignal/rack/generic_instrumentation_spec.rb
|
355
355
|
- spec/lib/appsignal/rack/rails_instrumentation_spec.rb
|
@@ -498,7 +498,6 @@ test_files:
|
|
498
498
|
- spec/lib/appsignal/logger_spec.rb
|
499
499
|
- spec/lib/appsignal/marker_spec.rb
|
500
500
|
- spec/lib/appsignal/minutely_spec.rb
|
501
|
-
- spec/lib/appsignal/probes/puma_spec.rb
|
502
501
|
- spec/lib/appsignal/probes/sidekiq_spec.rb
|
503
502
|
- spec/lib/appsignal/rack/generic_instrumentation_spec.rb
|
504
503
|
- spec/lib/appsignal/rack/rails_instrumentation_spec.rb
|