appsignal 1.0.7 → 1.1.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +5 -21
  4. data/Rakefile +2 -0
  5. data/circle.yml +2 -1
  6. data/ext/agent.yml +7 -7
  7. data/ext/appsignal_extension.c +3 -5
  8. data/ext/extconf.rb +6 -15
  9. data/gemfiles/grape.gemfile +7 -0
  10. data/lib/appsignal/config.rb +2 -5
  11. data/lib/appsignal/event_formatter.rb +0 -2
  12. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +47 -1
  13. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +29 -0
  14. data/lib/appsignal/event_formatter/moped/query_formatter.rb +7 -6
  15. data/lib/appsignal/hooks.rb +33 -0
  16. data/lib/appsignal/hooks/net_http.rb +1 -1
  17. data/lib/appsignal/hooks/sequel.rb +7 -4
  18. data/lib/appsignal/hooks/sidekiq.rb +10 -19
  19. data/lib/appsignal/integrations/capistrano/appsignal.cap +1 -1
  20. data/lib/appsignal/integrations/delayed_job_plugin.rb +20 -11
  21. data/lib/appsignal/integrations/grape.rb +44 -0
  22. data/lib/appsignal/integrations/mongo_ruby_driver.rb +5 -9
  23. data/lib/appsignal/integrations/railtie.rb +4 -0
  24. data/lib/appsignal/integrations/resque.rb +1 -1
  25. data/lib/appsignal/js_exception_transaction.rb +2 -3
  26. data/lib/appsignal/subscriber.rb +2 -3
  27. data/lib/appsignal/transaction.rb +2 -8
  28. data/lib/appsignal/transmitter.rb +1 -1
  29. data/lib/appsignal/utils.rb +7 -43
  30. data/lib/appsignal/version.rb +1 -1
  31. data/lib/tasks/diag.rake +75 -0
  32. data/spec/lib/appsignal/capistrano3_spec.rb +1 -21
  33. data/spec/lib/appsignal/config_spec.rb +0 -12
  34. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +1 -1
  35. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +186 -14
  36. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +54 -0
  37. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +4 -4
  38. data/spec/lib/appsignal/extension_spec.rb +1 -1
  39. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +49 -14
  40. data/spec/lib/appsignal/hooks/sequel_spec.rb +1 -1
  41. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +29 -62
  42. data/spec/lib/appsignal/hooks_spec.rb +115 -0
  43. data/spec/lib/appsignal/integrations/grape_spec.rb +94 -0
  44. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +5 -8
  45. data/spec/lib/appsignal/integrations/resque_spec.rb +0 -1
  46. data/spec/lib/appsignal/js_exception_transaction_spec.rb +0 -1
  47. data/spec/lib/appsignal/subscriber_spec.rb +5 -23
  48. data/spec/lib/appsignal/transaction_spec.rb +0 -21
  49. data/spec/lib/appsignal/utils_spec.rb +1 -68
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/support/helpers/env_helpers.rb +0 -1
  52. data/spec/support/stubs/delayed_job.rb +0 -0
  53. metadata +15 -11
  54. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +0 -88
  55. data/lib/appsignal/event_formatter/sequel/sql_formatter.rb +0 -13
  56. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +0 -115
  57. data/spec/lib/appsignal/event_formatter/sequel/sql_formatter_spec.rb +0 -22
@@ -74,3 +74,118 @@ describe Appsignal::Hooks do
74
74
  Appsignal::Hooks.hooks[:mock_error_hook].installed?.should be_false
75
75
  end
76
76
  end
