appsignal 3.11.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -0
  3. data/Rakefile +1 -1
  4. data/lib/appsignal/cli/diagnose.rb +1 -1
  5. data/lib/appsignal/config.rb +150 -32
  6. data/lib/appsignal/demo.rb +1 -6
  7. data/lib/appsignal/integrations/grape.rb +7 -0
  8. data/lib/appsignal/integrations/hanami.rb +8 -43
  9. data/lib/appsignal/integrations/padrino.rb +8 -73
  10. data/lib/appsignal/integrations/railtie.rb +35 -13
  11. data/lib/appsignal/integrations/sinatra.rb +8 -19
  12. data/lib/appsignal/loaders/grape.rb +13 -0
  13. data/lib/appsignal/loaders/hanami.rb +40 -0
  14. data/lib/appsignal/loaders/padrino.rb +68 -0
  15. data/lib/appsignal/loaders/sinatra.rb +24 -0
  16. data/lib/appsignal/loaders.rb +92 -0
  17. data/lib/appsignal/rack/abstract_middleware.rb +2 -1
  18. data/lib/appsignal/rack/event_handler.rb +5 -5
  19. data/lib/appsignal/rack.rb +6 -0
  20. data/lib/appsignal/version.rb +1 -1
  21. data/lib/appsignal.rb +163 -9
  22. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  23. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  24. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  25. data/spec/lib/appsignal/config_spec.rb +153 -1
  26. data/spec/lib/appsignal/demo_spec.rb +1 -2
  27. data/spec/lib/appsignal/environment_spec.rb +4 -2
  28. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  29. data/spec/lib/appsignal/hooks/activejob_spec.rb +3 -3
  30. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  31. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  32. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  33. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  34. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  35. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  36. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  37. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  38. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  39. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  40. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  41. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +2 -2
  42. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  43. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  44. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  45. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  46. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  47. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  48. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  49. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  50. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +1 -1
  51. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +11 -9
  52. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  53. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  54. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  55. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  56. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  57. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  58. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  59. data/spec/lib/appsignal/probes_spec.rb +6 -5
  60. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +3 -2
  61. data/spec/lib/appsignal/rack/event_handler_spec.rb +33 -0
  62. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  63. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  64. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  65. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  66. data/spec/lib/appsignal/span_spec.rb +1 -3
  67. data/spec/lib/appsignal/transaction_spec.rb +4 -2
  68. data/spec/lib/appsignal_spec.rb +278 -26
  69. data/spec/lib/puma/appsignal_spec.rb +0 -3
  70. data/spec/spec_helper.rb +5 -4
  71. data/spec/support/helpers/config_helpers.rb +2 -1
  72. data/spec/support/helpers/loader_helper.rb +21 -0
  73. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  74. data/spec/support/testing.rb +46 -0
  75. metadata +15 -2
@@ -11,7 +11,7 @@ describe Appsignal::Config do
11
11
 
12
12
  context "when environment is given" do
13
13
  let(:env) { "my_env" }
14
- let(:config) { described_class.new("", "my_env") }
14
+ let(:config) { described_class.new("/root/path", "my_env") }
15
15
 
16
16
  it "sets the environment" do
17
17
  expect(config.env).to eq(env)
@@ -20,6 +20,7 @@ describe Appsignal::Config do
20
20
  it "sets the environment as loaded through the initial_config" do
21
21
  expect(config.initial_config).to eq(:env => env)
22
22
  expect(config.config_hash).to_not have_key(:env)
23
+ expect(config.config_hash).to_not have_key(:root_path)
23
24
  end
24
25
 
25
26
  context "with APPSIGNAL_APP_ENV environment variable" do
@@ -34,6 +35,7 @@ describe Appsignal::Config do
34
35
  expect(config.initial_config).to eq(:env => env)
35
36
  expect(config.env_config).to eq(:env => env_env)
36
37
  expect(config.config_hash).to_not have_key(:env)
38
+ expect(config.config_hash).to_not have_key(:root_path)
37
39
  end
38
40
  end
39
41
  end
@@ -121,6 +123,76 @@ describe Appsignal::Config do
121
123
  end
122
124
  end
123
125
 
