appsignal 1.4.0.beta.1 → 2.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -17
- data/README.md +6 -5
- data/ext/agent.yml +11 -11
- data/lib/appsignal.rb +20 -19
- data/lib/appsignal/cli.rb +5 -7
- data/lib/appsignal/cli/diagnose.rb +133 -41
- data/lib/appsignal/cli/notify_of_deploy.rb +26 -11
- data/lib/appsignal/config.rb +9 -5
- data/lib/appsignal/integrations/grape.rb +23 -16
- data/lib/appsignal/js_exception_transaction.rb +3 -3
- data/lib/appsignal/marker.rb +4 -3
- data/lib/appsignal/rack/js_exception_catcher.rb +11 -4
- data/lib/appsignal/utils.rb +0 -12
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/capistrano2_spec.rb +7 -7
- data/spec/lib/appsignal/capistrano3_spec.rb +7 -7
- data/spec/lib/appsignal/cli/diagnose_spec.rb +329 -22
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +144 -96
- data/spec/lib/appsignal/cli_spec.rb +1 -18
- data/spec/lib/appsignal/config_spec.rb +27 -2
- data/spec/lib/appsignal/hooks/rake_spec.rb +35 -52
- data/spec/lib/appsignal/integrations/grape_spec.rb +172 -63
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +76 -36
- data/spec/lib/appsignal/marker_spec.rb +5 -5
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +49 -9
- data/spec/lib/appsignal_spec.rb +18 -7
- data/spec/support/helpers/cli_helpers.rb +17 -0
- data/spec/support/helpers/env_helpers.rb +2 -1
- metadata +5 -6
- data/lib/appsignal/params_sanitizer.rb +0 -13
- data/lib/tasks/diag.rake +0 -79
@@ -1,92 +1,201 @@
|
|
1
1
|
if DependencyHelper.grape_present?
|
2
|
-
require
|
2
|
+
require "appsignal/integrations/grape"
|
3
3
|
|
4
4
|
describe Appsignal::Grape::Middleware do
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
let(:app) do
|
6
|
+
Class.new(::Grape::API) do
|
7
|
+
format :json
|
8
|
+
post :ping do
|
9
|
+
{ :message => "Hello world!" }
|
10
|
+
end
|
11
|
+
end
|
8
12
|
end
|
9
|
-
|
10
|
-
let(:app) { double(:call => true) }
|
11
|
-
let(:api_endpoint) { double(:options => options) }
|
12
|
-
let(:options) { {
|
13
|
-
:for => 'Api::PostPut',
|
14
|
-
:method => ['POST'],
|
15
|
-
:path => ['ping']
|
16
|
-
}}
|
13
|
+
let(:api_endpoint) { app.endpoints.first }
|
17
14
|
let(:env) do
|
18
|
-
http_request_env_with_data
|
15
|
+
http_request_env_with_data \
|
16
|
+
"api.endpoint" => api_endpoint,
|
17
|
+
"REQUEST_METHOD" => "POST",
|
18
|
+
:path => "/ping"
|
19
|
+
end
|
20
|
+
let(:middleware) { Appsignal::Grape::Middleware.new(api_endpoint) }
|
21
|
+
around do |example|
|
22
|
+
GrapeExample = Module.new
|
23
|
+
GrapeExample.send(:const_set, :Api, app)
|
24
|
+
example.run
|
25
|
+
Object.send(:remove_const, :GrapeExample)
|
19
26
|
end
|
20
|
-
let(:middleware) { Appsignal::Grape::Middleware.new(app) }
|
21
27
|
|
22
28
|
describe "#call" do
|
23
|
-
context "when
|
24
|
-
before
|
29
|
+
context "when AppSignal is not active" do
|
30
|
+
before(:all) do
|
31
|
+
Appsignal.config = nil
|
32
|
+
Appsignal::Hooks.load_hooks
|
33
|
+
end
|
25
34
|
|
26
|
-
it "
|
27
|
-
expect(
|
35
|
+
it "creates no transaction" do
|
36
|
+
expect(Appsignal::Transaction).to_not receive(:create)
|
28
37
|
end
|
29
|
-
end
|
30
38
|
|
31
|
-
|
32
|
-
|
39
|
+
it "calls the endpoint normally" do
|
40
|
+
expect(api_endpoint).to receive(:call).with(env)
|
41
|
+
end
|
33
42
|
|
34
|
-
|
35
|
-
|
43
|
+
after { middleware.call(env) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when AppSignal is active" do
|
47
|
+
let(:transaction) { http_request_transaction }
|
48
|
+
before :all do
|
49
|
+
Appsignal.config = project_fixture_config
|
50
|
+
expect(Appsignal.active?).to be_true
|
51
|
+
end
|
52
|
+
before do
|
53
|
+
expect(Appsignal::Transaction).to receive(:create).with(
|
54
|
+
kind_of(String),
|
55
|
+
Appsignal::Transaction::HTTP_REQUEST,
|
56
|
+
kind_of(::Rack::Request)
|
57
|
+
).and_return(transaction)
|
36
58
|
end
|
37
59
|
|
38
|
-
|
39
|
-
|
60
|
+
context "without error" do
|
61
|
+
it "calls the endpoint" do
|
62
|
+
expect(api_endpoint).to receive(:call).with(env)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "sets metadata" do
|
66
|
+
expect(transaction).to receive(:set_http_or_background_queue_start)
|
67
|
+
expect(transaction).to receive(:set_action).with("POST::GrapeExample::Api#/ping")
|
68
|
+
expect(transaction).to receive(:set_metadata).with("path", "/ping")
|
69
|
+
expect(transaction).to receive(:set_metadata).with("method", "POST")
|
70
|
+
end
|
71
|
+
|
72
|
+
after { middleware.call(env) }
|
40
73
|
end
|
41
|
-
end
|
42
74
|
|
43
|
-
|
44
|
-
|
75
|
+
context "with error" do
|
76
|
+
let(:app) do
|
77
|
+
Class.new(::Grape::API) do
|
78
|
+
format :json
|
79
|
+
post :ping do
|
80
|
+
raise VerySpecificError
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
45
84
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
Appsignal::Transaction::HTTP_REQUEST,
|
53
|
-
kind_of(::Rack::Request)
|
54
|
-
).and_return(
|
55
|
-
double(
|
56
|
-
:set_action => nil,
|
57
|
-
:set_http_or_background_queue_start => nil,
|
58
|
-
:set_metadata => nil
|
59
|
-
)
|
60
|
-
)
|
61
|
-
end
|
85
|
+
it "sets metadata" do
|
86
|
+
expect(transaction).to receive(:set_http_or_background_queue_start)
|
87
|
+
expect(transaction).to receive(:set_action).with("POST::GrapeExample::Api#/ping")
|
88
|
+
expect(transaction).to receive(:set_metadata).with("path", "/ping")
|
89
|
+
expect(transaction).to receive(:set_metadata).with("method", "POST")
|
90
|
+
end
|
62
91
|
|
63
|
-
|
64
|
-
|
65
|
-
|
92
|
+
it "sets the error" do
|
93
|
+
expect(transaction).to receive(:set_error).with(kind_of(VerySpecificError))
|
94
|
+
end
|
66
95
|
|
67
|
-
|
68
|
-
|
69
|
-
let(:app) do
|
70
|
-
double.tap do |d|
|
71
|
-
d.stub(:call).and_raise(error)
|
96
|
+
after do
|
97
|
+
expect { middleware.call(env) }.to raise_error VerySpecificError
|
72
98
|
end
|
73
99
|
end
|
74
100
|
|
75
|
-
|
76
|
-
|
101
|
+
context "with route_param" do
|
102
|
+
let(:app) do
|
103
|
+
Class.new(::Grape::API) do
|
104
|
+
format :json
|
105
|
+
resource :users do
|
106
|
+
route_param :id do
|
107
|
+
get do
|
108
|
+
{ :name => "Tom" }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
let(:env) do
|
115
|
+
http_request_env_with_data \
|
116
|
+
"api.endpoint" => api_endpoint,
|
117
|
+
"REQUEST_METHOD" => "GET",
|
118
|
+
:path => ""
|
119
|
+
end
|
120
|
+
|
121
|
+
it "sets non-unique route_param path" do
|
122
|
+
expect(transaction).to receive(:set_action).with("GET::GrapeExample::Api#/users/:id/")
|
123
|
+
expect(transaction).to receive(:set_metadata).with("path", "/users/:id/")
|
124
|
+
expect(transaction).to receive(:set_metadata).with("method", "GET")
|
125
|
+
end
|
126
|
+
|
127
|
+
after { middleware.call(env) }
|
77
128
|
end
|
78
|
-
end
|
79
129
|
|
80
|
-
|
81
|
-
|
82
|
-
|
130
|
+
context "with namespaced path" do
|
131
|
+
context "with symbols" do
|
132
|
+
let(:app) do
|
133
|
+
Class.new(::Grape::API) do
|
134
|
+
format :json
|
135
|
+
namespace :v1 do
|
136
|
+
namespace :beta do
|
137
|
+
post :ping do
|
138
|
+
{ :message => "Hello namespaced world!" }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "sets namespaced path" do
|
146
|
+
expect(transaction).to receive(:set_action).with("POST::GrapeExample::Api#/v1/beta/ping")
|
147
|
+
expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
|
148
|
+
expect(transaction).to receive(:set_metadata).with("method", "POST")
|
149
|
+
end
|
150
|
+
end
|
83
151
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
152
|
+
context "with strings" do
|
153
|
+
context "without / prefix" do
|
154
|
+
let(:app) do
|
155
|
+
Class.new(::Grape::API) do
|
156
|
+
format :json
|
157
|
+
namespace "v1" do
|
158
|
+
namespace "beta" do
|
159
|
+
post "ping" do
|
160
|
+
{ :message => "Hello namespaced world!" }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
it "sets namespaced path" do
|
168
|
+
expect(transaction).to receive(:set_action).with("POST::GrapeExample::Api#/v1/beta/ping")
|
169
|
+
expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
|
170
|
+
expect(transaction).to receive(:set_metadata).with("method", "POST")
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "with / prefix" do
|
175
|
+
let(:app) do
|
176
|
+
Class.new(::Grape::API) do
|
177
|
+
format :json
|
178
|
+
namespace "/v1" do
|
179
|
+
namespace "/beta" do
|
180
|
+
post "/ping" do
|
181
|
+
{ :message => "Hello namespaced world!" }
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "sets namespaced path" do
|
189
|
+
expect(transaction).to receive(:set_action).with("POST::GrapeExample::Api#/v1/beta/ping")
|
190
|
+
expect(transaction).to receive(:set_metadata).with("path", "/v1/beta/ping")
|
191
|
+
expect(transaction).to receive(:set_metadata).with("method", "POST")
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
88
195
|
|
89
|
-
|
196
|
+
after { middleware.call(env) }
|
197
|
+
end
|
198
|
+
end
|
90
199
|
end
|
91
200
|
end
|
92
201
|
end
|
@@ -21,22 +21,22 @@ describe Appsignal::JSExceptionTransaction do
|
|
21
21
|
|
22
22
|
describe "#initialize" do
|
23
23
|
it "should call all required methods" do
|
24
|
-
expect(
|
24
|
+
expect(Appsignal::Extension).to receive(:start_transaction).with('123abc', 'frontend', 0).and_return(1)
|
25
25
|
|
26
|
-
expect(
|
27
|
-
expect(
|
28
|
-
expect(
|
29
|
-
expect(
|
26
|
+
expect(transaction).to receive(:set_action)
|
27
|
+
expect(transaction).to receive(:set_metadata)
|
28
|
+
expect(transaction).to receive(:set_error)
|
29
|
+
expect(transaction).to receive(:set_sample_data)
|
30
30
|
|
31
31
|
transaction.send :initialize, data
|
32
32
|
|
33
|
-
expect(
|
33
|
+
expect(transaction.ext).to_not be_nil
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
describe "#
|
38
|
-
it "should call `Appsignal::Extension.
|
39
|
-
expect(
|
37
|
+
describe "#set_action" do
|
38
|
+
it "should call `Appsignal::Extension.set_action`" do
|
39
|
+
expect(transaction.ext).to receive(:set_action).with(
|
40
40
|
'ExceptionIncidentComponent'
|
41
41
|
)
|
42
42
|
|
@@ -45,43 +45,83 @@ describe Appsignal::JSExceptionTransaction do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
describe "#set_metadata" do
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
it "should call `Appsignal::Extension.set_transaction_metadata`" do
|
49
|
+
expect(transaction.ext).to receive(:set_metadata).with(
|
50
|
+
'path',
|
51
|
+
'foo.bar/moo'
|
52
|
+
)
|
53
|
+
|
54
|
+
transaction.set_metadata
|
55
|
+
end
|
56
56
|
end
|
57
57
|
|
58
58
|
describe "#set_error" do
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
59
|
+
it "should call `Appsignal::Extension.set_transaction_error`" do
|
60
|
+
expect(transaction.ext).to receive(:set_error).with(
|
61
|
+
'TypeError',
|
62
|
+
'foo is not a valid method',
|
63
|
+
Appsignal::Utils.data_generate(['foo.bar/js:11:1', 'foo.bar/js:22:2'])
|
64
|
+
)
|
65
|
+
|
66
|
+
transaction.set_error
|
67
|
+
end
|
68
68
|
end
|
69
69
|
|
70
70
|
describe "#set_sample_data" do
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
it "should call `Appsignal::Extension.set_transaction_error_data`" do
|
72
|
+
expect(transaction.ext).to receive(:set_sample_data).with(
|
73
|
+
'tags',
|
74
|
+
Appsignal::Utils.data_generate(['tag1'])
|
75
|
+
)
|
76
|
+
|
77
|
+
transaction.set_sample_data
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when sending just the name" do
|
82
|
+
let(:data) { {'name' => 'TypeError'} }
|
83
|
+
|
84
|
+
describe "#set_action" do
|
85
|
+
it "should not call `Appsignal::Extension.set_action`" do
|
86
|
+
expect(transaction.ext).to_not receive(:set_action)
|
87
|
+
|
88
|
+
transaction.set_action
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#set_metadata" do
|
93
|
+
it "should not call `Appsignal::Extension.set_transaction_metadata`" do
|
94
|
+
expect(transaction.ext).to_not receive(:set_metadata)
|
95
|
+
|
96
|
+
transaction.set_metadata
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#set_error" do
|
101
|
+
it "should call `Appsignal::Extension.set_transaction_error` with just the name" do
|
102
|
+
expect(transaction.ext).to receive(:set_error).with(
|
103
|
+
'TypeError',
|
104
|
+
'',
|
105
|
+
Appsignal::Utils.data_generate([])
|
106
|
+
)
|
107
|
+
|
108
|
+
transaction.set_error
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#set_sample_data" do
|
113
|
+
it "should not call `Appsignal::Extension.set_transaction_error_data`" do
|
114
|
+
expect(transaction.ext).to_not receive(:set_sample_data)
|
115
|
+
|
116
|
+
transaction.set_sample_data
|
117
|
+
end
|
118
|
+
end
|
79
119
|
end
|
80
120
|
|
81
121
|
describe "#complete!" do
|
82
122
|
it "should call all required methods" do
|
83
|
-
expect(
|
84
|
-
expect(
|
123
|
+
expect(transaction.ext).to receive(:finish)
|
124
|
+
expect(transaction.ext).to receive(:complete)
|
85
125
|
transaction.complete!
|
86
126
|
end
|
87
127
|
end
|
@@ -30,8 +30,8 @@ describe Appsignal::Marker do
|
|
30
30
|
it "outputs success" do
|
31
31
|
output = out_stream.string
|
32
32
|
expect(output).to include \
|
33
|
-
'Notifying
|
34
|
-
'
|
33
|
+
'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
|
34
|
+
'AppSignal has been notified of this deploy!'
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -44,11 +44,11 @@ describe Appsignal::Marker do
|
|
44
44
|
it "outputs failure" do
|
45
45
|
output = out_stream.string
|
46
46
|
expect(output).to include \
|
47
|
-
'Notifying
|
48
|
-
"Something went wrong while trying to notify
|
47
|
+
'Notifying AppSignal of deploy with: revision: 503ce0923ed177a3ce000005, user: batman',
|
48
|
+
"Something went wrong while trying to notify AppSignal: 500 at "\
|
49
49
|
"#{config[:endpoint]}/1/markers"
|
50
50
|
expect(output).to_not include \
|
51
|
-
'
|
51
|
+
'AppSignal has been notified of this deploy!'
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -12,7 +12,7 @@ describe Appsignal::Rack::JSExceptionCatcher do
|
|
12
12
|
|
13
13
|
describe "#initialize" do
|
14
14
|
it "should log to the logger" do
|
15
|
-
expect(
|
15
|
+
expect(Appsignal.logger).to receive(:debug)
|
16
16
|
.with('Initializing Appsignal::Rack::JSExceptionCatcher')
|
17
17
|
|
18
18
|
Appsignal::Rack::JSExceptionCatcher.new(app, options)
|
@@ -26,7 +26,7 @@ describe Appsignal::Rack::JSExceptionCatcher do
|
|
26
26
|
let(:env) { {'PATH_INFO' => '/foo'} }
|
27
27
|
|
28
28
|
it "should call the next middleware" do
|
29
|
-
expect(
|
29
|
+
expect(app).to receive(:call).with(env)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -35,16 +35,23 @@ describe Appsignal::Rack::JSExceptionCatcher do
|
|
35
35
|
let(:env) do
|
36
36
|
{
|
37
37
|
'PATH_INFO' => '/appsignal_error_catcher',
|
38
|
-
'rack.input' => double(:read => '{"
|
38
|
+
'rack.input' => double(:read => '{"name": "error"}')
|
39
39
|
}
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should create a JSExceptionTransaction" do
|
43
|
-
expect(
|
44
|
-
.with({'
|
43
|
+
expect(Appsignal::JSExceptionTransaction).to receive(:new)
|
44
|
+
.with({'name' => 'error'})
|
45
45
|
.and_return(transaction)
|
46
46
|
|
47
|
-
expect(
|
47
|
+
expect(transaction).to receive(:complete!)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return 200" do
|
51
|
+
allow( Appsignal::JSExceptionTransaction).to receive(:new)
|
52
|
+
.and_return(transaction)
|
53
|
+
|
54
|
+
expect(catcher.call(env)).to eql([200, {}, []])
|
48
55
|
end
|
49
56
|
|
50
57
|
context "when `frontend_error_catching_path` is different" do
|
@@ -55,16 +62,49 @@ describe Appsignal::Rack::JSExceptionCatcher do
|
|
55
62
|
end
|
56
63
|
|
57
64
|
it "should not create a transaction" do
|
58
|
-
expect(
|
65
|
+
expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
|
59
66
|
end
|
60
67
|
|
61
68
|
it "should call the next middleware" do
|
62
|
-
expect(
|
69
|
+
expect(app).to receive(:call).with(env)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when `name` is empty" do
|
74
|
+
let(:env) do
|
75
|
+
{
|
76
|
+
'PATH_INFO' => '/appsignal_error_catcher',
|
77
|
+
'rack.input' => double(:read => '{"name": ""}')
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not create a transaction" do
|
82
|
+
expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return 422" do
|
86
|
+
expect(catcher.call(env)).to eql([422, {}, []])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when `name` doesn't exist" do
|
91
|
+
let(:env) do
|
92
|
+
{
|
93
|
+
'PATH_INFO' => '/appsignal_error_catcher',
|
94
|
+
'rack.input' => double(:read => '{"foo": ""}')
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should not create a transaction" do
|
99
|
+
expect(Appsignal::JSExceptionTransaction).to_not receive(:new)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return 422" do
|
103
|
+
expect(catcher.call(env)).to eql([422, {}, []])
|
63
104
|
end
|
64
105
|
end
|
65
106
|
end
|
66
107
|
|
67
108
|
after { catcher.call(env) }
|
68
109
|
end
|
69
|
-
|
70
110
|
end
|