77
+
78
+ describe Appsignal::Hooks::Helpers do
79
+ class ClassWithHelpers
80
+ include Appsignal::Hooks::Helpers
81
+ end
82
+ let(:with_helpers) { ClassWithHelpers.new }
83
+
84
+ describe "#truncate" do
85
+ let(:very_long_text) do
86
+ "a" * 400
87
+ end
88
+
89
+ it "should truncate the text to 200 chars max" do
90
+ with_helpers.truncate(very_long_text).should == "#{'a' * 197}..."
91
+ end
92
+ end
93
+
94
+ describe "#string_or_inspect" do
95
+ context "when string" do
96
+ it "should return the string" do
97
+ with_helpers.string_or_inspect('foo').should == 'foo'
98
+ end
99
+ end
100
+
101
+ context "when integer" do
102
+ it "should return the string" do
103
+ with_helpers.string_or_inspect(1).should == '1'
104
+ end
105
+ end
106
+
107
+ context "when object" do
108
+ let(:object) { Object.new }
109
+
110
+ it "should return the string" do
111
+ with_helpers.string_or_inspect(object).should == object.inspect
112
+ end
113
+ end
114
+ end
115
+
116
+ describe "#extract_value" do
117
+ context "for a hash" do
118
+ let(:hash) { {:key => 'value'} }
119
+
120
+ context "when the key exists" do
121
+ subject { with_helpers.extract_value(hash, :key) }
122
+
123
+ it { should == 'value' }
124
+ end
125
+
126
+ context "when the key does not exist" do
127
+ subject { with_helpers.extract_value(hash, :nonexistent_key) }
128
+
129
+ it { should be_nil }
130
+
131
+ context "with a default value" do
132
+ subject { with_helpers.extract_value(hash, :nonexistent_key, 1) }
133
+
134
+ it { should == 1 }
135
+ end
136
+ end
137
+ end
138
+
139
+ context "for an object" do
140
+ let(:object) { double(:existing_method => 'value') }
141
+
142
+ context "when the method exists" do
143
+ subject { with_helpers.extract_value(object, :existing_method) }
144
+
145
+ it { should == 'value' }
146
+ end
147
+
148
+ context "when the method does not exist" do
149
+ subject { with_helpers.extract_value(object, :nonexistent_method) }
150
+
151
+ it { should be_nil }
152
+
153
+ context "and there is a default value" do
154
+ subject { with_helpers.extract_value(object, :nonexistent_method, 1) }
155
+
156
+ it { should == 1 }
157
+ end
158
+ end
159
+
160
+ end
161
+
162
+ context "when we need to call to_s on the value" do
163
+ let(:object) { double(:existing_method => 1) }
164
+
165
+ subject { with_helpers.extract_value(object, :existing_method, nil, true) }
166
+
167
+ it { should == '1' }
168
+ end
169
+ end
170
+
171
+ describe "#format_args" do
172
+ let(:object) { Object.new }
173
+ let(:args) do
174
+ [
175
+ 'Model',
176
+ 1,
177
+ object,
178
+ 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
179
+ ]
180
+ end
181
+
182
+ it "should format the arguments" do
183
+ with_helpers.format_args(args).should == [
184
+ 'Model',
185
+ '1',
186
+ object.inspect,
187
+ 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ...'
188
+ ]
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ if grape_present?
4
+ require 'appsignal/integrations/grape'
5
+
6
+ describe Appsignal::Grape::Middleware do
7
+
8
+ before :all do
9
+ start_agent
10
+ end
11
+
12
+ let(:app) { double(:call => true) }
13
+ let(:api_endpoint) { double(:options => options) }
14
+ let(:options) { {
15
+ :for => 'Api::PostPut',
16
+ :method => ['POST'],
17
+ :path => ['ping']
18
+ }}
19
+ let(:env) do
20
+ http_request_env_with_data('api.endpoint' => api_endpoint)
21
+ end
22
+ let(:middleware) { Appsignal::Grape::Middleware.new(app) }
23
+
24
+ describe "#call" do
25
+ context "when appsignal is active" do
26
+ before { Appsignal.stub(:active? => true) }
27
+
28
+ it "should call with monitoring" do
29
+ expect( middleware ).to receive(:call_with_appsignal_monitoring).with(env)
30
+ end
31
+ end
32
+
33
+ context "when appsignal is not active" do
34
+ before { Appsignal.stub(:active? => false) }
35
+
36
+ it "should not call with monitoring" do
37
+ expect( middleware ).to_not receive(:call_with_appsignal_monitoring)
38
+ end
39
+
40
+ it "should call the app" do
41
+ expect( app ).to receive(:call).with(env)
42
+ end
43
+ end
44
+
45
+ after { middleware.call(env) }
46
+ end
47
+
48
+ describe "#call_with_appsignal_monitoring" do
49
+ before { SecureRandom.stub(:uuid => '1') }
50
+
51
+ it "should create a transaction" do
52
+ Appsignal::Transaction.should_receive(:create).with(
53
+ '1',
54
+ Appsignal::Transaction::HTTP_REQUEST,
55
+ kind_of(::Rack::Request)
56
+ ).and_return(
57
+ double(
58
+ :set_action => nil,
59
+ :set_http_or_background_queue_start => nil,
60
+ :set_metadata => nil
61
+ )
62
+ )
63
+ end
64
+
65
+ it "should call the app" do
66
+ app.should_receive(:call).with(env)
67
+ end
68
+
69
+ context "with an error" do
70
+ let(:error) { VerySpecificError.new }
71
+ let(:app) do
72
+ double.tap do |d|
73
+ d.stub(:call).and_raise(error)
74
+ end
75
+ end
76
+
77
+ it "should set the error" do
78
+ Appsignal::Transaction.any_instance.should_receive(:set_error).with(error)
79
+ end
80
+ end
81
+
82
+ it "should set metadata" do
83
+ Appsignal::Transaction.any_instance.should_receive(:set_metadata).twice
84
+ end
85
+
86
+ it "should set the action and queue start" do
87
+ Appsignal::Transaction.any_instance.should_receive(:set_action).with('POST::Api::PostPut#ping')
88
+ Appsignal::Transaction.any_instance.should_receive(:set_http_or_background_queue_start)
89
+ end
90
+
91
+ after { middleware.call(env) rescue VerySpecificError }
92
+ end
93
+ end
94
+ end
@@ -11,15 +11,13 @@ describe Appsignal::Hooks::MongoMonitorSubscriber do
11
11
  describe "#started" do