126
+ describe "loader default config" do
127
+ let(:config) do
128
+ described_class.new("some-path", "production")
129
+ end
130
+ before do
131
+ class TestLoader < Appsignal::Loaders::Loader
132
+ register :test
133
+ def on_load
134
+ register_config_defaults(
135
+ :env => "new_env",
136
+ :root_path => "/some/path",
137
+ :my_option => "my_value",
138
+ :nil_option => nil
139
+ )
140
+ end
141
+ end
142
+ load_loader(:test)
143
+ end
144
+ after do
145
+ Object.send(:remove_const, :TestLoader)
146
+ unregister_loader(:first)
147
+ end
148
+
149
+ it "merges with the loader defaults" do
150
+ expect(config.config_hash).to include(:my_option => "my_value")
151
+ end
152
+
153
+ it "does not set any nil values" do
154
+ expect(config.config_hash).to_not have_key(:nil_option)
155
+ end
156
+
157
+ it "overwrites the env" do
158
+ expect(config.env).to eq("new_env")
159
+ end
160
+
161
+ it "overwrites the path" do
162
+ expect(config.root_path).to eq("/some/path")
163
+ end
164
+
165
+ context "with multiple loaders" do
166
+ before do
167
+ class SecondLoader < Appsignal::Loaders::Loader
168
+ register :second
169
+ def on_load
170
+ register_config_defaults(
171
+ :env => "second_env",
172
+ :root_path => "/second/path",
173
+ :my_option => "second_value",
174
+ :second_option => "second_value"
175
+ )
176
+ end
177
+ end
178
+ load_loader(:second)
179
+ end
180
+ after do
181
+ Object.send(:remove_const, :SecondLoader)
182
+ unregister_loader(:second)
183
+ end
184
+
185
+ it "makes the first loader's config leading" do
186
+ expect(config.config_hash).to include(
187
+ :my_option => "my_value",
188
+ :second_option => "second_value"
189
+ )
190
+ expect(config.env).to eq("new_env")
191
+ expect(config.root_path).to eq("/some/path")
192
+ end
193
+ end
194
+ end
195
+
124
196
  describe "initial config" do
125
197
  let(:initial_config) do
