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
@@ -1,95 +1,59 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module Appsignal
|
4
|
-
class TransactionFormatter
|
5
|
-
extend Forwardable
|
4
|
+
class TransactionFormatter < SimpleDelegator
|
6
5
|
|
7
6
|
def initialize(transaction)
|
8
|
-
|
7
|
+
super(transaction)
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
12
|
-
|
10
|
+
def hash
|
11
|
+
@hash ||= default_hash
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
16
|
-
|
14
|
+
def to_hash
|
15
|
+
merge_process_action_event_with_log_entry! if process_action_event
|
16
|
+
add_exception_to_hash! if exception?
|
17
|
+
add_events_to_hash! if slow_request?
|
18
|
+
hash
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
|
-
TransactionFormatter::FaultyRequestFormatter.new(transaction)
|
21
|
-
end
|
21
|
+
protected
|
22
22
|
|
23
|
-
def
|
23
|
+
def default_hash
|
24
24
|
{
|
25
25
|
:request_id => id,
|
26
|
-
:
|
27
|
-
|
26
|
+
:log_entry => {
|
27
|
+
:path => fullpath,
|
28
|
+
:kind => 'http_request',
|
29
|
+
:time => time,
|
30
|
+
:environment => sanitized_environment,
|
31
|
+
:session_data => sanitized_session_data
|
32
|
+
},
|
28
33
|
:failed => exception?
|
29
34
|
}
|
30
35
|
end
|
31
36
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def formatted_process_action_event
|
41
|
-
basic_process_action_event.tap { |hsh| hsh.merge!(formatted_payload) if process_action_event }
|
37
|
+
def merge_process_action_event_with_log_entry!
|
38
|
+
hash[:log_entry].merge!(process_action_event.to_appsignal_hash)
|
39
|
+
hash[:log_entry].tap do |o|
|
40
|
+
o.merge!(o.delete(:payload))
|
41
|
+
o[:action] = "#{o.delete(:controller)}##{o.delete(:action)}"
|
42
|
+
o.delete(:name)
|
43
|
+
end
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
45
|
-
{
|
46
|
-
:
|
47
|
-
:
|
46
|
+
def add_exception_to_hash!
|
47
|
+
hash[:exception] = {
|
48
|
+
:backtrace => exception.backtrace,
|
49
|
+
:exception => exception.name,
|
50
|
+
:message => exception.message
|
48
51
|
}
|
49
52
|
end
|
50
53
|
|
51
|
-
def
|
52
|
-
|
53
|
-
{
|
54
|
-
:duration => process_action_event.duration,
|
55
|
-
:time => process_action_event.time.to_f,
|
56
|
-
:end => process_action_event.end.to_f,
|
57
|
-
:action => action
|
58
|
-
}
|
59
|
-
)
|
60
|
-
end
|
61
|
-
|
62
|
-
def sanitized_event_payload(event)
|
63
|
-
Appsignal::ParamsSanitizer.sanitize(
|
64
|
-
Appsignal.event_payload_sanitizer.call(event)
|
65
|
-
)
|
54
|
+
def add_events_to_hash!
|
55
|
+
hash[:events] = events.map(&:to_appsignal_hash)
|
66
56
|
end
|
67
57
|
|
68
|
-
def filtered_environment
|
69
|
-
{}.tap do |out|
|
70
|
-
env.each_pair do |key, value|
|
71
|
-
out[key] = value if ENV_METHODS.include?(key)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Based on what Rails uses + some variables we'd like to show
|
77
|
-
ENV_METHODS = %w{ CONTENT_LENGTH AUTH_TYPE GATEWAY_INTERFACE
|
78
|
-
PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER
|
79
|
-
REMOTE_ADDR REQUEST_METHOD SERVER_NAME SERVER_PORT
|
80
|
-
SERVER_PROTOCOL
|
81
|
-
|
82
|
-
HTTP_X_REQUEST_START HTTP_X_MIDDLEWARE_START HTTP_X_QUEUE_START
|
83
|
-
HTTP_X_QUEUE_TIME HTTP_X_HEROKU_QUEUE_WAIT_TIME
|
84
|
-
HTTP_X_APPLICATION_START HTTP_ACCEPT HTTP_ACCEPT_CHARSET
|
85
|
-
HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL
|
86
|
-
HTTP_CONNECTION HTTP_USER_AGENT HTTP_FROM HTTP_NEGOTIATE
|
87
|
-
HTTP_PRAGMA HTTP_REFERER }.freeze
|
88
|
-
|
89
58
|
end
|
90
59
|
end
|
91
|
-
|
92
|
-
require 'appsignal/transaction/regular_request_formatter'
|
93
|
-
require 'appsignal/transaction/slow_request_formatter'
|
94
|
-
require 'appsignal/transaction/faulty_request_formatter'
|
95
|
-
require 'appsignal/transaction/params_sanitizer'
|
data/lib/appsignal/version.rb
CHANGED
@@ -1,119 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
:name => 'transaction',
|
6
|
-
:exception? => false,
|
7
|
-
:action => 'something#else'
|
8
|
-
) }
|
9
|
-
|
10
|
-
describe '#add_to_queue' do
|
11
|
-
before do
|
12
|
-
@agent = Appsignal::Agent.new
|
13
|
-
@exception_transaction = stub(
|
14
|
-
:name => 'exception',
|
15
|
-
:exception? => true,
|
16
|
-
:action => 'controller#action1'
|
17
|
-
)
|
18
|
-
@slow_transaction = stub(
|
19
|
-
:name => 'slow',
|
20
|
-
:action => 'controller#action1',
|
21
|
-
:exception? => false,
|
22
|
-
:process_action_event => stub(
|
23
|
-
:duration => 250.0
|
24
|
-
)
|
25
|
-
)
|
26
|
-
@slower_transaction = stub(
|
27
|
-
:name => 'slow',
|
28
|
-
:action => 'controller#action1',
|
29
|
-
:exception? => false,
|
30
|
-
:process_action_event => stub(
|
31
|
-
:duration => 300.0
|
32
|
-
)
|
33
|
-
)
|
34
|
-
@other_slow_transaction = stub(
|
35
|
-
:name => 'slow',
|
36
|
-
:action => 'controller#action1',
|
37
|
-
:exception? => false,
|
38
|
-
:process_action_event => stub(
|
39
|
-
:duration => 260.0
|
40
|
-
)
|
41
|
-
)
|
42
|
-
@slow_transaction_in_other_action = stub(
|
43
|
-
:name => 'slow',
|
44
|
-
:action => 'controller#action2',
|
45
|
-
:exception? => false,
|
46
|
-
:process_action_event => stub(
|
47
|
-
:duration => 400.0
|
48
|
-
)
|
49
|
-
)
|
50
|
-
end
|
51
|
-
subject { @agent }
|
52
|
-
|
53
|
-
context "an exception transaction" do
|
54
|
-
before do
|
55
|
-
@exception_transaction.should_not_receive(:clear_payload_and_events!)
|
56
|
-
subject.add_to_queue(@exception_transaction)
|
57
|
-
end
|
58
|
-
|
59
|
-
its(:queue) { should include(@exception_transaction) }
|
60
|
-
its(:slowest_transactions) { should be_empty }
|
3
|
+
class PostProcessingException < Exception
|
4
|
+
end
|
61
5
|
|
62
|
-
|
63
|
-
|
64
|
-
subject.add_to_queue(@slow_transaction)
|
65
|
-
end
|
6
|
+
describe Appsignal::Agent do
|
7
|
+
let(:transaction) { regular_transaction }
|
66
8
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
context "a slower transaction in the same action" do
|
73
|
-
before do
|
74
|
-
@slow_transaction.should_receive(:clear_payload_and_events!)
|
75
|
-
@slower_transaction.should_not_receive(:clear_payload_and_events!)
|
76
|
-
subject.add_to_queue(@slower_transaction)
|
77
|
-
end
|
78
|
-
|
79
|
-
its(:queue) { should include(@slower_transaction) }
|
80
|
-
its(:slowest_transactions) { should == {
|
81
|
-
'controller#action1' => @slower_transaction
|
82
|
-
} }
|
83
|
-
|
84
|
-
context "a slow but not the slowest transaction in the same action" do
|
85
|
-
before do
|
86
|
-
@other_slow_transaction.should_receive(:clear_payload_and_events!)
|
87
|
-
subject.add_to_queue(@other_slow_transaction)
|
88
|
-
end
|
89
|
-
|
90
|
-
its(:queue) { should include(@other_slow_transaction) }
|
91
|
-
its(:slowest_transactions) { should == {
|
92
|
-
'controller#action1' => @slower_transaction
|
93
|
-
} }
|
94
|
-
end
|
95
|
-
|
96
|
-
context "an even slower transaction in a different action" do
|
97
|
-
before do
|
98
|
-
@slow_transaction_in_other_action.should_not_receive(:clear_payload_and_events!)
|
99
|
-
subject.add_to_queue(@slow_transaction_in_other_action)
|
100
|
-
end
|
101
|
-
|
102
|
-
its(:queue) { should include(@slow_transaction_in_other_action) }
|
103
|
-
its(:slowest_transactions) { should == {
|
104
|
-
'controller#action1' => @slower_transaction,
|
105
|
-
'controller#action2' => @slow_transaction_in_other_action
|
106
|
-
} }
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
9
|
+
describe "#enqueue" do
|
10
|
+
it "forwards to the aggregator" do
|
11
|
+
subject.aggregator.should respond_to(:add)
|
12
|
+
subject.aggregator.should_receive(:add).with(:foo)
|
110
13
|
end
|
14
|
+
|
15
|
+
after { subject.enqueue(:foo) }
|
111
16
|
end
|
112
17
|
|
113
18
|
describe "#send_queue" do
|
114
19
|
it "transmits" do
|
115
|
-
subject.stub(:
|
116
|
-
subject.transmitter.should_receive(:transmit).with(
|
20
|
+
subject.aggregator.stub(:post_processed_queue! => :foo)
|
21
|
+
subject.transmitter.should_receive(:transmit).with(:foo)
|
117
22
|
end
|
118
23
|
|
119
24
|
it "handles the return code" do
|
@@ -121,42 +26,62 @@ describe Appsignal::Agent do
|
|
121
26
|
subject.should_receive(:handle_result).with('200')
|
122
27
|
end
|
123
28
|
|
29
|
+
it "handle exceptions in post processing" do
|
30
|
+
subject.aggregator.stub(:post_processed_queue!).and_raise(
|
31
|
+
PostProcessingException.new('Message')
|
32
|
+
)
|
33
|
+
|
34
|
+
subject.should_receive(:stop_logging)
|
35
|
+
Appsignal.logger.should_receive(:error).
|
36
|
+
with('PostProcessingException while sending queue: Message').
|
37
|
+
once
|
38
|
+
Appsignal.logger.should_receive(:error).
|
39
|
+
with(kind_of(String)).
|
40
|
+
once
|
41
|
+
end
|
42
|
+
|
124
43
|
it "handles exceptions in transmit" do
|
125
|
-
subject.transmitter.stub(:transmit).and_raise(
|
126
|
-
|
127
|
-
|
44
|
+
subject.transmitter.stub(:transmit).and_raise(
|
45
|
+
Exception.new('Message')
|
46
|
+
)
|
47
|
+
subject.should_receive(:stop_logging)
|
48
|
+
Appsignal.logger.should_receive(:error).
|
49
|
+
with('Exception while sending queue: Message').
|
50
|
+
once
|
51
|
+
Appsignal.logger.should_receive(:error).
|
52
|
+
with(kind_of(String)).
|
53
|
+
once
|
128
54
|
end
|
129
55
|
|
130
56
|
after { subject.send_queue }
|
131
57
|
end
|
132
58
|
|
133
59
|
describe '#handle_result' do
|
134
|
-
before { subject.
|
60
|
+
before { subject.aggregator.add(transaction) }
|
135
61
|
before { subject.instance_variable_set(:@sleep_time, 3.0) }
|
136
62
|
|
137
63
|
context "good responses" do
|
138
|
-
before { subject.handle_result
|
64
|
+
before { subject.send(:handle_result, code) }
|
139
65
|
|
140
66
|
context "with 200" do
|
141
67
|
let(:code) { '200' }
|
142
68
|
|
143
|
-
its(:
|
144
|
-
|
69
|
+
its(:sleep_time) { should == 3.0 }
|
70
|
+
|
71
|
+
it "does not log the event" do
|
72
|
+
Appsignal.logger.should_not_receive(:error)
|
73
|
+
end
|
145
74
|
end
|
146
75
|
|
147
76
|
context "with 420" do
|
148
77
|
let(:code) { '420' }
|
149
78
|
|
150
|
-
its(:queue) { should be_empty }
|
151
|
-
its(:slowest_transactions) { should be_empty }
|
152
79
|
its(:sleep_time) { should == 4.5 }
|
153
80
|
end
|
154
81
|
|
155
82
|
context "with 413" do
|
156
83
|
let(:code) { '413' }
|
157
84
|
|
158
|
-
its(:queue) { should be_empty }
|
159
|
-
its(:slowest_transactions) { should be_empty }
|
160
85
|
its(:sleep_time) { should == 2.0 }
|
161
86
|
end
|
162
87
|
end
|
@@ -197,47 +122,12 @@ describe Appsignal::Agent do
|
|
197
122
|
context "any other response" do
|
198
123
|
let(:code) { 'any other response' }
|
199
124
|
|
200
|
-
it "
|
201
|
-
|
125
|
+
it "logs the event" do
|
126
|
+
Appsignal.logger.should_receive(:error)
|
202
127
|
end
|
203
128
|
end
|
204
129
|
|
205
|
-
after { subject.handle_result
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
describe "#good_response" do
|
210
|
-
before do
|
211
|
-
subject.instance_variable_set(:@retry_once, false)
|
212
|
-
subject.add_to_queue(transaction)
|
213
|
-
subject.send :good_response
|
214
|
-
end
|
215
|
-
|
216
|
-
its(:queue) { should be_empty }
|
217
|
-
its(:slowest_transactions) { should be_empty }
|
218
|
-
|
219
|
-
it "allows the next request to be retried" do
|
220
|
-
subject.instance_variable_get(:@retry_request).should be_true
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
describe "#retry_once" do
|
225
|
-
before do
|
226
|
-
subject.add_to_queue(transaction)
|
227
|
-
subject.send :retry_once
|
228
|
-
end
|
229
|
-
|
230
|
-
context "on time," do
|
231
|
-
its(:queue) { should == [transaction] }
|
232
|
-
its(:slowest_transactions) { should == {
|
233
|
-
'something#else' => transaction
|
234
|
-
} }
|
235
|
-
|
236
|
-
context "two times" do
|
237
|
-
before { subject.send :retry_once }
|
238
|
-
|
239
|
-
its(:queue) { should be_empty }
|
240
|
-
end
|
130
|
+
after { subject.send(:handle_result, code) }
|
241
131
|
end
|
242
132
|
end
|
243
133
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Appsignal::PostProcessor do
|
4
|
+
let(:klass) { Appsignal::PostProcessor }
|
5
|
+
let(:post_processor) { klass.new(transactions) }
|
6
|
+
|
7
|
+
describe "#initialize" do
|
8
|
+
subject { klass.new(:foo) }
|
9
|
+
|
10
|
+
its(:transactions) { should == :foo }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#post_processed_queue!" do
|
14
|
+
let(:first_transaction) { regular_transaction }
|
15
|
+
let(:second_transaction) do
|
16
|
+
slow_transaction(
|
17
|
+
:events => [
|
18
|
+
notification_event(
|
19
|
+
:payload => {
|
20
|
+
:set_value => 'set value',
|
21
|
+
:nil_value => nil
|
22
|
+
}
|
23
|
+
)
|
24
|
+
]
|
25
|
+
)
|
26
|
+
end
|
27
|
+
let(:transactions) { [first_transaction, second_transaction] }
|
28
|
+
let(:processed_queue) { post_processor.post_processed_queue! }
|
29
|
+
subject { processed_queue }
|
30
|
+
|
31
|
+
it { should have(2).items }
|
32
|
+
|
33
|
+
context "the first transaction" do
|
34
|
+
subject { processed_queue[0] }
|
35
|
+
|
36
|
+
it { should_not have_key(:events) }
|
37
|
+
|
38
|
+
context "log entry" do
|
39
|
+
subject { processed_queue[0][:log_entry] }
|
40
|
+
|
41
|
+
it { should have_key(:duration) }
|
42
|
+
it { should have_key(:end) }
|
43
|
+
it { should_not have_key(:events) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "the second transaction" do
|
48
|
+
context "log entry" do
|
49
|
+
subject { processed_queue[1][:log_entry] }
|
50
|
+
|
51
|
+
it { should have_key(:duration) }
|
52
|
+
it { should have_key(:end) }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "first event" do
|
56
|
+
subject { processed_queue[1][:events][0] }
|
57
|
+
|
58
|
+
it { should_not be_nil }
|
59
|
+
it { should have_key(:name) }
|
60
|
+
|
61
|
+
it "should have the set value in the payload" do
|
62
|
+
subject[:payload][:set_value].should == 'set value'
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not have the nil value in the payload"\
|
66
|
+
"since delete blanks is in the middle ware stack" do
|
67
|
+
subject[:payload].should_not have_key(:nil_value)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe ".default_middleware" do
|
74
|
+
subject { klass.default_middleware }
|
75
|
+
|
76
|
+
it { should be_instance_of Appsignal::Middleware::Chain }
|
77
|
+
|
78
|
+
it "should include the default middleware stack" do
|
79
|
+
subject.exists?(Appsignal::Middleware::DeleteBlanks).should be_true
|
80
|
+
subject.exists?(Appsignal::Middleware::ActionViewSanitizer).should be_true
|
81
|
+
subject.exists?(Appsignal::Middleware::ActiveRecordSanitizer).should be_true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|