appsignal 2.8.0.alpha.1-java → 2.8.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|