126
198
  {
@@ -1259,4 +1331,84 @@ describe Appsignal::Config do
1259
1331
  end
1260
1332
  end
1261
1333
  end
1334
+
1335
+ describe Appsignal::Config::ConfigDSL do
1336
+ let(:env) { :production }
1337
+ let(:config) { project_fixture_config(env) }
1338
+ let(:dsl) { described_class.new(config) }
1339
+
1340
+ describe "default options" do
1341
+ let(:env) { :unknown_env }
1342
+
1343
+ it "returns default values for config options" do
1344
+ Appsignal::Config::DEFAULT_CONFIG.each do |option, value|
1345
+ expect(dsl.send(option)).to eq(value)
1346
+ end
1347
+ end
1348
+ end
1349
+
1350
+ it "returns already set values for config options" do
1351
+ ENV["APPSIGNAL_IGNORE_ERRORS"] = "my_error1,my_error2"
1352
+ config[:push_api_key] = "my push key"
1353
+ config[:ignore_actions] = ["My ignored action"]
1354
+
1355
+ expect(dsl.push_api_key).to eq("my push key")
1356
+ expect(dsl.ignore_actions).to eq(["My ignored action"])
1357
+ expect(dsl.ignore_errors).to eq(["my_error1", "my_error2"])
1358
+ end
1359
+
1360
+ it "returns the env" do
1361
+ expect(dsl.env).to eq("production")
1362
+ end
1363
+
1364
+ it "sets config options" do
1365
+ dsl.push_api_key = "my push key"
1366
+ dsl.ignore_actions = ["My ignored action"]
1367
+
1368
+ expect(dsl.push_api_key).to eq("my push key")
1369
+ expect(dsl.ignore_actions).to eq(["My ignored action"])
1370
+ end
1371
+
1372
+ it "doesn't update the config object" do
1373
+ dsl.push_api_key = "my push key"
1374
+
1375
+ expect(dsl.push_api_key).to eq("my push key")
1376
+ expect(config[:push_api_key]).to eq("abc") # Loaded from file
1377
+ end
1378
+
1379
+ it "casts strings to strings" do
1380
+ dsl.activejob_report_errors = :all
1381
+ dsl.sidekiq_report_errors = :all
1382
+
1383
+ expect(dsl.activejob_report_errors).to eq("all")
1384
+ expect(dsl.sidekiq_report_errors).to eq("all")
1385
+ end
1386
+
1387
+ it "casts booleans to booleans" do
1388
+ dsl.active = :yes
1389
+ dsl.enable_host_metrics = "An object representing a truthy value"
1390
+ dsl.send_params = true
1391
+ dsl.send_session_data = false
1392
+
1393
+ expect(dsl.active).to be(true)
1394
+ expect(dsl.enable_host_metrics).to be(true)
1395
+ expect(dsl.send_params).to be(true)
1396
+ expect(dsl.send_session_data).to be(false)
1397
+ end
1398
+
1399
+ it "casts arrays to arrays" do
1400
+ ignore_actions = Set.new
1401
+ ignore_actions << "my ignored action 1"
1402
+ ignore_actions << "my ignored action 2"
1403
+ dsl.ignore_actions = ignore_actions
1404
+
1405
+ expect(dsl.ignore_actions).to eq(["my ignored action 1", "my ignored action 2"])
1406
+ end
1407
+
1408
+ it "casts floats to floats" do
1409
+ dsl.cpu_count = 1
1410
+
1411
+ expect(dsl.cpu_count).to eq(1.0)
1412
+ end
1413
+ end
1262
1414
  end
@@ -16,8 +16,7 @@ describe Appsignal::Demo do
16
16
  end
17
17
 
18
18
  context "with config" do
19
- let(:config) { project_fixture_config("production") }
20
- before { Appsignal.config = config }
19
+ before { start_agent }
21
20
 
22
21
  it "returns true" do
23
22
  expect(subject).to eq(true)
@@ -1,8 +1,10 @@
1
1
  describe Appsignal::Environment do
2
2
  include EnvironmentMetadataHelper
3
3
 
4
- before(:context) { start_agent }
5
- before { capture_environment_metadata_report_calls }
4
+ before do
5
+ start_agent
6
+ capture_environment_metadata_report_calls
7
+ end
6
8
 
7
9
  def report(key, &value_block)
8
10
  described_class.report(key, &value_block)
@@ -4,13 +4,10 @@ describe Appsignal::Hooks::ActiveSupportNotificationsHook do
4
4
  if active_support_present?
5
5
  let(:notifier) { ActiveSupport::Notifications::Fanout.new }
6
6
  let(:as) { ActiveSupport::Notifications }
7
- let!(:transaction) do
8
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
9
- end
10
- before :context do
11
- start_agent
12
- end
7
+ let(:transaction) { http_request_transaction }
13
8
  before do
9
+ start_agent
10
+ set_current_transaction(transaction)
14
11
  as.notifier = notifier
15
12
  end
16
13
 
@@ -210,7 +210,7 @@ if DependencyHelper.active_job_present?
210
210
 
211
211
  context "with activejob_report_errors set to none" do
212
212
  it "does not report the error" do
213
- Appsignal.config = project_fixture_config("production")
213
+ start_agent("production")
214
214
  Appsignal.config[:activejob_report_errors] = "none"
215
215
 
216
216
  allow(Appsignal).to receive(:increment_counter)
@@ -229,7 +229,7 @@ if DependencyHelper.active_job_present?
229
229
  if DependencyHelper.rails_version >= Gem::Version.new("7.1.0")
230
230
  context "with activejob_report_errors set to discard" do
231
231
  before do
232
- Appsignal.config = project_fixture_config("production")
232
+ start_agent("production")
233
233
  Appsignal.config[:activejob_report_errors] = "discard"
234
234
  end
235
235
 
@@ -352,7 +352,7 @@ if DependencyHelper.active_job_present?
352
352
 
353
353
  context "with params" do
354
354
  it "filters the configured params" do
355
- Appsignal.config = project_fixture_config("production")
355
+ start_agent("production")
356
356
  Appsignal.config[:filter_parameters] = ["foo"]
357
357
  queue_job(ActiveJobTestJob, method_given_args)
358
358
 
@@ -32,16 +32,13 @@ if DependencyHelper.dry_monitor_present?
32
32
  end
33
33
 
34
34
  describe "Dry Monitor Integration" do
35
- before :context do
35
+ let(:notifications) { Dry::Monitor::Notifications.new(:test) }
36
+ let(:transaction) { http_request_transaction }
37
+ before do
36
38
  start_agent
39
+ set_current_transaction(transaction)
37
40
  end
38
41
 
39
- let!(:transaction) do
40
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
41
- end
42
-
43
- let(:notifications) { Dry::Monitor::Notifications.new(:test) }
44
-
45
42
  context "when is a dry-sql event" do
46
43
  let(:event_id) { :sql }
47
44
  let(:payload) do
@@ -1,7 +1,5 @@
1
1
  describe Appsignal::Hooks::ExconHook do
2
- before :context do
3
- start_agent
4
- end
2
+ before { start_agent }
5
3
 
6
4
  context "with Excon" do
7
5
  before(:context) do
@@ -27,9 +25,8 @@ describe Appsignal::Hooks::ExconHook do
27
25
  end
28
26
 
29
27
  describe "instrumentation" do
30
- let!(:transaction) do
31
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
32
- end
28
+ let(:transaction) { http_request_transaction }
29
+ before { set_current_transaction(transaction) }
33
30
  around { |example| keep_transactions { example.run } }
34
31
 
35
32
  it "instruments a http request" do
@@ -7,8 +7,8 @@ describe Appsignal::Hooks::GvlHook do
7
7
  end
8
8
  end
9
9
  else
10
- before(:context) do
11
- Appsignal.config = project_fixture_config
10
+ before do
11
+ start_agent
12
12
  end
13
13
 
14
14
  def expect_gvltools_require
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe Appsignal::Hooks::HttpHook do
4
- before :context do
5
- start_agent
6
- end
4
+ before { start_agent }
7
5
 
8
6
  if DependencyHelper.http_present?
9
7
  context "with instrument_http_rb set to true" do
@@ -1,5 +1,5 @@
1
1
  describe Appsignal::Hooks::NetHttpHook do
2
- before(:context) { start_agent }
2
+ before { start_agent }
3
3
 
4
4
  describe "#dependencies_present?" do
5
5
  subject { described_class.new.dependencies_present? }
@@ -1,6 +1,6 @@
1
1
  describe Appsignal::Hooks::RedisClientHook do
2
2
  before do
3
- Appsignal.config = project_fixture_config
3
+ start_agent
4
4
  end
5
5
 
6
6
  if DependencyHelper.redis_client_present?
@@ -78,10 +78,9 @@ describe Appsignal::Hooks::RedisClientHook do
78
78
  # track if it was installed already or not.
79
79
  Appsignal::Hooks::RedisClientHook.new.install
80
80
  end
81
- let!(:transaction) do
82
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
83
- end
81
+ let(:transaction) { http_request_transaction }
84
82
  let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
83
+ before { set_current_transaction(transaction) }
85
84
  around { |example| keep_transactions { example.run } }
86
85
 
87
86
  it "instrument a redis call" do
@@ -164,11 +163,9 @@ describe Appsignal::Hooks::RedisClientHook do
164
163
  # track if it was installed already or not.
165
164
  Appsignal::Hooks::RedisClientHook.new.install
166
165
  end
167
- let!(:transaction) do
168
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST,
169
- "test")
170
- end
166
+ let(:transaction) { http_request_transaction }
171
167
  let!(:client_config) { RedisClient::Config.new(:id => "stub_id") }