12
12
  let(:event) do
13
13
  double(
14
- :request_id => 1,
15
- :command_name => 'find',
16
- :command => {'foo' => 'bar'}
14
+ :request_id => 1,
15
+ :command => {'foo' => 'bar'}
17
16
  )
18
17
  end
19
18
 
20
19
  it "should sanitize command" do
21
- Appsignal::EventFormatter::MongoRubyDriver::QueryFormatter
22
- .should receive(:format).with('find', {'foo' => 'bar'})
20
+ Appsignal::Utils.should receive(:sanitize).with({'foo' => 'bar'} )
23
21
 
24
22
  subscriber.started(event)
25
23
  end
@@ -83,9 +81,8 @@ describe Appsignal::Hooks::MongoMonitorSubscriber do
83
81
  Appsignal::Extension.should receive(:finish_event).with(
84
82
  transaction.transaction_index,
85
83
  'query.mongodb',
86
- 'find | test | SUCCEEDED',
87
- "{\"foo\":\"?\"}",
88
- 0
84
+ 'find',
85
+ "test | SUCCEEDED | {\"foo\"=>\"?\"}"
89
86
  )
90
87
 
91
88
  subscriber.finish('SUCCEEDED', event)
@@ -31,7 +31,6 @@ if resque_present?
31
31
  before do
32
32
  transaction.stub(:complete => true)
33
33
  Appsignal::Transaction.stub(:current => transaction)
34
- Appsignal.should_receive(:stop)
35
34
  end
36
35
 
37
36
  context "without exception" do
@@ -87,7 +87,6 @@ describe Appsignal::JSExceptionTransaction do
87
87
  describe "#complete!" do
