appsignal 2.8.0.alpha.1 → 2.8.0
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/.travis.yml +13 -14
- data/CHANGELOG.md +27 -5
- data/ext/agent.yml +38 -35
- data/ext/extconf.rb +12 -0
- data/lib/appsignal/cli.rb +3 -0
- data/lib/appsignal/cli/diagnose.rb +191 -177
- data/lib/appsignal/cli/diagnose/paths.rb +91 -0
- data/lib/appsignal/cli/diagnose/utils.rb +36 -0
- data/lib/appsignal/cli/install.rb +2 -2
- data/lib/appsignal/config.rb +71 -23
- data/lib/appsignal/event_formatter.rb +11 -5
- data/lib/appsignal/garbage_collection_profiler.rb +11 -0
- data/lib/appsignal/system.rb +6 -4
- data/lib/appsignal/transaction.rb +2 -1
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/utils/deprecation_message.rb +10 -0
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +37 -0
- data/spec/lib/appsignal/cli/diagnose_spec.rb +498 -278
- data/spec/lib/appsignal/config_spec.rb +93 -36
- data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +1 -1
- data/spec/lib/appsignal/event_formatter_spec.rb +12 -7
- data/spec/lib/appsignal/extension_spec.rb +5 -2
- data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +10 -0
- data/spec/lib/appsignal/system_spec.rb +1 -1
- data/spec/lib/appsignal/transaction_spec.rb +24 -7
- data/spec/support/helpers/std_streams_helper.rb +31 -8
- metadata +9 -4
@@ -1,28 +1,39 @@
|
|
1
1
|
describe Appsignal::Config do
|
2
2
|
describe "#initialize" do
|
3
|
-
subject { config.env }
|
4
|
-
|
5
3
|
describe "environment" do
|
6
4
|
context "when environment is nil" do
|
7
|
-
let(:config) { described_class.new("",
|
5
|
+
let(:config) { described_class.new("", nil) }
|
8
6
|
|
9
7
|
it "sets an empty string" do
|
10
|
-
expect(
|
8
|
+
expect(config.env).to eq("")
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
14
12
|
context "when environment is given" do
|
13
|
+
let(:env) { "my_env" }
|
15
14
|
let(:config) { described_class.new("", "my_env") }
|
16
15
|
|
17
16
|
it "sets the environment" do
|
18
|
-
expect(
|
17
|
+
expect(config.env).to eq(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sets the environment as loaded through the initial_config" do
|
21
|
+
expect(config.initial_config).to eq(:env => env)
|
22
|
+
expect(config.config_hash).to_not have_key(:env)
|
19
23
|
end
|
20
24
|
|
21
25
|
context "with APPSIGNAL_APP_ENV environment variable" do
|
22
|
-
|
26
|
+
let(:env_env) { "my_env_env" }
|
27
|
+
before { ENV["APPSIGNAL_APP_ENV"] = env_env }
|
23
28
|
|
24
29
|
it "uses the environment variable" do
|
25
|
-
expect(
|
30
|
+
expect(config.env).to eq(env_env)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sets the environment as loaded through the env_config" do
|
34
|
+
expect(config.initial_config).to eq(:env => env)
|
35
|
+
expect(config.env_config).to eq(:env => env_env)
|
36
|
+
expect(config.config_hash).to_not have_key(:env)
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
@@ -41,6 +52,11 @@ describe Appsignal::Config do
|
|
41
52
|
it "becomes active" do
|
42
53
|
expect(subject).to be_truthy
|
43
54
|
end
|
55
|
+
|
56
|
+
it "sets the push_api_key as loaded through the env_config" do
|
57
|
+
expect(config.env_config).to eq(:push_api_key => "abc")
|
58
|
+
expect(config.system_config).to eq(:active => true)
|
59
|
+
end
|
44
60
|
end
|
45
61
|
|
46
62
|
context "without APPSIGNAL_PUSH_API_KEY env variable" do
|
@@ -59,27 +75,36 @@ describe Appsignal::Config do
|
|
59
75
|
it "is set to stdout" do
|
60
76
|
expect(subject).to eq("stdout")
|
61
77
|
end
|
78
|
+
|
79
|
+
it "sets the log as loaded through the system" do
|
80
|
+
expect(config.system_config).to eq(:log => "stdout")
|
81
|
+
end
|
62
82
|
end
|
63
83
|
|
64
84
|
context "when not running on Heroku" do
|
65
85
|
it "is set to file" do
|
66
86
|
expect(subject).to eq("file")
|
67
87
|
end
|
88
|
+
|
89
|
+
it "does not set log as loaded through the system" do
|
90
|
+
expect(config.system_config).to eq({})
|
91
|
+
end
|
68
92
|
end
|
69
93
|
end
|
70
94
|
end
|
71
95
|
|
72
96
|
describe "initial config" do
|
73
|
-
let(:
|
74
|
-
|
75
|
-
"non-existing-path",
|
76
|
-
"production",
|
97
|
+
let(:initial_config) do
|
98
|
+
{
|
77
99
|
:push_api_key => "abc",
|
78
100
|
:name => "TestApp",
|
79
101
|
:active => true,
|
80
102
|
:revision => "v2.5.1",
|
81
103
|
:request_headers => []
|
82
|
-
|
104
|
+
}
|
105
|
+
end
|
106
|
+
let(:config) do
|
107
|
+
described_class.new("non-existing-path", "production", initial_config)
|
83
108
|
end
|
84
109
|
|
85
110
|
it "merges with the default config" do
|
@@ -114,6 +139,10 @@ describe Appsignal::Config do
|
|
114
139
|
)
|
115
140
|
end
|
116
141
|
|
142
|
+
it "sets the initial_config" do
|
143
|
+
expect(config.initial_config).to eq(initial_config)
|
144
|
+
end
|
145
|
+
|
117
146
|
describe "overriding system detected config" do
|
118
147
|
describe ":running_in_container" do
|
119
148
|
let(:config) do
|
@@ -183,6 +212,16 @@ describe Appsignal::Config do
|
|
183
212
|
config
|
184
213
|
end
|
185
214
|
|
215
|
+
it "sets the file_config" do
|
216
|
+
# config found in spec/support/project_fixture/config/appsignal.yml
|
217
|
+
expect(config.file_config).to match(
|
218
|
+
:active => true,
|
219
|
+
:push_api_key => "abc",
|
220
|
+
:name => "TestApp",
|
221
|
+
:request_headers => kind_of(Array)
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
186
225
|
describe "overriding system and defaults config" do
|
187
226
|
let(:config) do
|
188
227
|
described_class.new(
|
@@ -228,8 +267,11 @@ describe Appsignal::Config do
|
|
228
267
|
end
|
229
268
|
|
230
269
|
describe "support for old config keys" do
|
270
|
+
let(:out_stream) { std_stream }
|
271
|
+
let(:output) { out_stream.read }
|
231
272
|
let(:config) { project_fixture_config(env, {}, test_logger(log)) }
|
232
273
|
let(:log) { StringIO.new }
|
274
|
+
before { capture_stdout(out_stream) { config } }
|
233
275
|
|
234
276
|
describe ":api_key" do
|
235
277
|
context "without :push_api_key" do
|
@@ -238,8 +280,10 @@ describe Appsignal::Config do
|
|
238
280
|
it "sets the :push_api_key with the old :api_key value" do
|
239
281
|
expect(config[:push_api_key]).to eq "def"
|
240
282
|
expect(config.config_hash).to_not have_key :api_key
|
241
|
-
|
242
|
-
|
283
|
+
|
284
|
+
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
285
|
+
expect(output).to include "appsignal WARNING: #{message}"
|
286
|
+
expect(log_contents(log)).to contains_log :warn, message
|
243
287
|
end
|
244
288
|
end
|
245
289
|
|
@@ -249,8 +293,10 @@ describe Appsignal::Config do
|
|
249
293
|
it "ignores the :api_key config and deletes it" do
|
250
294
|
expect(config[:push_api_key]).to eq "ghi"
|
251
295
|
expect(config.config_hash).to_not have_key :api_key
|
252
|
-
|
253
|
-
|
296
|
+
|
297
|
+
message = "Old configuration key found. Please update the 'api_key' to 'push_api_key'"
|
298
|
+
expect(output).to include "appsignal WARNING: #{message}"
|
299
|
+
expect(log_contents(log)).to contains_log :warn, message
|
254
300
|
end
|
255
301
|
end
|
256
302
|
end
|
@@ -262,8 +308,10 @@ describe Appsignal::Config do
|
|
262
308
|
it "sets :ignore_errors with the old :ignore_exceptions value" do
|
263
309
|
expect(config[:ignore_errors]).to eq ["StandardError"]
|
264
310
|
expect(config.config_hash).to_not have_key :ignore_exceptions
|
265
|
-
|
266
|
-
|
311
|
+
|
312
|
+
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
313
|
+
expect(output).to include "appsignal WARNING: #{message}"
|
314
|
+
expect(log_contents(log)).to contains_log :warn, message
|
267
315
|
end
|
268
316
|
end
|
269
317
|
|
@@ -273,8 +321,10 @@ describe Appsignal::Config do
|
|
273
321
|
it "ignores the :ignore_exceptions config" do
|
274
322
|
expect(config[:ignore_errors]).to eq ["NoMethodError"]
|
275
323
|
expect(config.config_hash).to_not have_key :ignore_exceptions
|
276
|
-
|
277
|
-
|
324
|
+
|
325
|
+
message = "Old configuration key found. Please update the 'ignore_exceptions' to 'ignore_errors'"
|
326
|
+
expect(output).to include "appsignal WARNING: #{message}"
|
327
|
+
expect(log_contents(log)).to contains_log :warn, message
|
278
328
|
end
|
279
329
|
end
|
280
330
|
end
|
@@ -290,6 +340,24 @@ describe Appsignal::Config do
|
|
290
340
|
:debug => true
|
291
341
|
)
|
292
342
|
end
|
343
|
+
let(:env_config) do
|
344
|
+
{
|
345
|
+
:running_in_container => true,
|
346
|
+
:push_api_key => "aaa-bbb-ccc",
|
347
|
+
:active => true,
|
348
|
+
:name => "App name",
|
349
|
+
:debug => true,
|
350
|
+
:ignore_actions => %w[action1 action2],
|
351
|
+
:ignore_errors => %w[ExampleStandardError AnotherError],
|
352
|
+
:ignore_namespaces => %w[admin private_namespace],
|
353
|
+
:instrument_net_http => false,
|
354
|
+
:instrument_redis => false,
|
355
|
+
:instrument_sequel => false,
|
356
|
+
:files_world_accessible => false,
|
357
|
+
:request_headers => %w[accept accept-charset],
|
358
|
+
:revision => "v2.5.1"
|
359
|
+
}
|
360
|
+
end
|
293
361
|
before do
|
294
362
|
ENV["APPSIGNAL_RUNNING_IN_CONTAINER"] = "true"
|
295
363
|
ENV["APPSIGNAL_PUSH_API_KEY"] = "aaa-bbb-ccc"
|
@@ -310,21 +378,7 @@ describe Appsignal::Config do
|
|
310
378
|
it "overrides config with environment values" do
|
311
379
|
expect(config.valid?).to be_truthy
|
312
380
|
expect(config.active?).to be_truthy
|
313
|
-
|
314
|
-
expect(config[:running_in_container]).to be_truthy
|
315
|
-
expect(config[:push_api_key]).to eq "aaa-bbb-ccc"
|
316
|
-
expect(config[:active]).to eq(true)
|
317
|
-
expect(config[:name]).to eq "App name"
|
318
|
-
expect(config[:debug]).to eq(true)
|
319
|
-
expect(config[:ignore_actions]).to eq %w[action1 action2]
|
320
|
-
expect(config[:ignore_errors]).to eq %w[ExampleStandardError AnotherError]
|
321
|
-
expect(config[:ignore_namespaces]).to eq %w[admin private_namespace]
|
322
|
-
expect(config[:instrument_net_http]).to eq(false)
|
323
|
-
expect(config[:instrument_redis]).to eq(false)
|
324
|
-
expect(config[:instrument_sequel]).to eq(false)
|
325
|
-
expect(config[:files_world_accessible]).to eq(false)
|
326
|
-
expect(config[:request_headers]).to eq(%w[accept accept-charset])
|
327
|
-
expect(config[:revision]).to eq("v2.5.1")
|
381
|
+
expect(config.config_hash).to include(env_config)
|
328
382
|
end
|
329
383
|
|
330
384
|
context "with mixed case `true` env variables values" do
|
@@ -338,6 +392,10 @@ describe Appsignal::Config do
|
|
338
392
|
expect(config[:instrument_sequel]).to eq(true)
|
339
393
|
end
|
340
394
|
end
|
395
|
+
|
396
|
+
it "sets the env_config" do
|
397
|
+
expect(config.env_config).to eq(env_config)
|
398
|
+
end
|
341
399
|
end
|
342
400
|
|
343
401
|
describe "config keys" do
|
@@ -432,7 +490,6 @@ describe Appsignal::Config do
|
|
432
490
|
expect(ENV["_APPSIGNAL_IGNORE_ACTIONS"]).to eq "action1,action2"
|
433
491
|
expect(ENV["_APPSIGNAL_IGNORE_ERRORS"]).to eq "ExampleStandardError,AnotherError"
|
434
492
|
expect(ENV["_APPSIGNAL_IGNORE_NAMESPACES"]).to eq "admin,private_namespace"
|
435
|
-
expect(ENV["_APPSIGNAL_SEND_PARAMS"]).to eq "true"
|
436
493
|
expect(ENV["_APPSIGNAL_RUNNING_IN_CONTAINER"]).to eq "false"
|
437
494
|
expect(ENV["_APPSIGNAL_ENABLE_HOST_METRICS"]).to eq "true"
|
438
495
|
expect(ENV["_APPSIGNAL_ENABLE_MINUTELY_PROBES"]).to eq "false"
|
@@ -35,7 +35,7 @@ describe Appsignal::EventFormatter::ElasticSearch::SearchFormatter do
|
|
35
35
|
}
|
36
36
|
end
|
37
37
|
|
38
|
-
it "should sanitize non-
|
38
|
+
it "should sanitize non-allowlisted params" do
|
39
39
|
expect(
|
40
40
|
formatter.sanitized_search(search)
|
41
41
|
).to eql(:index => "users", :type => "user", :q => "?", :other => "?")
|
@@ -46,6 +46,9 @@ describe Appsignal::EventFormatter do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
context "registering and unregistering formatters" do
|
49
|
+
let(:out_stream) { std_stream }
|
50
|
+
let(:output) { out_stream.read }
|
51
|
+
|
49
52
|
it "registers a formatter" do
|
50
53
|
expect(klass.formatters["mock"]).to be_instance_of(MockFormatter)
|
51
54
|
end
|
@@ -92,19 +95,21 @@ describe Appsignal::EventFormatter do
|
|
92
95
|
end
|
93
96
|
|
94
97
|
it "does not register deprecated formatters" do
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
98
|
+
message = "Formatter for 'mock.deprecated' is using a deprecated registration method. " \
|
99
|
+
"This event formatter will not be loaded. " \
|
100
|
+
"Please update the formatter according to the documentation at: " \
|
101
|
+
"https://docs.appsignal.com/ruby/instrumentation/event-formatters.html"
|
102
|
+
expect(Appsignal.logger).to receive(:warn).with(message)
|
100
103
|
|
101
|
-
deprecated_formatter
|
104
|
+
capture_stdout(out_stream) { deprecated_formatter }
|
105
|
+
expect(output).to include "appsignal WARNING: #{message}"
|
102
106
|
|
103
107
|
expect(Appsignal::EventFormatter.deprecated_formatter_classes.keys).to include("mock.deprecated")
|
104
108
|
end
|
105
109
|
|
106
110
|
it "initializes deprecated formatters" do
|
107
|
-
|
111
|
+
# Silence deprecation warning
|
112
|
+
capture_stdout(out_stream) { deprecated_formatter }
|
108
113
|
Appsignal::EventFormatter.initialize_deprecated_formatters
|
109
114
|
|
110
115
|
expect(klass.registered?("mock.deprecated")).to be_truthy
|
@@ -29,8 +29,11 @@ describe Appsignal::Extension do
|
|
29
29
|
subject.start
|
30
30
|
end
|
31
31
|
|
32
|
-
expect(output).to
|
33
|
-
|
32
|
+
expect(output).to match \
|
33
|
+
%r{
|
34
|
+
WARNING:\sError\swhen\sreading\sappsignal\sconfig,\s
|
35
|
+
appsignal\s\(as\s(\d{2,4})/(\d{2,4})\)\snot\sstarting
|
36
|
+
}x
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
@@ -64,3 +64,13 @@ describe Appsignal::GarbageCollectionProfiler do
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
describe Appsignal::NilGarbageCollectionProfiler do
|
69
|
+
let(:profiler) { described_class.new }
|
70
|
+
|
71
|
+
describe "#total_time" do
|
72
|
+
it "has a total time of 0" do
|
73
|
+
expect(profiler.total_time).to eq(0)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -672,6 +672,23 @@ describe Appsignal::Transaction do
|
|
672
672
|
end
|
673
673
|
end
|
674
674
|
|
675
|
+
describe "#garbage_collection_profiler" do
|
676
|
+
before { Appsignal::Transaction.instance_variable_set(:@garbage_collection_profiler, nil) }
|
677
|
+
|
678
|
+
it "returns the NilGarbageCollectionProfiler" do
|
679
|
+
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::NilGarbageCollectionProfiler)
|
680
|
+
end
|
681
|
+
|
682
|
+
context "when gc profiling is enabled" do
|
683
|
+
before { Appsignal.config.config_hash[:enable_gc_instrumentation] = true }
|
684
|
+
after { Appsignal.config.config_hash[:enable_gc_instrumentation] = false }
|
685
|
+
|
686
|
+
it "returns the GarbageCollectionProfiler" do
|
687
|
+
expect(Appsignal::Transaction.garbage_collection_profiler).to be_a(Appsignal::GarbageCollectionProfiler)
|
688
|
+
end
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
675
692
|
describe "#start_event" do
|
676
693
|
it "should start the event in the extension" do
|
677
694
|
expect(transaction.ext).to receive(:start_event).with(0).and_call_original
|
@@ -986,7 +1003,7 @@ describe Appsignal::Transaction do
|
|
986
1003
|
end
|
987
1004
|
|
988
1005
|
describe "#sanitized_environment" do
|
989
|
-
let(:
|
1006
|
+
let(:allowlisted_keys) { Appsignal.config[:request_headers] }
|
990
1007
|
subject { transaction.send(:sanitized_environment) }
|
991
1008
|
|
992
1009
|
context "when request is nil" do
|
@@ -1004,14 +1021,14 @@ describe Appsignal::Transaction do
|
|
1004
1021
|
context "when env is present" do
|
1005
1022
|
let(:env) do
|
1006
1023
|
{}.tap do |hash|
|
1007
|
-
|
1008
|
-
hash[
|
1009
|
-
hash[:
|
1024
|
+
allowlisted_keys.each { |o| hash[o] = 1 } # use all allowlisted keys
|
1025
|
+
hash[allowlisted_keys] = nil # don't add if nil
|
1026
|
+
hash[:not_allowlisted] = "I will be sanitized"
|
1010
1027
|
end
|
1011
1028
|
end
|
1012
1029
|
|
1013
|
-
it "only sets
|
1014
|
-
expect(subject.keys).to match_array(
|
1030
|
+
it "only sets allowlisted keys" do
|
1031
|
+
expect(subject.keys).to match_array(allowlisted_keys)
|
1015
1032
|
end
|
1016
1033
|
|
1017
1034
|
context "with configured request_headers" do
|
@@ -1019,7 +1036,7 @@ describe Appsignal::Transaction do
|
|
1019
1036
|
Appsignal.config.config_hash[:request_headers] = %w[CONTENT_LENGTH]
|
1020
1037
|
end
|
1021
1038
|
|
1022
|
-
it "only sets
|
1039
|
+
it "only sets allowlisted keys" do
|
1023
1040
|
expect(subject.keys).to match_array(%w[CONTENT_LENGTH])
|
1024
1041
|
end
|
1025
1042
|
end
|
@@ -56,18 +56,41 @@ module StdStreamsHelper
|
|
56
56
|
# If an error is found the output the output is raised as an error, failing
|
57
57
|
# the spec. Warnings and other AppSignal messages are ignored.
|
58
58
|
#
|
59
|
-
#
|
59
|
+
# @example
|
60
|
+
# silence { do_something }
|
61
|
+
# # Does nothing
|
62
|
+
#
|
63
|
+
# silence { puts "ERROR!" }
|
64
|
+
# # => Error found in silenced output:
|
65
|
+
# # ERROR!
|
60
66
|
#
|
61
|
-
#
|
67
|
+
# @example Ignore certain errors
|
68
|
+
# silence(:allowed => ["my error"]) { puts "my error!" }
|
69
|
+
# # Does nothing
|
62
70
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
def silence(&block)
|
71
|
+
# silence { puts "my error!" }
|
72
|
+
# # => Error found in silenced output:
|
73
|
+
# # my error!
|
74
|
+
def silence(options = {}, &block)
|
67
75
|
stream = Tempfile.new(SecureRandom.uuid)
|
68
76
|
capture_std_streams(stream, stream, &block)
|
69
77
|
ensure
|
70
|
-
output = stream.read
|
71
|
-
|
78
|
+
output = filter_allowed_errors(stream.read, options.fetch(:allowed, []))
|
79
|
+
if output =~ /(ERR|Error|error)/
|
80
|
+
raise "Error found in silenced output:\n#{output}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def filter_allowed_errors(output, allowed_errors)
|
85
|
+
output.lines.reject do |line|
|
86
|
+
reject = false
|
87
|
+
allowed_errors.each do |error|
|
88
|
+
if line.include?(error)
|
89
|
+
reject = true
|
90
|
+
break
|
91
|
+
end
|
92
|
+
end
|
93
|
+
reject
|
94
|
+
end.join(",")
|
72
95
|
end
|
73
96
|
end
|