appsignal 3.13.0 → 4.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +499 -487
  3. data/CHANGELOG.md +113 -0
  4. data/Rakefile +31 -7
  5. data/benchmark.rake +4 -6
  6. data/build_matrix.yml +45 -39
  7. data/ext/agent.rb +27 -27
  8. data/ext/appsignal_extension.c +25 -0
  9. data/gemfiles/rails-7.2.gemfile +11 -0
  10. data/lib/appsignal/check_in/cron.rb +2 -15
  11. data/lib/appsignal/cli/diagnose.rb +37 -28
  12. data/lib/appsignal/cli/install.rb +5 -1
  13. data/lib/appsignal/config.rb +57 -119
  14. data/lib/appsignal/demo.rb +2 -2
  15. data/lib/appsignal/extension/jruby.rb +14 -0
  16. data/lib/appsignal/helpers/instrumentation.rb +139 -417
  17. data/lib/appsignal/helpers/metrics.rb +0 -16
  18. data/lib/appsignal/hooks/action_cable.rb +8 -8
  19. data/lib/appsignal/hooks/active_job.rb +2 -2
  20. data/lib/appsignal/hooks/at_exit.rb +37 -0
  21. data/lib/appsignal/hooks.rb +1 -16
  22. data/lib/appsignal/integrations/action_cable.rb +2 -2
  23. data/lib/appsignal/integrations/capistrano/appsignal.cap +2 -4
  24. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +1 -4
  25. data/lib/appsignal/integrations/delayed_job_plugin.rb +3 -3
  26. data/lib/appsignal/integrations/que.rb +2 -2
  27. data/lib/appsignal/integrations/railtie.rb +26 -59
  28. data/lib/appsignal/integrations/rake.rb +2 -2
  29. data/lib/appsignal/integrations/resque.rb +2 -2
  30. data/lib/appsignal/integrations/shoryuken.rb +4 -4
  31. data/lib/appsignal/integrations/sidekiq.rb +3 -3
  32. data/lib/appsignal/integrations/webmachine.rb +2 -2
  33. data/lib/appsignal/loaders.rb +1 -1
  34. data/lib/appsignal/probes.rb +0 -9
  35. data/lib/appsignal/rack/abstract_middleware.rb +4 -26
  36. data/lib/appsignal/rack/event_handler.rb +4 -4
  37. data/lib/appsignal/rack/rails_instrumentation.rb +1 -1
  38. data/lib/appsignal/rack.rb +0 -25
  39. data/lib/appsignal/sample_data.rb +95 -0
  40. data/lib/appsignal/transaction.rb +235 -361
  41. data/lib/appsignal/utils/rails_helper.rb +4 -0
  42. data/lib/appsignal/version.rb +1 -1
  43. data/lib/appsignal.rb +19 -71
  44. data/spec/lib/appsignal/auth_check_spec.rb +1 -1
  45. data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
  46. data/spec/lib/appsignal/capistrano3_spec.rb +53 -13
  47. data/spec/lib/appsignal/check_in_spec.rb +1 -207
  48. data/spec/lib/appsignal/cli/demo_spec.rb +7 -27
  49. data/spec/lib/appsignal/cli/diagnose_spec.rb +145 -110
  50. data/spec/lib/appsignal/config_spec.rb +304 -379
  51. data/spec/lib/appsignal/extension_install_failure_spec.rb +5 -1
  52. data/spec/lib/appsignal/extension_spec.rb +5 -1
  53. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +1 -1
  54. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +1 -2
  55. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +1 -0
  56. data/spec/lib/appsignal/hooks/activejob_spec.rb +7 -12
  57. data/spec/lib/appsignal/hooks/at_exit_spec.rb +72 -0
  58. data/spec/lib/appsignal/hooks/gvl_spec.rb +10 -5
  59. data/spec/lib/appsignal/hooks/http_spec.rb +3 -3
  60. data/spec/lib/appsignal/hooks/net_http_spec.rb +3 -3
  61. data/spec/lib/appsignal/hooks/rake_spec.rb +6 -9
  62. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -10
  63. data/spec/lib/appsignal/hooks/redis_spec.rb +4 -7
  64. data/spec/lib/appsignal/hooks/resque_spec.rb +3 -5
  65. data/spec/lib/appsignal/hooks_spec.rb +0 -41
  66. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +29 -20
  67. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +4 -9
  68. data/spec/lib/appsignal/integrations/railtie_spec.rb +179 -157
  69. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +3 -5
  70. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +48 -62
  71. data/spec/lib/appsignal/loaders/hanami_spec.rb +6 -9
  72. data/spec/lib/appsignal/loaders/padrino_spec.rb +6 -10
  73. data/spec/lib/appsignal/loaders/sinatra_spec.rb +6 -9
  74. data/spec/lib/appsignal/loaders_spec.rb +8 -1
  75. data/spec/lib/appsignal/marker_spec.rb +1 -1
  76. data/spec/lib/appsignal/probes_spec.rb +4 -83
  77. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +4 -63
  78. data/spec/lib/appsignal/rack/event_handler_spec.rb +18 -15
  79. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +3 -11
  80. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +4 -5
  81. data/spec/lib/appsignal/sample_data_spec.rb +174 -0
  82. data/spec/lib/appsignal/transaction_spec.rb +791 -1031
  83. data/spec/lib/appsignal/transmitter_spec.rb +6 -8
  84. data/spec/lib/appsignal_spec.rb +294 -643
  85. data/spec/spec_helper.rb +1 -3
  86. data/spec/support/fixtures/projects/valid/config/appsignal.yml +4 -7
  87. data/spec/support/fixtures/projects/valid_with_rails_app/config/application.rb +16 -0
  88. data/spec/support/fixtures/projects/valid_with_rails_app/config/appsignal.yml +56 -0
  89. data/spec/support/fixtures/projects/valid_with_rails_app/config/environment.rb +5 -0
  90. data/spec/support/helpers/api_request_helper.rb +3 -2
  91. data/spec/support/helpers/config_helpers.rb +41 -11
  92. data/spec/support/helpers/dependency_helper.rb +8 -0
  93. data/spec/support/helpers/log_helpers.rb +1 -0
  94. data/spec/support/helpers/rails_helper.rb +6 -6
  95. data/spec/support/helpers/transaction_helpers.rb +2 -24
  96. data/spec/support/matchers/transaction.rb +3 -3
  97. data/spec/support/mocks/appsignal_mock.rb +3 -3
  98. data/spec/support/mocks/mock_probe.rb +2 -0
  99. data/spec/support/testing.rb +2 -2
  100. metadata +12 -22
  101. data/gemfiles/que_beta.gemfile +0 -5
  102. data/lib/appsignal/helpers/heartbeat.rb +0 -20
  103. data/lib/appsignal/integrations/grape.rb +0 -35
  104. data/lib/appsignal/integrations/hanami.rb +0 -13
  105. data/lib/appsignal/integrations/padrino.rb +0 -13
  106. data/lib/appsignal/integrations/sinatra.rb +0 -13
  107. data/lib/appsignal/rack/generic_instrumentation.rb +0 -22
  108. data/lib/appsignal/rack/streaming_listener.rb +0 -28
  109. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -36
  110. data/spec/lib/appsignal/integrations/hanami_spec.rb +0 -17
  111. data/spec/lib/appsignal/integrations/padrino_spec.rb +0 -15
  112. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -15
  113. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +0 -81
  114. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +0 -69
  115. data/spec/support/fixtures/projects/valid/config/environments/development.rb +0 -0
  116. data/spec/support/fixtures/projects/valid/config/environments/production.rb +0 -0
  117. data/spec/support/fixtures/projects/valid/config/environments/test.rb +0 -0
  118. data/spec/support/rails/my_app.rb +0 -6
  119. /data/spec/support/fixtures/projects/{valid/config/application.rb → valid_with_rails_app/log/.gitkeep} +0 -0