168
+ before { set_current_transaction(transaction) }
172
169
  around { |example| keep_transactions { example.run } }
173
170
 
174
171
  it "instrument a redis call" do
@@ -1,7 +1,5 @@
1
1
  describe Appsignal::Hooks::RedisHook do
2
- before do
3
- Appsignal.config = project_fixture_config
4
- end
2
+ before { start_agent }
5
3
 
6
4
  if DependencyHelper.redis_present?
7
5
  context "with redis" do
@@ -72,9 +70,8 @@ describe Appsignal::Hooks::RedisHook do
72
70
  # track if it was installed already or not.
73
71
  Appsignal::Hooks::RedisHook.new.install
74
72
  end
75
- let!(:transaction) do
76
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
77
- end
73
+ let(:transaction) { http_request_transaction }
74
+ before { set_current_transaction(transaction) }
78
75
  around { |example| keep_transactions { example.run } }
79
76
 
80
77
  it "instrument a redis call" do
@@ -83,7 +83,7 @@ describe Appsignal::Hooks::ResqueHook do
83
83
 
84
84
  context "with arguments" do
85
85
  before do
86
- Appsignal.config = project_fixture_config("production")
86
+ start_agent("production")
87
87
  Appsignal.config[:filter_parameters] = ["foo"]
88
88
  end