88
88
  it "should call all required methods" do
89
89
  expect( Appsignal::Extension ).to receive(:finish_transaction).with(kind_of(Integer))
90
- expect( Appsignal::Extension ).to receive(:complete_transaction).with(kind_of(Integer))
91
90
  transaction.complete!
92
91
  end
93
92
  end
@@ -98,10 +98,10 @@ describe Appsignal::Subscriber do
98
98
 
99
99
  it "should call native start and finish event for every event" do
100
100
  Appsignal::Extension.should_receive(:start_event).exactly(4).times
101
- Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'one', '', '', 0).once
102
- Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'two', '', '', 0).once
103
- Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'two.three', '', '', 0).once
104
- Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'one.three', '', '', 0).once
101
+ Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'one', '', '').once
102
+ Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'two', '', '').once
103
+ Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'two.three', '', '').once
104
+ Appsignal::Extension.should_receive(:finish_event).with(kind_of(Integer), 'one.three', '', '').once
105
105
 
106
106
  ActiveSupport::Notifications.instrument('one') do
107
107
  ActiveSupport::Notifications.instrument('two') do
@@ -119,8 +119,7 @@ describe Appsignal::Subscriber do
119
119
  kind_of(Integer),
120
120
  'request.net_http',
121
121
  'GET http://www.google.com',
122
- '',
123
- 0
122
+ ''
124
123
  ).once
125
124
 
126
125
  ActiveSupport::Notifications.instrument(
@@ -131,23 +130,6 @@ describe Appsignal::Subscriber do
131
130
  )
132
131
  end
133
132
 
134
- it "should call finish with title, body and body format if there is a formatter that returns it" do
135
- Appsignal::Extension.should_receive(:start_event).once
136
- Appsignal::Extension.should_receive(:finish_event).with(
137
- kind_of(Integer),
138
- 'sql.active_record',
139
- 'Something load',
140
- 'SELECT * FROM something',
141
- 1
142
- ).once
143
-
144
- ActiveSupport::Notifications.instrument(
145
- 'sql.active_record',
146
- :name => 'Something load',
147
- :sql => 'SELECT * FROM something'
148
- )
149
- end
150
-
151
133
  context "when paused" do
152
134
  before { transaction.pause! }
153
135
 
@@ -331,11 +331,6 @@ describe Appsignal::Transaction do
331
331
  'params',
332
332
  '{"controller":"blog_posts","action":"show","id":"1"}'
333
333
  ).once