@@ -13,10 +13,11 @@ describe Appsignal::Rack::EventHandler do
13
13
  let(:request) { Rack::Request.new(env) }
14
14
  let(:response) { nil }
15
15
  let(:log_stream) { StringIO.new }
16
- let(:log) { log_contents(log_stream) }
16
+ let(:logs) { log_contents(log_stream) }
17
17
  let(:event_handler_instance) { described_class.new }
18
+ let(:appsignal_env) { :default }
18
19
  before do
19
- start_agent
20
+ start_agent(:env => appsignal_env)
20
21
  Appsignal.internal_logger = test_logger(log_stream)
21
22
  end
22
23
  around { |example| keep_transactions { example.run } }
@@ -41,9 +42,9 @@ describe Appsignal::Rack::EventHandler do
41
42
  end
42
43
 
43
44
  context "when not active" do
44
- it "does not create a new transaction" do
45
- allow(Appsignal).to receive(:active?).and_return(false)
45
+ let(:appsignal_env) { :inactive_env }
46
46
 
47
+ it "does not create a new transaction" do
47
48
  expect { on_start }.to_not(change { created_transactions.length })
48
49
  end
49
50
  end
@@ -95,7 +96,7 @@ describe Appsignal::Rack::EventHandler do
95
96
  end
96
97
 