89
89
 
@@ -8,9 +8,7 @@ describe Appsignal::Hooks::SequelHook do
8
8
  end
9
9
  end
10
10
 
11
- before :context do
12
- start_agent
13
- end
11
+ before { start_agent }
14
12
 
15
13
  describe "#dependencies_present?" do
16
14
  subject { described_class.new.dependencies_present? }
@@ -19,9 +17,9 @@ describe Appsignal::Hooks::SequelHook do
19
17
  end
20
18
 
21
19
  context "with a transaction" do
22
- let(:transaction) { Appsignal::Transaction.current }
20
+ let(:transaction) { http_request_transaction }
23
21
  before do
24
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
22
+ set_current_transaction(transaction)
25
23
  db.logger = Logger.new($stdout) # To test #log_duration call
26
24
  end
27
25
 
@@ -65,7 +65,7 @@ describe Appsignal::Hooks::SidekiqHook do
65
65
  end
66
66
 
67
67
  before do
68
- Appsignal.config = project_fixture_config
68
+ start_agent
69
69
  stub_const "Sidekiq", SidekiqMock
70
70
  end
71
71
 
@@ -2,7 +2,7 @@ describe Appsignal::Hooks::WebmachineHook do
2
2
  if DependencyHelper.webmachine_present?
3
3
  context "with webmachine" do
4
4
  let(:fsm) { Webmachine::Decision::FSM.new(double(:trace? => false), double, double) }
5
- before(:context) { start_agent }
5
+ before { start_agent }
6
6
 
7
7
  describe "#dependencies_present?" do
8
8
  subject { described_class.new.dependencies_present? }
@@ -83,7 +83,7 @@ describe "Appsignal::Integrations::DelayedJobHook" do
83
83
 
84
84
  context "with parameter filtering" do
85
85
  before do
86
- Appsignal.config = project_fixture_config("production")
86
+ start_agent("production")
87
87
  Appsignal.config[:filter_parameters] = ["foo"]
88
88
  end
89
89
 
@@ -272,7 +272,7 @@ describe "Appsignal::Integrations::DelayedJobHook" do
272
272
 
273
273
  context "with parameter filtering" do
274
274
  before do
275
- Appsignal.config = project_fixture_config("production")
275
+ start_agent("production")
276
276
  Appsignal.config[:filter_parameters] = ["foo"]
277
277
  end
278
278
 
@@ -0,0 +1,36 @@
1
+ if DependencyHelper.grape_present?
2
+ require "appsignal/integrations/grape"
3
+
4
+ context "Appsignal::Grape::Middleware constant" do
5
+ let(:err_stream) { std_stream }
6
+ let(:stderr) { err_stream.read }
7
+
8
+ it "returns the Rack::GrapeMiddleware constant calling the Grape::Middleware constant" do
9
+ silence { expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware) }
10
+ end
11
+
12
+ it "prints a deprecation warning to STDERR" do
13
+ capture_std_streams(std_stream, err_stream) do
14
+ expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
15
+ end
16
+
17
+ expect(stderr).to include(
18
+ "appsignal WARNING: The constant Appsignal::Grape::Middleware has been deprecated."
19
+ )
20
+ end
21
+
22
+ it "logs a warning" do
23
+ logs =
24
+ capture_logs do
25
+ silence do
26
+ expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
27
+ end
28
+ end
29
+
30
+ expect(logs).to contains_log(
31
+ :warn,
32
+ "The constant Appsignal::Grape::Middleware has been deprecated."
33
+ )
34
+ end
35
+ end
36
+ end