334
- Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
335
- kind_of(Integer),
336
- 'metadata',
337
- '{"key":"value"}'
338
- ).once
339
334
  Appsignal::Extension.should_receive(:set_transaction_sample_data).with(
340
335
  kind_of(Integer),
341
336
  'tags',
@@ -621,22 +616,6 @@ describe Appsignal::Transaction do
621
616
  end
622
617
  end
623
618
 
624
- describe "#metadata" do
625
- subject { transaction.send(:metadata) }
626
-
627
- context "when env is nil" do
628
- before { transaction.request.stub(:env => nil) }
629
-
630
- it { should be_nil }
631
- end
632
-
633
- context "when env is present" do
634
- let(:env) { {:metadata => {:key => 'value'}} }
635
-
636
- it { should == env[:metadata] }
637
- end
638
- end
639
-
640
619
  describe '#sanitized_tags' do
641
620
  before do
642
621
  transaction.set_tags(
@@ -1,5 +1,3 @@
1
- # encoding: UTF-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe Appsignal::Utils do
@@ -20,22 +18,13 @@ describe Appsignal::Utils do
20
18
  end
21
19
  end
22
20
 
23
- context "when params is an array of strings" do
21
+ context "when params is an array of strings " do
24
22
  let(:params) { ['foo', 'bar'] }
25
23
 
26
24
  it "should sanitize all hash values with a single questionmark" do
27
25
  expect( Appsignal::Utils.sanitize(params) ).to eq(['?'])
28
26
  end
29
27
  end
30
-
31
- context "when params is a mixed array" do
32
- let(:params) { [nil, 'foo', 'bar'] }
33
-
34
- it "should sanitize all hash values with a single questionmark" do
35
- expect( Appsignal::Utils.sanitize(params) ).to eq(['?'])
36
- end
37
- end
38
-
39
28
  context "when params is a string" do
40
29
  let(:params) { 'bar'}
41
30
 
@@ -44,60 +33,4 @@ describe Appsignal::Utils do
44
33
  end
45
34
  end
46
35
  end
47
-
48
- describe ".sanitize_key" do
49
- it "should not sanitize key when no key_sanitizer is given" do
50
- expect( Appsignal::Utils.sanitize_key('foo', nil) ).to eql('foo')
51
- end
52
-
53
- context "with mongodb sanitizer" do
54
- it "should not sanitize key when no dots are in the key" do
55
- expect( Appsignal::Utils.sanitize_key('foo', :mongodb) ).to eql('foo')
56
- end
57
-
58
- it "should sanitize key when dots are in the key" do
59
- expect( Appsignal::Utils.sanitize_key('foo.bar', :mongodb) ).to eql('foo.?')
60
- end
61
-
62
- it "should sanitize a symbol" do
63
- expect( Appsignal::Utils.sanitize_key(:ismaster, :mongodb) ).to eql('ismaster')
64
- end
65
- end
66
- end
67
-
68
- describe ".json_generate" do
69
- subject { Appsignal::Utils.json_generate(body) }
70
-
71
- context "with a valid body" do
72
- let(:body) { {'the' => 'payload'} }
73
-
74
- it { should == "{\"the\":\"payload\"}" }
75
- end
76
-
77
- context "with a body that contains strings with invalid utf-8 content" do
78
- let(:string_with_invalid_utf8) { [0x61, 0x61, 0x85].pack('c*') }
79
- let(:body) { {
80
- 'field_one' => [0x61, 0x61].pack('c*'),
81
- 'field_two' => string_with_invalid_utf8,
82
- 'field_three' => [
83
- 'one', string_with_invalid_utf8
84
- ],
85
- 'field_four' => {
86
- 'one' => string_with_invalid_utf8
87
- }
88
- } }
89
-
90
- it { should == "{\"field_one\":\"aa\",\"field_two\":\"aa�\",\"field_three\":[\"one\",\"aa�\"],\"field_four\":{\"one\":\"aa�\"}}" }
91
- end
92
- end
93
-
94
- describe ".encode_utf8" do
95
- subject { Appsignal::Utils.encode_utf8(value) }
96
-
97
- context "value with invalid utf-8 content" do
98
- let(:value) { [0x61, 0x61, 0x85].pack('c*') }
99
-
100
- it { should == "aa�" }
101
- end
102
- end
103
36
  end
@@ -7,6 +7,8 @@ require 'webmock/rspec'
7
7
 
8
8
  puts "Runnings specs in #{RUBY_VERSION} on #{RUBY_PLATFORM}"
9
9
 
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'support/stubs'))
11
+
10
12
  begin
11
13
  require 'rails'
12
14
  Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support/rails','*.rb'))].each {|f| require f}
@@ -21,6 +23,13 @@ def rails_present?
21
23
  RAILS_PRESENT
22
24
  end
23
25
 
26
+ def active_job_present?
27
+ require 'active_job'
28
+ true
29
+ rescue LoadError
30
+ false
31
+ end
32
+
24
33
  def active_record_present?
25
34
  require 'active_record'
26
35
  true
@@ -67,6 +76,13 @@ rescue LoadError
67
76
  false
68
77
  end
69
78
 
79
+ def grape_present?
80
+ require 'grape'
81
+ true
82
+ rescue LoadError
83
+ false
84
+ end
85
+
70
86
  require 'appsignal'
71
87
 
72
88
  Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support/helpers','*.rb'))].each {|f| require f}