appsignal 0.4.7 → 0.5.0
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.
- data/.ruby-version +1 -0
- data/README.md +20 -19
- data/appsignal.gemspec +2 -2
- data/lib/appsignal.rb +41 -18
- data/lib/appsignal/agent.rb +28 -54
- data/lib/appsignal/aggregator.rb +65 -0
- data/lib/appsignal/aggregator/post_processor.rb +27 -0
- data/lib/appsignal/config.rb +9 -4
- data/lib/appsignal/listener.rb +30 -0
- data/lib/appsignal/middleware.rb +4 -30
- data/lib/appsignal/middleware/action_view_sanitizer.rb +21 -0
- data/lib/appsignal/middleware/active_record_sanitizer.rb +60 -0
- data/lib/appsignal/middleware/chain.rb +99 -0
- data/lib/appsignal/middleware/delete_blanks.rb +12 -0
- data/lib/appsignal/railtie.rb +9 -1
- data/lib/appsignal/to_appsignal_hash.rb +23 -0
- data/lib/appsignal/transaction.rb +72 -16
- data/lib/appsignal/transaction/params_sanitizer.rb +91 -13
- data/lib/appsignal/transaction/transaction_formatter.rb +32 -68
- data/lib/appsignal/version.rb +1 -1
- data/spec/appsignal/agent_spec.rb +46 -156
- data/spec/appsignal/aggregator/post_processor_spec.rb +84 -0
- data/spec/appsignal/aggregator_spec.rb +182 -0
- data/spec/appsignal/inactive_railtie_spec.rb +2 -1
- data/spec/appsignal/{middleware_spec.rb → listener_spec.rb} +2 -2
- data/spec/appsignal/middleware/action_view_sanitizer_spec.rb +27 -0
- data/spec/appsignal/middleware/active_record_sanitizer_spec.rb +201 -0
- data/spec/appsignal/middleware/chain_spec.rb +168 -0
- data/spec/appsignal/middleware/delete_blanks_spec.rb +37 -0
- data/spec/appsignal/railtie_spec.rb +47 -34
- data/spec/appsignal/to_appsignal_hash_spec.rb +29 -0
- data/spec/appsignal/transaction/params_sanitizer_spec.rb +141 -36
- data/spec/appsignal/transaction/transaction_formatter_spec.rb +60 -155
- data/spec/appsignal/transaction_spec.rb +186 -53
- data/spec/appsignal/transmitter_spec.rb +11 -6
- data/spec/appsignal_spec.rb +33 -0
- data/spec/spec_helper.rb +9 -62
- data/spec/support/helpers/notification_helpers.rb +30 -0
- data/spec/support/helpers/transaction_helpers.rb +64 -0
- metadata +74 -63
- data/.rvmrc +0 -1
- data/lib/appsignal/transaction/faulty_request_formatter.rb +0 -30
- data/lib/appsignal/transaction/regular_request_formatter.rb +0 -11
- data/lib/appsignal/transaction/slow_request_formatter.rb +0 -34
- data/spec/appsignal/transaction/faulty_request_formatter_spec.rb +0 -49
- data/spec/appsignal/transaction/regular_request_formatter_spec.rb +0 -14
- data/spec/appsignal/transaction/slow_request_formatter_spec.rb +0 -76
@@ -39,18 +39,17 @@ describe Appsignal::Transaction do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
describe '#set_process_action_event' do
|
42
|
-
let(:process_action_event) {
|
42
|
+
let(:process_action_event) { notification_event }
|
43
43
|
|
44
44
|
it 'should add a process action event' do
|
45
45
|
transaction.set_process_action_event(process_action_event)
|
46
46
|
|
47
47
|
transaction.process_action_event.should == process_action_event
|
48
|
-
transaction.action.should == 'BlogPostsController#show'
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
52
51
|
describe '#add_event' do
|
53
|
-
let(:event) {
|
52
|
+
let(:event) { mock(:event, :name => 'test') }
|
54
53
|
|
55
54
|
it 'should add an event' do
|
56
55
|
expect {
|
@@ -59,29 +58,54 @@ describe Appsignal::Transaction do
|
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
62
|
-
|
63
|
-
let(:exception) {
|
61
|
+
context "using exceptions" do
|
62
|
+
let(:exception) { mock(:exception, :name => 'test') }
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
describe '#add_exception' do
|
65
|
+
it 'should add an exception' do
|
66
|
+
expect {
|
67
|
+
transaction.add_exception(exception)
|
68
|
+
}.to change(transaction, :exception).to(exception)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#exception?" do
|
73
|
+
subject { transaction.exception? }
|
74
|
+
|
75
|
+
context "without an exception" do
|
76
|
+
it { should be_false }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "without an exception" do
|
80
|
+
before { transaction.add_exception(exception) }
|
81
|
+
|
82
|
+
it { should be_true }
|
83
|
+
end
|
69
84
|
end
|
70
85
|
end
|
71
86
|
|
72
87
|
describe '#slow_request?' do
|
73
|
-
let(:
|
88
|
+
let(:start) { Time.now }
|
74
89
|
subject { transaction.slow_request? }
|
75
|
-
before { transaction.set_process_action_event(
|
76
|
-
stub(:duration => duration, :payload => {})
|
77
|
-
) }
|
78
90
|
|
79
|
-
|
91
|
+
context "duration" do
|
92
|
+
before do
|
93
|
+
transaction.set_process_action_event(
|
94
|
+
notification_event(:start => start, :ending => start + duration)
|
95
|
+
)
|
96
|
+
end
|
80
97
|
|
81
|
-
|
82
|
-
|
98
|
+
context "when it reasonably fast" do
|
99
|
+
let(:duration) { 0.199 } # in seconds
|
83
100
|
|
84
|
-
|
101
|
+
it { should be_false }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when the request took too long" do
|
105
|
+
let(:duration) { 0.200 } # in seconds
|
106
|
+
|
107
|
+
it { should be_true }
|
108
|
+
end
|
85
109
|
end
|
86
110
|
|
87
111
|
context "when process action event is empty" do
|
@@ -91,88 +115,148 @@ describe Appsignal::Transaction do
|
|
91
115
|
end
|
92
116
|
|
93
117
|
context "when process action event does not have a payload" do
|
94
|
-
|
118
|
+
let(:event) { notification_event }
|
119
|
+
before do
|
120
|
+
event.instance_variable_set(:@payload, nil)
|
121
|
+
transaction.set_process_action_event(event)
|
122
|
+
end
|
95
123
|
|
96
124
|
it { should be_false }
|
97
125
|
end
|
98
126
|
end
|
99
127
|
|
100
|
-
describe "#
|
128
|
+
describe "#slower?" do
|
129
|
+
context "comparing to a slower transaction" do
|
130
|
+
subject { regular_transaction.slower?(slow_transaction) }
|
131
|
+
|
132
|
+
it { should be_false }
|
133
|
+
end
|
134
|
+
|
135
|
+
context "comparing to a faster transaction" do
|
136
|
+
subject { slow_transaction.slower?(regular_transaction) }
|
137
|
+
|
138
|
+
it { should be_true }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "#truncate!" do
|
101
143
|
subject { slow_transaction }
|
102
144
|
|
103
145
|
it "should clear the process action payload and events" do
|
104
|
-
subject.
|
146
|
+
subject.truncate!
|
105
147
|
|
106
148
|
subject.process_action_event.payload.should be_empty
|
107
149
|
subject.events.should be_empty
|
108
150
|
end
|
109
151
|
end
|
110
152
|
|
111
|
-
describe
|
112
|
-
|
113
|
-
|
153
|
+
describe "#convert_values_to_primitives!" do
|
154
|
+
let(:transaction) { slow_transaction }
|
155
|
+
let(:action_event_payload) { transaction.process_action_event.payload }
|
156
|
+
let(:event_payload) { transaction.events.first.payload }
|
157
|
+
let(:weird_class) { Class.new }
|
158
|
+
|
159
|
+
context "with values that need to be converted" do
|
160
|
+
context "process action event payload" do
|
161
|
+
subject { action_event_payload }
|
162
|
+
before do
|
163
|
+
action_event_payload.clear
|
164
|
+
action_event_payload.
|
165
|
+
merge!(:model => {:with => [:weird, weird_class]})
|
166
|
+
transaction.convert_values_to_primitives!
|
167
|
+
end
|
168
|
+
|
169
|
+
it { should == {:model => {:with => [:weird, weird_class.inspect]}} }
|
170
|
+
end
|
114
171
|
|
115
|
-
|
116
|
-
|
172
|
+
context "payload of events" do
|
173
|
+
subject { event_payload }
|
174
|
+
before do
|
175
|
+
event_payload.clear
|
176
|
+
event_payload.merge!(:weird => weird_class)
|
177
|
+
transaction.convert_values_to_primitives!
|
178
|
+
end
|
117
179
|
|
118
|
-
|
119
|
-
Appsignal::TransactionFormatter.should_receive(:faulty).
|
120
|
-
with(transaction).and_return({})
|
180
|
+
it { should == {:weird => weird_class.inspect} }
|
121
181
|
end
|
122
182
|
end
|
123
183
|
|
124
|
-
context "
|
125
|
-
|
184
|
+
context "without values that need to be converted" do
|
185
|
+
subject { transaction.convert_values_to_primitives! }
|
186
|
+
|
187
|
+
it "doesn't change the action event payload" do
|
188
|
+
before = action_event_payload.dup
|
189
|
+
subject
|
190
|
+
action_event_payload.should == before
|
191
|
+
end
|
126
192
|
|
127
|
-
it "
|
128
|
-
|
129
|
-
|
193
|
+
it " doesn't change the event payloads" do
|
194
|
+
before = event_payload.dup
|
195
|
+
subject
|
196
|
+
event_payload.should == before
|
130
197
|
end
|
131
198
|
end
|
199
|
+
end
|
132
200
|
|
133
|
-
|
134
|
-
|
201
|
+
describe "#type" do
|
202
|
+
context "with a regular transaction" do
|
203
|
+
subject { regular_transaction.type }
|
135
204
|
|
136
|
-
it
|
137
|
-
|
138
|
-
|
139
|
-
|
205
|
+
it { should == :regular_request }
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with a slow transaction" do
|
209
|
+
subject { slow_transaction.type }
|
210
|
+
|
211
|
+
it { should == :slow_request }
|
140
212
|
end
|
141
213
|
|
142
|
-
|
214
|
+
context "with an exception transaction" do
|
215
|
+
subject { transaction_with_exception.type }
|
216
|
+
|
217
|
+
it { should == :exception }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe '#to_hash' do
|
222
|
+
subject { transaction.to_hash }
|
223
|
+
|
224
|
+
it { should be_instance_of Hash }
|
143
225
|
end
|
144
226
|
|
145
227
|
describe '#complete!' do
|
146
|
-
|
147
|
-
|
148
|
-
) }
|
228
|
+
let(:event) { mock(:event) }
|
229
|
+
before { transaction.set_process_action_event(notification_event) }
|
149
230
|
|
150
231
|
it 'should remove transaction from the list' do
|
151
|
-
expect {
|
152
|
-
|
153
|
-
}.to change(Appsignal.transactions, :length).by(-1)
|
232
|
+
expect { transaction.complete! }.
|
233
|
+
to change(Appsignal.transactions, :length).by(-1)
|
154
234
|
end
|
155
235
|
|
156
|
-
context '
|
157
|
-
context '
|
236
|
+
context 'enqueueing' do
|
237
|
+
context 'sanity check' do
|
238
|
+
specify { Appsignal.should respond_to(:enqueue) }
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'without events and without exception' do
|
158
242
|
it 'should add transaction to the agent' do
|
159
|
-
Appsignal.
|
243
|
+
Appsignal.should_receive(:enqueue).with(transaction)
|
160
244
|
end
|
161
245
|
end
|
162
246
|
|
163
247
|
context 'with events' do
|
164
|
-
before { transaction.add_event(
|
248
|
+
before { transaction.add_event(event) }
|
165
249
|
|
166
250
|
it 'should add transaction to the agent' do
|
167
|
-
Appsignal.
|
251
|
+
Appsignal.should_receive(:enqueue).with(transaction)
|
168
252
|
end
|
169
253
|
end
|
170
254
|
|
171
255
|
context 'with exception' do
|
172
|
-
before { transaction.add_exception(
|
256
|
+
before { transaction.add_exception(event) }
|
173
257
|
|
174
258
|
it 'should add transaction to the agent' do
|
175
|
-
Appsignal.
|
259
|
+
Appsignal.should_receive(:enqueue).with(transaction)
|
176
260
|
end
|
177
261
|
end
|
178
262
|
|
@@ -187,5 +271,54 @@ describe Appsignal::Transaction do
|
|
187
271
|
end
|
188
272
|
end
|
189
273
|
end
|
274
|
+
|
275
|
+
# protected
|
276
|
+
|
277
|
+
describe '#add_sanitized_context!' do
|
278
|
+
subject { transaction.send(:add_sanitized_context!) }
|
279
|
+
|
280
|
+
it "delegates to sanitize_environment! and sanitize_session_data!" do
|
281
|
+
transaction.should_receive(:sanitize_environment!)
|
282
|
+
transaction.should_receive(:sanitize_session_data!)
|
283
|
+
subject
|
284
|
+
end
|
285
|
+
|
286
|
+
specify { expect { subject }.to change(transaction, :env).to(nil) }
|
287
|
+
end
|
288
|
+
|
289
|
+
describe '#sanitize_environment!' do
|
290
|
+
let(:whitelisted_keys) { Appsignal::Transaction::ENV_METHODS }
|
291
|
+
let(:transaction) { Appsignal::Transaction.create('1', env) }
|
292
|
+
let(:env) do
|
293
|
+
Hash.new.tap do |hash|
|
294
|
+
whitelisted_keys.each { |o| hash[o] = 1 } # use all whitelisted keys
|
295
|
+
hash[:not_whitelisted] = 'I will be sanitized'
|
296
|
+
end
|
297
|
+
end
|
298
|
+
subject { transaction.sanitized_environment }
|
299
|
+
before { transaction.send(:sanitize_environment!) }
|
300
|
+
|
301
|
+
its(:keys) { should == whitelisted_keys }
|
302
|
+
end
|
303
|
+
|
304
|
+
describe '#sanitize_session_data!' do
|
305
|
+
subject { transaction.send(:sanitize_session_data!) }
|
306
|
+
before do
|
307
|
+
transaction.should respond_to(:request)
|
308
|
+
transaction.stub_chain(:request, :session => :foo)
|
309
|
+
transaction.stub_chain(:request, :fullpath => :bar)
|
310
|
+
end
|
311
|
+
|
312
|
+
it "passes the session data into the params sanitizer" do
|
313
|
+
Appsignal::ParamsSanitizer.should_receive(:sanitize).with(:foo).
|
314
|
+
and_return(:sanitized_foo)
|
315
|
+
subject
|
316
|
+
transaction.sanitized_session_data.should == :sanitized_foo
|
317
|
+
end
|
318
|
+
|
319
|
+
it "sets the fullpath of the request" do
|
320
|
+
expect { subject }.to change(transaction, :fullpath).to(:bar)
|
321
|
+
end
|
322
|
+
end
|
190
323
|
end
|
191
324
|
end
|
@@ -10,13 +10,16 @@ describe Appsignal::Transmitter do
|
|
10
10
|
describe "#uri" do
|
11
11
|
it "returns the uri" do
|
12
12
|
Socket.stub(:gethostname => 'app1.local')
|
13
|
-
subject.uri.should ==
|
14
|
-
|
13
|
+
subject.uri.should == URI(
|
14
|
+
"http://www.80beans.com/action?api_key=the_api_key&"\
|
15
|
+
"hostname=app1.local&gem_version=#{Appsignal::VERSION}"
|
16
|
+
)
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
describe "#transmit" do
|
19
|
-
let(:
|
21
|
+
let(:response) { mock(:response, :code => '200') }
|
22
|
+
let(:http_client) { mock(:request, :request => response) }
|
20
23
|
before { instance.stub(:http_client => http_client) }
|
21
24
|
|
22
25
|
subject { instance.transmit(:shipit => :payload) }
|
@@ -26,13 +29,15 @@ describe Appsignal::Transmitter do
|
|
26
29
|
|
27
30
|
describe "#http_post" do
|
28
31
|
it "calls Net::HTTP.post_form with the correct params" do
|
29
|
-
post =
|
30
|
-
post.should_receive(:[]=).
|
32
|
+
post = mock(:post)
|
33
|
+
post.should_receive(:[]=).
|
34
|
+
with('Content-Type', 'application/json; charset=UTF-8')
|
31
35
|
post.should_receive(:body=).with("{\"the\":\"payload\"}")
|
32
36
|
Socket.stub(:gethostname => 'app1.local')
|
33
37
|
|
34
38
|
Net::HTTP::Post.should_receive(:new).with(
|
35
|
-
"/action?api_key=the_api_key&hostname=app1.local&
|
39
|
+
"/action?api_key=the_api_key&hostname=app1.local&"\
|
40
|
+
"gem_version=#{Appsignal::VERSION}"
|
36
41
|
).and_return(post)
|
37
42
|
instance.send(:http_post, :the => :payload)
|
38
43
|
end
|
data/spec/appsignal_spec.rb
CHANGED
@@ -3,6 +3,17 @@ require 'spec_helper'
|
|
3
3
|
describe Appsignal do
|
4
4
|
it { should respond_to :subscriber }
|
5
5
|
|
6
|
+
describe ".enqueue" do
|
7
|
+
let(:transaction) { regular_transaction }
|
8
|
+
subject { Appsignal.enqueue(transaction) }
|
9
|
+
|
10
|
+
it "forwards the call to the agent" do
|
11
|
+
Appsignal.agent.should respond_to(:enqueue)
|
12
|
+
Appsignal.agent.should_receive(:enqueue).with(transaction)
|
13
|
+
subject
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
6
17
|
describe ".transactions" do
|
7
18
|
subject { Appsignal.transactions }
|
8
19
|
|
@@ -42,6 +53,28 @@ describe Appsignal do
|
|
42
53
|
end
|
43
54
|
end
|
44
55
|
|
56
|
+
describe ".post_processing_middleware" do
|
57
|
+
before { Appsignal.instance_variable_set(:@post_processing_chain, nil) }
|
58
|
+
|
59
|
+
it "returns the default middleware stack" do
|
60
|
+
Appsignal::PostProcessor.should_receive(:default_middleware)
|
61
|
+
Appsignal.post_processing_middleware
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns a chain when called without a block" do
|
65
|
+
instance = Appsignal.post_processing_middleware
|
66
|
+
instance.should be_an_instance_of Appsignal::Middleware::Chain
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when passing a block" do
|
70
|
+
it "yields an appsignal middleware chain" do
|
71
|
+
Appsignal.post_processing_middleware do |o|
|
72
|
+
o.should be_an_instance_of Appsignal::Middleware::Chain
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
45
78
|
describe '.active?' do
|
46
79
|
subject { Appsignal.active? }
|
47
80
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rspec'
|
2
|
+
require 'pry'
|
2
3
|
require 'rails'
|
3
4
|
require 'action_controller/railtie'
|
4
5
|
|
@@ -15,71 +16,17 @@ module MyApp
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
RSpec.configure do |config|
|
19
|
+
def log_file
|
20
|
+
File.join(File.dirname(__FILE__), '../log/appsignal.log')
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
appsignal_transaction.tap do |o|
|
25
|
-
begin
|
26
|
-
raise ArgumentError, 'oh no'
|
27
|
-
rescue ArgumentError => exception
|
28
|
-
env = {}
|
29
|
-
o.add_exception(
|
30
|
-
Appsignal::ExceptionNotification.new(env, exception)
|
31
|
-
)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def regular_transaction
|
37
|
-
appsignal_transaction(:process_action_event => create_process_action_event)
|
38
|
-
end
|
23
|
+
require 'appsignal'
|
39
24
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
)
|
44
|
-
end
|
25
|
+
RSpec.configure do |config|
|
26
|
+
config.include TransactionHelpers
|
27
|
+
config.include NotificationHelpers
|
45
28
|
|
46
|
-
|
47
|
-
|
48
|
-
events = args.delete(:events) || [create_process_action_event(name='query.mongoid')]
|
49
|
-
exception = args.delete(:exception)
|
50
|
-
Appsignal::Transaction.create(
|
51
|
-
'1',
|
52
|
-
{
|
53
|
-
'HTTP_USER_AGENT' => 'IE6',
|
54
|
-
'SERVER_NAME' => 'localhost',
|
55
|
-
'action_dispatch.routes' => 'not_available'
|
56
|
-
}.merge(args)
|
57
|
-
).tap do |o|
|
58
|
-
o.set_process_action_event(process_action_event)
|
59
|
-
o.add_exception(exception)
|
60
|
-
events.each { |event| o.add_event(event) }
|
29
|
+
config.before :all do
|
30
|
+
FileUtils.rm(log_file) if File.exists?(log_file)
|
61
31
|
end
|
62
32
|
end
|
63
|
-
|
64
|
-
def create_process_action_event(name=nil, start=nil, ending=nil, tid=nil, payload=nil)
|
65
|
-
ActiveSupport::Notifications::Event.new(
|
66
|
-
name || 'process_action.action_controller',
|
67
|
-
start || Time.parse("01-01-2001 10:00:00"),
|
68
|
-
ending || Time.parse("01-01-2001 10:00:01"),
|
69
|
-
tid || '1',
|
70
|
-
payload || create_payload
|
71
|
-
)
|
72
|
-
end
|
73
|
-
|
74
|
-
def create_payload(args = {})
|
75
|
-
{
|
76
|
-
:path => '/blog',
|
77
|
-
:action => 'show',
|
78
|
-
:controller => 'BlogPostsController',
|
79
|
-
:request_format => 'html',
|
80
|
-
:request_method => "GET",
|
81
|
-
:status => '200',
|
82
|
-
:view_runtime => 500,
|
83
|
-
:db_runtime => 500
|
84
|
-
}.merge(args)
|
85
|
-
end
|