97
98
  it "logs an error" do
98
- expect(log).to contains_log(
99
+ expect(logs).to contains_log(
99
100
  :error,
100
101
  "Error occurred in Appsignal::Rack::EventHandler's after_reply: " \
101
102
  "ExampleStandardError: oh no"
@@ -112,7 +113,7 @@ describe Appsignal::Rack::EventHandler do
112
113
  callback = request.env[Appsignal::Rack::RACK_AFTER_REPLY].first
113
114
  callback.call
114
115
 
115
- expect(log).to contains_log(
116
+ expect(logs).to contains_log(
116
117
  :error,
117
118
  "Error occurred in Appsignal::Rack::EventHandler's after_reply: ExampleStandardError: oh no"
118
119
  )
@@ -124,7 +125,7 @@ describe Appsignal::Rack::EventHandler do
124
125
 
125
126
  on_start
126
127
 
127
- expect(log).to contains_log(
128
+ expect(logs).to contains_log(
128
129
  :error,
129
130
  "Error occurred in Appsignal::Rack::EventHandler#on_start: ExampleStandardError: oh no"
130
131
  )
@@ -140,9 +141,9 @@ describe Appsignal::Rack::EventHandler do
140
141
  end
141
142
 
142
143
  context "when not active" do
143
- it "does not report the transaction" do
144
- allow(Appsignal).to receive(:active?).and_return(false)
144
+ let(:appsignal_env) { :inactive_env }
145
145
 
146
+ it "does not report the transaction" do
146
147
  on_start
147
148
  on_error(ExampleStandardError.new("the error"))
148
149
 
@@ -167,7 +168,7 @@ describe Appsignal::Rack::EventHandler do
167
168
 
168
169
  on_error(ExampleStandardError.new("the error"))
169
170
 
170
- expect(log).to contains_log(
171
+ expect(logs).to contains_log(
171
172
  :error,
172
173
  "Error occurred in Appsignal::Rack::EventHandler#on_error: ExampleStandardError: oh no"
173
174
  )
@@ -195,9 +196,9 @@ describe Appsignal::Rack::EventHandler do
195
196
  end
196
197
 
197
198
  context "when not active" do
198
- it "doesn't do anything" do
199
- allow(Appsignal).to receive(:active?).and_return(false)
199
+ let(:appsignal_env) { :inactive_env }
200
200
 
201
+ it "doesn't do anything" do
201
202
  request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = http_request_transaction
202
203
  on_finish
203
204
 
@@ -353,8 +354,10 @@ describe Appsignal::Rack::EventHandler do
353
354
  end
354
355
 
355
356
  it "logs an error" do
356
- expect(log).to contains_log(:error,
357
- "Error occurred in Appsignal::Rack::EventHandler#on_finish: ExampleStandardError: oh no")
357
+ expect(logs).to contains_log(
358
+ :error,
359
+ "Error occurred in Appsignal::Rack::EventHandler#on_finish: ExampleStandardError: oh no"
360
+ )
358
361
  end
359
362
  end
360
363
 
@@ -429,7 +432,7 @@ describe Appsignal::Rack::EventHandler do
429
432
  on_start
430
433
  on_finish
431
434
 
432
- expect(log).to contains_log(
435
+ expect(logs).to contains_log(
433
436
  :error,
434
437
  "Error occurred in Appsignal::Rack::EventHandler#on_finish: ExampleStandardError: oh no"
435
438
  )
@@ -2,14 +2,7 @@ if DependencyHelper.rails_present?
2
2
  describe Appsignal::Rack::RailsInstrumentation do
3
3
  class MockController; end
4
4
 
5
- let(:log) { StringIO.new }
6
- let(:transaction) do
7
- Appsignal::Transaction.new(
8
- "transaction_id",
9
- Appsignal::Transaction::HTTP_REQUEST,
10
- Rack::Request.new(env)
11
- )
12
- end
5
+ let(:transaction) { new_transaction }
13
6
  let(:app) { DummyApp.new }
14
7
  let(:params) do
15
8
  {
@@ -36,7 +29,6 @@ if DependencyHelper.rails_present?
36
29
  around { |example| keep_transactions { example.run } }
37
30
  before do
38
31
  start_agent
39
- Appsignal.internal_logger = test_logger(log)
40
32
  env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
41
33
  end
42
34
 
@@ -111,10 +103,10 @@ if DependencyHelper.rails_present?
111
103
  it "does not store the invalid HTTP request method" do
112
104
  env[:request_method] = "FOO"
113
105
  env["REQUEST_METHOD"] = "FOO"
114
- make_request
106
+ logs = capture_logs { make_request }
115
107
 
116
108
  expect(last_transaction).to_not include_metadata("method" => anything)
117
- expect(log_contents(log)).to contains_log(
109
+ expect(logs).to contains_log(
118
110
  :error,
119
111
  "Exception while fetching the HTTP request method: "
120
112
  )
@@ -51,13 +51,12 @@ if DependencyHelper.sinatra_present?
51
51
  let(:env) do
52
52
  Rack::MockRequest.env_for("/path", "sinatra.route" => "GET /path", "REQUEST_METHOD" => "GET")
53
53
  end
54
+ let(:appsignal_env) { :default }
54
55
  let(:options) { {} }
55
56
  let(:middleware) { Appsignal::Rack::SinatraBaseInstrumentation.new(app, options) }
56
57
 
57
- before { start_agent }
58
- around do |example|
59
- keep_transactions { example.run }
60
- end
58
+ before { start_agent(:env => appsignal_env) }
59
+ around { |example| keep_transactions { example.run } }
61
60
 
62
61
  describe "#initialize" do
63
62
  context "with no settings method in the Sinatra app" do
@@ -97,7 +96,7 @@ if DependencyHelper.sinatra_present?
97
96
  before { allow(middleware).to receive(:raw_payload).and_return({}) }
98
97
 
99
98
  context "when appsignal is not active" do
100
- before { allow(Appsignal).to receive(:active?).and_return(false) }
99
+ let(:appsignal_env) { :inactive_env }
101
100
 
102
101
  it "does not instrument requests" do
103
102
  expect { make_request }.to_not(change { created_transactions.count })
@@ -0,0 +1,174 @@
1
+ describe Appsignal::SampleData do
2
+ let(:data) { described_class.new(:data_key) }
3
+
4
+ describe "#add" do
5
+ it "sets the given value" do
6
+ data.add(:key1 => "value 1")
7
+
8
+ expect(data.value).to eq(:key1 => "value 1")
9
+ end
10
+
11
+ it "adds the given value with the block being leading" do
12
+ data.add(:key1 => "value 1") { { :key2 => "value 2" } }
13
+
14
+ expect(data.value).to eq(:key2 => "value 2")
15
+ end
16
+
17
+ it "merges multiple values" do
18
+ data.add(:key1 => "value 1")
19
+ data.add(:key2 => "value 2")
20
+
21
+ expect(data.value).to eq(:key1 => "value 1", :key2 => "value 2")
22
+ end
23
+
24
+ it "merges only root level Hash keys" do
25
+ data.add(:key => { :abc => "value" })
26
+ data.add(:key => { :def => "value" })
27
+
28
+ expect(data.value).to eq(:key => { :def => "value" })
29
+ end
30
+
31
+ it "merges values from arguments and blocks" do
32
+ data.add(:key1 => "value 1")
33
+ data.add { { :key2 => "value 2" } }
34
+ data.add(:key3 => "value 3")
35
+
36
+ expect(data.value).to eq(:key1 => "value 1", :key2 => "value 2", :key3 => "value 3")
37
+ end
38
+
39
+ it "merges array values" do
40
+ data.add([:first_arg])
41
+ data.add { [:from_block] }
42
+ data.add([:second_arg])
43
+
44
+ expect(data.value).to eq([:first_arg, :from_block, :second_arg])
45
+ end
46
+
47
+ it "overwrites the value if the new value is of a different type" do
48
+ data.add(:key1 => "value 1")
49
+ expect(data.value).to eq(:key1 => "value 1")
50
+
51
+ data.add(["abc"])
52
+ expect(data.value).to eq(["abc"])
53
+
54
+ logs = capture_logs { data.value }
55
+ expect(logs).to contains_log(
56
+ :warn,
57
+ "The sample data 'data_key' changed type from 'Hash' to 'Array'."
58
+ )
59
+ end
60
+
61
+ it "ignores invalid values" do
62
+ logs = capture_logs { data.add("string") }
63
+ expect(data.value).to be_nil
64
+ expect(logs).to contains_log(
65
+ :error,
66
+ "Sample data 'data_key': Unsupported data type 'String' received: \"string\""
67
+ )
68
+
69
+ set = Set.new
70
+ set.add("abc")
71
+ logs = capture_logs { data.add(set) }
72
+ expect(data.value).to be_nil
73
+ expect(logs).to contains_log(
74
+ :error,
75
+ "Sample data 'data_key': Unsupported data type 'Set' received: #<Set: {\"abc\"}>"
76
+ )
77
+
78
+ instance = Class.new
79
+ logs = capture_logs { data.add(instance) }
80
+ expect(data.value).to be_nil
81
+ expect(logs).to contains_log(
82
+ :error,
83
+ "Sample data 'data_key': Unsupported data type 'Class' received: #<Class:"
84
+ )
85
+ end
86
+
87
+ context "with a type specified" do
88
+ it "only accepts values of Hash type" do
89
+ data = described_class.new(:data_key, Hash)
90
+
91
+ data.add(:key1 => "value 1")
92
+ data.add(["abc"])
93
+ data.add { { :key2 => "value 2" } }
94
+ data.add { ["def"] }
95
+ data.add(:key3 => "value 3")
96
+
97
+ expect(data.value).to eq(:key1 => "value 1", :key2 => "value 2", :key3 => "value 3")
98
+ end
99
+
100
+ it "only accepts values of Array type" do
101
+ data = described_class.new(:data_key, Array)
102
+
103
+ data.add(:key1 => "value 1")
104
+ data.add(["abc"])
105
+ data.add { { :key2 => "value 2" } }
106
+ data.add { ["def"] }
107
+ data.add(:key3 => "value 3")
108
+
109
+ expect(data.value).to eq(["abc", "def"])
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#value" do
115
+ it "caches the block value after calling it once" do
116
+ Appsignal::Testing.store[:block_call] = 0
117
+ data.add do
118
+ Appsignal::Testing.store[:block_call] += 1
119
+ { :key => "value" }
120
+ end
121
+
122
+ expect(data.value).to eq(:key => "value")
123
+ data.value
124
+
125
+ expect(Appsignal::Testing.store[:block_call]).to eq(1)
126
+ end
127
+ end
128
+
129
+ describe "#value?" do
130
+ it "returns true when value is set" do
131
+ data.add(["abc"])
132
+ expect(data.value?).to be_truthy
133
+ end
134
+
135
+ it "returns true when value is set with a block" do
136
+ data.add { ["abc"] }
137
+ expect(data.value?).to be_truthy
138
+ end
139
+
140
+ it "returns false when the value is not set" do
141
+ expect(data.value?).to be_falsey
142
+ end
143
+ end
144
+
145
+ describe "#duplicate" do
146
+ it "duplicates the internal Hash state without modifying the original" do
147
+ data = described_class.new(:my_key, Hash)
148
+ data.add(:abc => :value)
149
+
150
+ duplicate = data.dup
151
+ duplicate.add(:def => :value)
152
+
153
+ expect(data.value).to eq(:abc => :value)
154
+ expect(duplicate.value).to eq(:abc => :value, :def => :value)
155
+
156
+ expect(duplicate.instance_variable_get(:@key)).to eq(:my_key)
157
+ expect(duplicate.instance_variable_get(:@accepted_type)).to eq(Hash)
158
+ end
159
+
160
+ it "duplicates the internal Array state without modifying the original" do
161
+ data = described_class.new(:my_key, Array)
162
+ data.add([:abc])
163
+
164
+ duplicate = data.dup
165
+ duplicate.add([:def])
166
+
167
+ expect(data.value).to eq([:abc])
168
+ expect(duplicate.value).to eq([:abc, :def])
169
+
170
+ expect(duplicate.instance_variable_get(:@key)).to eq(:my_key)
171
+ expect(duplicate.instance_variable_get(:@accepted_type)).to eq(Array)
172
+ end
173
+ end
174
+ end