appsignal 3.0.4.alpha.1-java → 3.0.8-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 +50 -24
- data/README.md +9 -3
- data/appsignal.gemspec +1 -1
- data/ext/agent.yml +19 -19
- data/ext/base.rb +19 -6
- data/lib/appsignal/cli/diagnose.rb +2 -1
- data/lib/appsignal/config.rb +1 -0
- data/lib/appsignal/hooks.rb +2 -1
- data/lib/appsignal/hooks/excon.rb +19 -0
- data/lib/appsignal/hooks/puma.rb +1 -16
- data/lib/appsignal/integrations/excon.rb +20 -0
- data/lib/appsignal/integrations/padrino.rb +1 -1
- data/lib/appsignal/integrations/railtie.rb +1 -1
- data/lib/appsignal/integrations/redis.rb +8 -5
- data/lib/appsignal/integrations/sinatra.rb +1 -1
- data/lib/appsignal/probes.rb +0 -1
- data/lib/appsignal/system.rb +30 -3
- data/lib/appsignal/version.rb +1 -1
- data/lib/puma/plugin/appsignal.rb +146 -17
- data/mono.yml +16 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +5 -2
- data/spec/lib/appsignal/hooks/excon_spec.rb +74 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +0 -46
- data/spec/lib/appsignal/hooks/redis_spec.rb +34 -10
- data/spec/lib/appsignal/hooks_spec.rb +4 -1
- data/spec/lib/appsignal/system_spec.rb +30 -0
- data/spec/lib/puma/appsignal_spec.rb +246 -66
- data/spec/support/helpers/wait_for_helper.rb +16 -4
- metadata +10 -8
- data/lib/appsignal/probes/puma.rb +0 -61
- data/spec/lib/appsignal/probes/puma_spec.rb +0 -180
|
@@ -33,16 +33,17 @@ describe Appsignal::Hooks::RedisHook do
|
|
|
33
33
|
|
|
34
34
|
context "instrumentation" do
|
|
35
35
|
before do
|
|
36
|
+
start_agent
|
|
36
37
|
# Stub Redis::Client class so that it doesn't perform an actual
|
|
37
38
|
# Redis query. This class will be included (prepended) with the
|
|
38
39
|
# AppSignal Redis integration.
|
|
39
40
|
stub_const("Redis::Client", Class.new do
|
|
40
41
|
def id
|
|
41
|
-
|
|
42
|
+
"stub_id"
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
def
|
|
45
|
-
|
|
45
|
+
def write(_commands)
|
|
46
|
+
"stub_write"
|
|
46
47
|
end
|
|
47
48
|
end)
|
|
48
49
|
# Load the integration again for the stubbed Redis::Client class.
|
|
@@ -50,17 +51,40 @@ describe Appsignal::Hooks::RedisHook do
|
|
|
50
51
|
# track if it was installed already or not.
|
|
51
52
|
Appsignal::Hooks::RedisHook.new.install
|
|
52
53
|
end
|
|
54
|
+
let!(:transaction) do
|
|
55
|
+
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
|
56
|
+
end
|
|
57
|
+
around { |example| keep_transactions { example.run } }
|
|
53
58
|
|
|
54
59
|
it "instrument a redis call" do
|
|
55
|
-
|
|
56
|
-
expect(
|
|
57
|
-
.at_least(:once)
|
|
58
|
-
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
|
59
|
-
.at_least(:once)
|
|
60
|
-
.with("query.redis", :stub_id, "get ?", 0)
|
|
60
|
+
client = Redis::Client.new
|
|
61
|
+
expect(client.write([:get, "key"])).to eql("stub_write")
|
|
61
62
|
|
|
63
|
+
transaction_hash = transaction.to_h
|
|
64
|
+
expect(transaction_hash["events"]).to include(
|
|
65
|
+
hash_including(
|
|
66
|
+
"name" => "query.redis",
|
|
67
|
+
"body" => "get ?",
|
|
68
|
+
"title" => "stub_id"
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "instrument a redis script call" do
|
|
62
74
|
client = Redis::Client.new
|
|
63
|
-
|
|
75
|
+
script = "return redis.call('set',KEYS[1],ARGV[1])"
|
|
76
|
+
keys = ["foo"]
|
|
77
|
+
argv = ["bar"]
|
|
78
|
+
expect(client.write([:eval, script, keys.size, keys, argv])).to eql("stub_write")
|
|
79
|
+
|
|
80
|
+
transaction_hash = transaction.to_h
|
|
81
|
+
expect(transaction_hash["events"]).to include(
|
|
82
|
+
hash_including(
|
|
83
|
+
"name" => "query.redis",
|
|
84
|
+
"body" => "#{script} ? ?",
|
|
85
|
+
"title" => "stub_id"
|
|
86
|
+
)
|
|
87
|
+
)
|
|
64
88
|
end
|
|
65
89
|
end
|
|
66
90
|
end
|
|
@@ -68,7 +68,10 @@ describe Appsignal::Hooks do
|
|
|
68
68
|
expect(Appsignal::Hooks.hooks[:mock_error_hook].installed?).to be_falsy
|
|
69
69
|
|
|
70
70
|
expect(Appsignal.logger).to receive(:error).with("Error while installing mock_error_hook hook: error").once
|
|
71
|
-
expect(Appsignal.logger).to receive(:debug).
|
|
71
|
+
expect(Appsignal.logger).to receive(:debug).ordered do |message|
|
|
72
|
+
expect(message).to eq("Installing mock_error_hook hook")
|
|
73
|
+
end
|
|
74
|
+
expect(Appsignal.logger).to receive(:debug).ordered do |message|
|
|
72
75
|
# Start of the error backtrace as debug log
|
|
73
76
|
expect(message).to start_with(File.expand_path("../../../../", __FILE__))
|
|
74
77
|
end
|
|
@@ -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
|
|
@@ -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
|