appsignal 3.10.0-java → 3.12.0-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/.rubocop.yml +1 -1
- data/CHANGELOG.md +197 -0
- data/Gemfile +1 -0
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +204 -130
- data/lib/appsignal/demo.rb +16 -26
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
- data/lib/appsignal/event_formatter.rb +3 -2
- data/lib/appsignal/helpers/instrumentation.rb +331 -19
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +14 -8
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/shoryuken.rb +3 -63
- data/lib/appsignal/integrations/action_cable.rb +5 -7
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
- data/lib/appsignal/integrations/data_mapper.rb +1 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
- data/lib/appsignal/integrations/dry_monitor.rb +1 -0
- data/lib/appsignal/integrations/excon.rb +1 -0
- data/lib/appsignal/integrations/grape.rb +7 -0
- data/lib/appsignal/integrations/hanami.rb +8 -43
- data/lib/appsignal/integrations/http.rb +1 -0
- data/lib/appsignal/integrations/net_http.rb +1 -0
- data/lib/appsignal/integrations/object.rb +6 -0
- data/lib/appsignal/integrations/padrino.rb +8 -73
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +36 -14
- data/lib/appsignal/integrations/rake.rb +1 -5
- data/lib/appsignal/integrations/redis.rb +1 -0
- data/lib/appsignal/integrations/redis_client.rb +1 -0
- data/lib/appsignal/integrations/resque.rb +2 -5
- data/lib/appsignal/integrations/shoryuken.rb +75 -0
- data/lib/appsignal/integrations/sidekiq.rb +7 -15
- data/lib/appsignal/integrations/sinatra.rb +8 -19
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +2 -5
- data/lib/appsignal/loaders/grape.rb +13 -0
- data/lib/appsignal/loaders/hanami.rb +40 -0
- data/lib/appsignal/loaders/padrino.rb +68 -0
- data/lib/appsignal/loaders/sinatra.rb +24 -0
- data/lib/appsignal/loaders.rb +92 -0
- data/lib/appsignal/logger.rb +7 -3
- data/lib/appsignal/probes/helpers.rb +1 -0
- data/lib/appsignal/probes/mri.rb +1 -0
- data/lib/appsignal/probes/sidekiq.rb +1 -0
- data/lib/appsignal/probes.rb +3 -0
- data/lib/appsignal/rack/abstract_middleware.rb +20 -13
- data/lib/appsignal/rack/event_handler.rb +44 -13
- data/lib/appsignal/rack/generic_instrumentation.rb +1 -0
- data/lib/appsignal/rack/grape_middleware.rb +2 -1
- data/lib/appsignal/rack/streaming_listener.rb +1 -0
- data/lib/appsignal/rack.rb +35 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +308 -101
- data/lib/appsignal/utils/data.rb +0 -1
- data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
- data/lib/appsignal/utils/integration_logger.rb +0 -13
- data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
- data/lib/appsignal/utils/json.rb +0 -1
- data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
- data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
- data/lib/appsignal/utils.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +169 -14
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
- data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
- data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
- data/spec/lib/appsignal/config_spec.rb +291 -44
- data/spec/lib/appsignal/demo_spec.rb +1 -2
- data/spec/lib/appsignal/environment_spec.rb +4 -2
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/activejob_spec.rb +12 -3
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
- data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
- data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
- data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
- data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
- data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
- data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
- data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
- data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
- data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
- data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
- data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +15 -13
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +13 -1
- data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
- data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
- data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
- data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
- data/spec/lib/appsignal/loaders_spec.rb +137 -0
- data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
- data/spec/lib/appsignal/probes_spec.rb +6 -5
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +51 -5
- data/spec/lib/appsignal/rack/event_handler_spec.rb +114 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
- data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/span_spec.rb +1 -3
- data/spec/lib/appsignal/transaction_spec.rb +1640 -1075
- data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
- data/spec/lib/appsignal_spec.rb +601 -36
- data/spec/lib/puma/appsignal_spec.rb +0 -3
- data/spec/spec_helper.rb +5 -4
- data/spec/support/helpers/config_helpers.rb +2 -1
- data/spec/support/helpers/loader_helper.rb +21 -0
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
- data/spec/support/testing.rb +47 -1
- metadata +19 -2
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
if DependencyHelper.padrino_present?
|
|
2
|
+
describe "Appsignal::Loaders::PadrinoLoader" do
|
|
3
|
+
before { Appsignal.config = nil }
|
|
4
|
+
|
|
5
|
+
describe "#on_load" do
|
|
6
|
+
it "registers Padrino default config" do
|
|
7
|
+
load_loader(:padrino)
|
|
8
|
+
|
|
9
|
+
expect(Appsignal::Config.loader_defaults).to include([
|
|
10
|
+
:padrino,
|
|
11
|
+
{
|
|
12
|
+
:env => :test,
|
|
13
|
+
:root_path => Padrino.mounted_root
|
|
14
|
+
}
|
|
15
|
+
])
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe "#on_start" do
|
|
20
|
+
let(:callbacks) { { :before_load => nil } }
|
|
21
|
+
before do
|
|
22
|
+
allow(Padrino).to receive(:before_load)
|
|
23
|
+
.and_wrap_original do |original_method, *args, &block|
|
|
24
|
+
callbacks[:before_load] = block
|
|
25
|
+
original_method.call(*args, &block)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
after { uninstall_padrino_integration }
|
|
29
|
+
|
|
30
|
+
def uninstall_padrino_integration
|
|
31
|
+
expected_middleware = [
|
|
32
|
+
Rack::Events,
|
|
33
|
+
Appsignal::Rack::SinatraBaseInstrumentation
|
|
34
|
+
]
|
|
35
|
+
Padrino.middleware.delete_if do |middleware|
|
|
36
|
+
expected_middleware.include?(middleware.first)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "adds the instrumentation middleware to Padrino" do
|
|
41
|
+
load_loader(:padrino)
|
|
42
|
+
start_loader(:padrino)
|
|
43
|
+
|
|
44
|
+
callbacks[:before_load].call
|
|
45
|
+
|
|
46
|
+
middlewares = Padrino.middleware
|
|
47
|
+
expect(middlewares).to include(
|
|
48
|
+
[Rack::Events, [[instance_of(Appsignal::Rack::EventHandler)]], nil]
|
|
49
|
+
)
|
|
50
|
+
expect(middlewares).to include(
|
|
51
|
+
[
|
|
52
|
+
Appsignal::Rack::SinatraBaseInstrumentation,
|
|
53
|
+
[
|
|
54
|
+
:instrument_event_name => "process_action.padrino"
|
|
55
|
+
],
|
|
56
|
+
nil
|
|
57
|
+
]
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe "Padrino integration" do
|
|
63
|
+
class PadrinoClassWithRouter
|
|
64
|
+
include Padrino::Routing
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
let(:base) { double }
|
|
68
|
+
let(:router) { PadrinoClassWithRouter.new }
|
|
69
|
+
let(:env) { {} }
|
|
70
|
+
# TODO: use an instance double
|
|
71
|
+
let(:settings) { double(:name => "TestApp") }
|
|
72
|
+
around { |example| keep_transactions { example.run } }
|
|
73
|
+
before { Appsignal.config = nil }
|
|
74
|
+
|
|
75
|
+
describe "routes" do
|
|
76
|
+
let(:env) do
|
|
77
|
+
{
|
|
78
|
+
"REQUEST_METHOD" => "GET",
|
|
79
|
+
"PATH_INFO" => path,
|
|
80
|
+
"REQUEST_PATH" => path,
|
|
81
|
+
"rack.input" => StringIO.new
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
let(:app) do
|
|
85
|
+
Class.new(Padrino::Application) do
|
|
86
|
+
def self.name
|
|
87
|
+
"PadrinoTestApp"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
let(:response) { app.call(env) }
|
|
92
|
+
|
|
93
|
+
def fetch_body(body)
|
|
94
|
+
if body.respond_to?(:response)
|
|
95
|
+
_, _, nested_body = body.response.to_a
|
|
96
|
+
fetch_body(nested_body)
|
|
97
|
+
elsif body.respond_to?(:to_ary)
|
|
98
|
+
body.to_ary
|
|
99
|
+
else
|
|
100
|
+
body
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
RSpec::Matchers.define :match_response do |expected_status, expected_body|
|
|
105
|
+
match do |response|
|
|
106
|
+
status, _headers, potential_body = response
|
|
107
|
+
body = fetch_body(potential_body)
|
|
108
|
+
|
|
109
|
+
matches_body =
|
|
110
|
+
if expected_body.is_a?(Regexp)
|
|
111
|
+
body.join =~ expected_body
|
|
112
|
+
else
|
|
113
|
+
body == [expected_body].compact
|
|
114
|
+
end
|
|
115
|
+
status == expected_status && matches_body
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
context "when AppSignal is not active" do
|
|
120
|
+
let(:path) { "/foo" }
|
|
121
|
+
before { app.controllers { get(:foo) { "content" } } }
|
|
122
|
+
|
|
123
|
+
it "does not instrument the request" do
|
|
124
|
+
expect do
|
|
125
|
+
expect(response).to match_response(200, "content")
|
|
126
|
+
end.to_not(change { created_transactions.count })
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "when AppSignal is active" do
|
|
131
|
+
let(:transaction) { http_request_transaction }
|
|
132
|
+
before do
|
|
133
|
+
start_agent
|
|
134
|
+
set_current_transaction(transaction)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "with not existing route" do
|
|
138
|
+
let(:path) { "/404" }
|
|
139
|
+
|
|
140
|
+
it "instruments the request" do
|
|
141
|
+
expect(response).to match_response(404, /^GET /404/)
|
|
142
|
+
expect(last_transaction).to have_action("PadrinoTestApp#unknown")
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context "when Sinatra tells us it's a static file" do
|
|
147
|
+
let(:path) { "/static" }
|
|
148
|
+
before do
|
|
149
|
+
env["sinatra.static_file"] = true
|
|
150
|
+
app.controllers { get(:static) { "Static!" } }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "does not instrument the request" do
|
|
154
|
+
expect(response).to match_response(200, "Static!")
|
|
155
|
+
expect(last_transaction).to_not have_action
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Older Padrino versions don't support `action` (v11.0+)
|
|
160
|
+
context "without #action on Sinatra::Request" do
|
|
161
|
+
let(:path) { "/my_original_path/10" }
|
|
162
|
+
before do
|
|
163
|
+
allow_any_instance_of(Sinatra::Request).to receive(:action).and_return(nil)
|
|
164
|
+
app.controllers { get(:my_original_path, :with => :id) { "content" } }
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "falls back on Sinatra::Request#route_obj.original_path" do
|
|
168
|
+
expect(response).to match_response(200, "content")
|
|
169
|
+
expect(last_transaction).to have_action("PadrinoTestApp:/my_original_path/:id")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context "without Sinatra::Request#route_obj.original_path" do
|
|
174
|
+
let(:path) { "/my_original_path" }
|
|
175
|
+
before do
|
|
176
|
+
allow_any_instance_of(Sinatra::Request).to receive(:action).and_return(nil)
|
|
177
|
+
allow_any_instance_of(Sinatra::Request).to receive(:route_obj).and_return(nil)
|
|
178
|
+
app.controllers { get(:my_original_path) { "content" } }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "falls back on app name" do
|
|
182
|
+
expect(response).to match_response(200, "content")
|
|
183
|
+
expect(last_transaction).to have_action("PadrinoTestApp#unknown")
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
context "with existing route" do
|
|
188
|
+
let(:path) { "/" }
|
|
189
|
+
def make_request
|
|
190
|
+
expect(response).to match_response(200, "content")
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
context "with action name as symbol" do
|
|
194
|
+
context "with :index helper" do
|
|
195
|
+
before do
|
|
196
|
+
# :index == "/"
|
|
197
|
+
app.controllers { get(:index) { "content" } }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it "sets the action with the app name and action name" do
|
|
201
|
+
make_request
|
|
202
|
+
expect(last_transaction).to have_action("PadrinoTestApp:#index")
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
context "with custom action name" do
|
|
207
|
+
let(:path) { "/foo" }
|
|
208
|
+
before do
|
|
209
|
+
app.controllers { get(:foo) { "content" } }
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "sets the action with the app name and action name" do
|
|
213
|
+
make_request
|
|
214
|
+
expect(last_transaction).to have_action("PadrinoTestApp:#foo")
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
context "with an action defined with a path" do
|
|
220
|
+
context "with root path" do
|
|
221
|
+
before do
|
|
222
|
+
# :index == "/"
|
|
223
|
+
app.controllers { get("/") { "content" } }
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "sets the action with the app name and action path" do
|
|
227
|
+
make_request
|
|
228
|
+
expect(last_transaction).to have_action("PadrinoTestApp:#/")
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context "with custom path" do
|
|
233
|
+
let(:path) { "/foo" }
|
|
234
|
+
before do
|
|
235
|
+
app.controllers { get("/foo") { "content" } }
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "sets the action with the app name and action path" do
|
|
239
|
+
make_request
|
|
240
|
+
expect(last_transaction).to have_action("PadrinoTestApp:#/foo")
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
context "with controller" do
|
|
246
|
+
let(:path) { "/my_controller" }
|
|
247
|
+
|
|
248
|
+
context "with controller as name" do
|
|
249
|
+
before do
|
|
250
|
+
# :index == "/"
|
|
251
|
+
app.controllers(:my_controller) { get(:index) { "content" } }
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it "sets the action with the app name, controller name and action name" do
|
|
255
|
+
make_request
|
|
256
|
+
expect(last_transaction).to have_action("PadrinoTestApp:my_controller#index")
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
context "with controller as path" do
|
|
261
|
+
before do
|
|
262
|
+
# :index == "/"
|
|
263
|
+
app.controllers("/my_controller") { get(:index) { "content" } }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
it "sets the action with the app name, controller name and action path" do
|
|
267
|
+
make_request
|
|
268
|
+
expect(last_transaction).to have_action("PadrinoTestApp:/my_controller#index")
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
if DependencyHelper.sinatra_present?
|
|
2
|
+
describe "Appsignal::Loaders::SinatraLoader" do
|
|
3
|
+
before { Appsignal.config = nil }
|
|
4
|
+
|
|
5
|
+
describe "#on_load" do
|
|
6
|
+
it "registers Sinatra default config" do
|
|
7
|
+
::Sinatra::Application.settings.root = "/some/path"
|
|
8
|
+
load_loader(:sinatra)
|
|
9
|
+
|
|
10
|
+
expect(Appsignal::Config.loader_defaults).to include([
|
|
11
|
+
:sinatra,
|
|
12
|
+
{
|
|
13
|
+
:env => :test,
|
|
14
|
+
:root_path => "/some/path"
|
|
15
|
+
}
|
|
16
|
+
])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#on_start" do
|
|
21
|
+
after { uninstall_sinatra_integration }
|
|
22
|
+
|
|
23
|
+
def uninstall_sinatra_integration
|
|
24
|
+
expected_middleware = [
|
|
25
|
+
Rack::Events,
|
|
26
|
+
Appsignal::Rack::SinatraBaseInstrumentation
|
|
27
|
+
]
|
|
28
|
+
Sinatra::Base.instance_variable_get(:@middleware).delete_if do |middleware|
|
|
29
|
+
expected_middleware.include?(middleware.first)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "adds the instrumentation middleware to Sinatra::Base" do
|
|
34
|
+
load_loader(:sinatra)
|
|
35
|
+
start_loader(:sinatra)
|
|
36
|
+
|
|
37
|
+
middlewares = Sinatra::Base.middleware.to_a
|
|
38
|
+
expect(middlewares).to include(
|
|
39
|
+
[Rack::Events, [[instance_of(Appsignal::Rack::EventHandler)]], nil]
|
|
40
|
+
)
|
|
41
|
+
expect(middlewares).to include(
|
|
42
|
+
[Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
describe Appsignal::Loaders do
|
|
2
|
+
describe ".register" do
|
|
3
|
+
before do
|
|
4
|
+
define_loader(:test_loader) do
|
|
5
|
+
def on_load
|
|
6
|
+
puts "do something on_load"
|
|
7
|
+
register_config_defaults(
|
|
8
|
+
:root_path => "/some/path",
|
|
9
|
+
:env => "test env",
|
|
10
|
+
:active => false
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "registers a loader" do
|
|
17
|
+
define_loader(:test_loader)
|
|
18
|
+
expect(Appsignal::Loaders.loaders).to have_key(:test_loader)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe ".unregister" do
|
|
23
|
+
it "unregisters a loader" do
|
|
24
|
+
define_loader(:test_loader)
|
|
25
|
+
expect(Appsignal::Loaders.loaders).to have_key(:test_loader)
|
|
26
|
+
|
|
27
|
+
Appsignal::Loaders.unregister(:test_loader)
|
|
28
|
+
expect(Appsignal::Loaders.loaders).to_not have_key(:test_loader)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe ".load" do
|
|
33
|
+
it "calls the Loader's on_loader method" do
|
|
34
|
+
Appsignal::Testing.store[:loader_loaded] = 0
|
|
35
|
+
define_loader(:test_loader) do
|
|
36
|
+
def on_load
|
|
37
|
+
Appsignal::Testing.store[:loader_loaded] += 1
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
Appsignal::Loaders.load(:test_loader)
|
|
41
|
+
|
|
42
|
+
expect(Appsignal::Testing.store[:loader_loaded]).to eq(1)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "registers config defaults" do
|
|
46
|
+
define_loader(:test_loader) do
|
|
47
|
+
def on_load
|
|
48
|
+
register_config_defaults(:my_option => true)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
Appsignal::Loaders.load(:test_loader)
|
|
52
|
+
|
|
53
|
+
expect(Appsignal::Config.loader_defaults).to eq([[:test_loader, { :my_option => true }]])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "does not load errors that aren't registered" do
|
|
57
|
+
logs =
|
|
58
|
+
capture_logs do
|
|
59
|
+
Appsignal::Loaders.load(:unknown_loader)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
expect(logs).to contains_log(:warn, "No loader found with the name 'unknown_loader'.")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "loads the loader file on load" do
|
|
66
|
+
expect(Appsignal::Loaders.registered?(:loader_stub)).to be_falsy
|
|
67
|
+
Appsignal::Loaders.load(:loader_stub)
|
|
68
|
+
|
|
69
|
+
expect(Appsignal::Loaders.registered?(:loader_stub)).to be_truthy
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "does not error when a loader has no on_load method" do
|
|
73
|
+
define_loader(:test_loader) do
|
|
74
|
+
# Do nothing
|
|
75
|
+
end
|
|
76
|
+
Appsignal::Loaders.load(:test_loader)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "logs an error when an error occurs on load" do
|
|
80
|
+
define_loader(:test_loader) do
|
|
81
|
+
def on_load
|
|
82
|
+
raise ExampleStandardError, "uh oh"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
logs =
|
|
86
|
+
capture_logs do
|
|
87
|
+
Appsignal::Loaders.load(:test_loader)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
expect(logs).to contains_log(
|
|
91
|
+
:error,
|
|
92
|
+
"An error occurred while loading the 'test_loader' loader: ExampleStandardError: uh oh"
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe ".start" do
|
|
98
|
+
it "starts all loaded loaders" do
|
|
99
|
+
Appsignal::Testing.store[:loader_started] = 0
|
|
100
|
+
define_loader(:test_loader) do
|
|
101
|
+
def on_start
|
|
102
|
+
Appsignal::Testing.store[:loader_started] += 1
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
Appsignal::Loaders.load(:test_loader)
|
|
106
|
+
Appsignal::Loaders.start
|
|
107
|
+
|
|
108
|
+
expect(Appsignal::Testing.store[:loader_started]).to eq(1)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "does not error when a loader has no on_start method" do
|
|
112
|
+
define_loader(:test_loader) do
|
|
113
|
+
# Do nothing
|
|
114
|
+
end
|
|
115
|
+
Appsignal::Loaders.load(:test_loader)
|
|
116
|
+
Appsignal::Loaders.start
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "logs an error when an error occurs on start" do
|
|
120
|
+
define_loader(:test_loader) do
|
|
121
|
+
def on_start
|
|
122
|
+
raise ExampleStandardError, "uh oh"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
logs =
|
|
126
|
+
capture_logs do
|
|
127
|
+
Appsignal::Loaders.load(:test_loader)
|
|
128
|
+
Appsignal::Loaders.start
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
expect(logs).to contains_log(
|
|
132
|
+
:error,
|
|
133
|
+
"An error occurred while starting the 'test_loader' loader: ExampleStandardError: uh oh"
|
|
134
|
+
)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -408,13 +408,14 @@ describe Appsignal::Probes do
|
|
|
408
408
|
end
|
|
409
409
|
|
|
410
410
|
context "logger" do
|
|
411
|
-
|
|
412
|
-
let(:log) { log_contents(log_stream) }
|
|
411
|
+
before { start_agent }
|
|
413
412
|
|
|
414
|
-
around { |example| use_logger_with(log_stream) { example.run } }
|
|
415
413
|
it "logs a deprecation message" do
|
|
416
|
-
|
|
417
|
-
|
|
414
|
+
logs =
|
|
415
|
+
capture_logs do
|
|
416
|
+
silence { collection.register :my_probe, lambda {} }
|
|
417
|
+
end
|
|
418
|
+
expect(logs).to contains_log :warn,
|
|
418
419
|
"The method 'Appsignal::Probes.probes.register' is deprecated. " \
|
|
419
420
|
"Use 'Appsignal::Probes.register' instead."
|
|
420
421
|
end
|
|
@@ -5,13 +5,14 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
5
5
|
Rack::MockRequest.env_for(
|
|
6
6
|
request_path,
|
|
7
7
|
"REQUEST_METHOD" => "GET",
|
|
8
|
-
:params => { "page" => 2, "query" => "lorem" }
|
|
8
|
+
:params => { "page" => 2, "query" => "lorem" },
|
|
9
|
+
"rack.session" => { "session" => "data", "user_id" => 123 }
|
|
9
10
|
)
|
|
10
11
|
end
|
|
11
12
|
let(:options) { {} }
|
|
12
13
|
let(:middleware) { described_class.new(app, options) }
|
|
13
14
|
|
|
14
|
-
before
|
|
15
|
+
before { start_agent }
|
|
15
16
|
around { |example| keep_transactions { example.run } }
|
|
16
17
|
|
|
17
18
|
def make_request
|
|
@@ -247,7 +248,7 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
247
248
|
end
|
|
248
249
|
end
|
|
249
250
|
|
|
250
|
-
context "
|
|
251
|
+
context "when fetching the request method raises an error" do
|
|
251
252
|
class BrokenRequestMethodRequest < Rack::Request
|
|
252
253
|
def request_method
|
|
253
254
|
raise "uh oh!"
|
|
@@ -255,11 +256,16 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
255
256
|
end
|
|
256
257
|
|
|
257
258
|
let(:options) { { :request_class => BrokenRequestMethodRequest } }
|
|
259
|
+
|
|
258
260
|
it "does not store the invalid HTTP request method" do
|
|
259
261
|
env["REQUEST_METHOD"] = "FOO"
|
|
260
|
-
make_request
|
|
262
|
+
logs = capture_logs { make_request }
|
|
261
263
|
|
|
262
264
|
expect(last_transaction).to_not include_metadata("method" => anything)
|
|
265
|
+
expect(logs).to contains_log(
|
|
266
|
+
:error,
|
|
267
|
+
"Exception while fetching the HTTP request method: RuntimeError: uh oh"
|
|
268
|
+
)
|
|
263
269
|
end
|
|
264
270
|
end
|
|
265
271
|
|
|
@@ -285,6 +291,35 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
285
291
|
expect(last_transaction).to include_params("custom" => "param")
|
|
286
292
|
end
|
|
287
293
|
end
|
|
294
|
+
|
|
295
|
+
context "when fetching the request method raises an error" do
|
|
296
|
+
class BrokenRequestParamsRequest < Rack::Request
|
|
297
|
+
def params
|
|
298
|
+
raise "uh oh!"
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
let(:options) do
|
|
303
|
+
{ :request_class => BrokenRequestParamsRequest, :params_method => :params }
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it "does not store the invalid HTTP request method" do
|
|
307
|
+
logs = capture_logs { make_request }
|
|
308
|
+
|
|
309
|
+
expect(last_transaction).to_not include_params
|
|
310
|
+
expect(logs).to contains_log(
|
|
311
|
+
:error,
|
|
312
|
+
"Exception while fetching params " \
|
|
313
|
+
"from 'BrokenRequestParamsRequest#params': RuntimeError uh oh!"
|
|
314
|
+
)
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it "sets session data" do
|
|
319
|
+
make_request
|
|
320
|
+
|
|
321
|
+
expect(last_transaction).to include_session_data("session" => "data", "user_id" => 123)
|
|
322
|
+
end
|
|
288
323
|
end
|
|
289
324
|
|
|
290
325
|
context "with queue start header" do
|
|
@@ -316,6 +351,10 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
316
351
|
def filtered_params
|
|
317
352
|
{ "abc" => "123" }
|
|
318
353
|
end
|
|
354
|
+
|
|
355
|
+
def session
|
|
356
|
+
{ "data" => "value" }
|
|
357
|
+
end
|
|
319
358
|
end
|
|
320
359
|
|
|
321
360
|
context "with overridden request class and params method" do
|
|
@@ -328,6 +367,12 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
328
367
|
|
|
329
368
|
expect(last_transaction).to include_params("abc" => "123")
|
|
330
369
|
end
|
|
370
|
+
|
|
371
|
+
it "uses the overridden request class to fetch session data" do
|
|
372
|
+
make_request
|
|
373
|
+
|
|
374
|
+
expect(last_transaction).to include_session_data("data" => "value")
|
|
375
|
+
end
|
|
331
376
|
end
|
|
332
377
|
|
|
333
378
|
context "with parent instrumentation" do
|
|
@@ -355,11 +400,12 @@ describe Appsignal::Rack::AbstractMiddleware do
|
|
|
355
400
|
expect(response_events).to eq(1)
|
|
356
401
|
end
|
|
357
402
|
|
|
358
|
-
context "when response body is already
|
|
403
|
+
context "when the response body is already instrumented" do
|
|
359
404
|
let(:body) { Appsignal::Rack::BodyWrapper.wrap(["hello!"], transaction) }
|
|
360
405
|
let(:app) { DummyApp.new { [200, {}, body] } }
|
|
361
406
|
|
|
362
407
|
it "doesn't wrap the body again" do
|
|
408
|
+
env[Appsignal::Rack::APPSIGNAL_RESPONSE_INSTRUMENTED] = true
|
|
363
409
|
_status, _headers, body = make_request
|
|
364
410
|
expect(body).to eq(body)
|
|
365
411
|
|