appsignal 0.11.18 → 0.12.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGELOG.md +4 -38
  3. data/Rakefile +14 -6
  4. data/appsignal.gemspec +3 -1
  5. data/benchmark.rake +12 -16
  6. data/ext/appsignal_extension.c +183 -0
  7. data/ext/extconf.rb +39 -0
  8. data/gemfiles/capistrano2.gemfile +0 -1
  9. data/gemfiles/capistrano3.gemfile +0 -1
  10. data/gemfiles/rails-4.2.gemfile +1 -1
  11. data/lib/appsignal.rb +23 -61
  12. data/lib/appsignal/capistrano.rb +1 -2
  13. data/lib/appsignal/config.rb +13 -1
  14. data/lib/appsignal/event_formatter.rb +67 -0
  15. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +23 -0
  16. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +74 -0
  17. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  18. data/lib/appsignal/event_formatter/net_http/request_formatter.rb +13 -0
  19. data/lib/appsignal/instrumentations/net_http.rb +6 -4
  20. data/lib/appsignal/integrations/resque.rb +2 -10
  21. data/lib/appsignal/integrations/sidekiq.rb +2 -2
  22. data/lib/appsignal/integrations/sinatra.rb +1 -0
  23. data/lib/appsignal/js_exception_transaction.rb +44 -28
  24. data/lib/appsignal/marker.rb +11 -13
  25. data/lib/appsignal/params_sanitizer.rb +5 -8
  26. data/lib/appsignal/rack/instrumentation.rb +2 -0
  27. data/lib/appsignal/rack/js_exception_catcher.rb +1 -0
  28. data/lib/appsignal/rack/listener.rb +1 -1
  29. data/lib/appsignal/rack/sinatra_instrumentation.rb +2 -12
  30. data/lib/appsignal/subscriber.rb +59 -0
  31. data/lib/appsignal/transaction.rb +117 -174
  32. data/lib/appsignal/transmitter.rb +8 -37
  33. data/lib/appsignal/version.rb +2 -1
  34. data/spec/lib/appsignal/config_spec.rb +25 -4
  35. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +42 -0
  36. data/spec/lib/appsignal/{aggregator/middleware/active_record_sanitizer_spec.rb → event_formatter/active_record/sql_formatter_spec.rb} +61 -61
  37. data/spec/lib/appsignal/{event/moped_event_spec.rb → event_formatter/moped/query_formatter_spec.rb} +32 -78
  38. data/spec/lib/appsignal/event_formatter/net_http/request_formatter_spec.rb +26 -0
  39. data/spec/lib/appsignal/event_formatter_spec.rb +102 -0
  40. data/spec/lib/appsignal/extension_spec.rb +75 -0
  41. data/spec/lib/appsignal/instrumentations/net_http_spec.rb +20 -4
  42. data/spec/lib/appsignal/integrations/delayed_job_spec.rb +3 -2
  43. data/spec/lib/appsignal/integrations/rails_spec.rb +0 -7
  44. data/spec/lib/appsignal/integrations/resque_spec.rb +51 -55
  45. data/spec/lib/appsignal/integrations/sequel_spec.rb +8 -3
  46. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -21
  47. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -6
  48. data/spec/lib/appsignal/js_exception_transaction_spec.rb +57 -60
  49. data/spec/lib/appsignal/params_sanitizer_spec.rb +11 -27
  50. data/spec/lib/appsignal/rack/listener_spec.rb +6 -6
  51. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +2 -43
  52. data/spec/lib/appsignal/subscriber_spec.rb +162 -0
  53. data/spec/lib/appsignal/transaction_spec.rb +283 -615
  54. data/spec/lib/appsignal/transmitter_spec.rb +3 -32
  55. data/spec/lib/appsignal_spec.rb +41 -90
  56. data/spec/lib/generators/appsignal/appsignal_generator_spec.rb +0 -17
  57. data/spec/spec_helper.rb +18 -22
  58. data/spec/support/helpers/notification_helpers.rb +1 -1
  59. data/spec/support/helpers/time_helpers.rb +11 -0
  60. data/spec/support/helpers/transaction_helpers.rb +6 -18
  61. data/spec/support/project_fixture/config/appsignal.yml +1 -2
  62. metadata +68 -78
  63. checksums.yaml +0 -7
  64. data/gemfiles/padrino-0.13.gemfile +0 -7
  65. data/gemfiles/resque.gemfile +0 -5
  66. data/lib/appsignal/agent.rb +0 -217
  67. data/lib/appsignal/aggregator.rb +0 -67
  68. data/lib/appsignal/aggregator/middleware.rb +0 -4
  69. data/lib/appsignal/aggregator/middleware/action_view_sanitizer.rb +0 -23
  70. data/lib/appsignal/aggregator/middleware/active_record_sanitizer.rb +0 -65
  71. data/lib/appsignal/aggregator/middleware/chain.rb +0 -101
  72. data/lib/appsignal/aggregator/middleware/delete_blanks.rb +0 -16
  73. data/lib/appsignal/aggregator/post_processor.rb +0 -32
  74. data/lib/appsignal/event.rb +0 -20
  75. data/lib/appsignal/event/moped_event.rb +0 -90
  76. data/lib/appsignal/integrations/padrino.rb +0 -64
  77. data/lib/appsignal/integrations/passenger.rb +0 -13
  78. data/lib/appsignal/integrations/rake.rb +0 -29
  79. data/lib/appsignal/integrations/unicorn.rb +0 -25
  80. data/lib/appsignal/ipc.rb +0 -68
  81. data/lib/appsignal/transaction/formatter.rb +0 -85
  82. data/lib/appsignal/transaction/params_sanitizer.rb +0 -4
  83. data/lib/appsignal/zipped_payload.rb +0 -37
  84. data/spec/lib/appsignal/agent_spec.rb +0 -592
  85. data/spec/lib/appsignal/aggregator/middleware/action_view_sanitizer_spec.rb +0 -44
  86. data/spec/lib/appsignal/aggregator/middleware/chain_spec.rb +0 -168
  87. data/spec/lib/appsignal/aggregator/middleware/delete_blanks_spec.rb +0 -37
  88. data/spec/lib/appsignal/aggregator/post_processor_spec.rb +0 -99
  89. data/spec/lib/appsignal/aggregator_spec.rb +0 -186
  90. data/spec/lib/appsignal/event_spec.rb +0 -48
  91. data/spec/lib/appsignal/integrations/padrino_spec.rb +0 -171
  92. data/spec/lib/appsignal/integrations/passenger_spec.rb +0 -22
  93. data/spec/lib/appsignal/integrations/rake_spec.rb +0 -92
  94. data/spec/lib/appsignal/integrations/unicorn_spec.rb +0 -48
  95. data/spec/lib/appsignal/ipc_spec.rb +0 -128
  96. data/spec/lib/appsignal/transaction/formatter_spec.rb +0 -247
  97. data/spec/lib/appsignal/zipped_payload_spec.rb +0 -42
@@ -4,7 +4,6 @@ describe Appsignal::Transmitter do
4
4
  let(:config) { project_fixture_config }
5
5
  let(:action) { 'action' }
6
6
  let(:instance) { Appsignal::Transmitter.new(action, config) }
7
- let!(:payload) { Appsignal::ZippedPayload.new({'the' => 'payload'}) }
8
7
 
9
8
  describe "#uri" do
10
9
  before { Socket.stub(:gethostname => 'app1.local') }
@@ -35,27 +34,9 @@ describe Appsignal::Transmitter do
35
34
  )
36
35
  end
37
36
 
38
- it "should post the ZippedPayload" do
39
- instance.transmit(payload).should == '200'
40
- end
41
-
42
- it "should not instantiate a new ZippedPayload" do
43
- expect( Appsignal::ZippedPayload ).to_not receive(:new)
44
- instance.transmit(payload)
45
- end
37
+ subject { instance.transmit(:the => :payload) }
46
38
 
47
- context "when not given a ZippedPayload, but a hash" do
48
- it "should post the ZippedPayload" do
49
- instance.transmit({'the' => 'payload'}).should == '200'
50
- end
51
-
52
- it "should instantiate a new ZippedPayload" do
53
- expect( Appsignal::ZippedPayload ).to receive(:new).with({'the' => 'payload'})
54
- .and_return(payload)
55
- .at_least(:once)
56
- instance.transmit({'the' => 'payload'})
57
- end
58
- end
39
+ it { should == '200' }
59
40
  end
60
41
 
61
42
  describe "#http_post" do
@@ -63,7 +44,7 @@ describe Appsignal::Transmitter do
63
44
  Socket.stub(:gethostname => 'app1.local')
64
45
  end
65
46
 
66
- subject { instance.send(:http_post, payload) }
47
+ subject { instance.send(:http_post, 'the' => 'payload') }
67
48
 
68
49
  its(:body) { should == Zlib::Deflate.deflate("{\"the\":\"payload\"}", Zlib::BEST_SPEED) }
69
50
  its(:path) { should == instance.uri.request_uri }
@@ -88,7 +69,6 @@ describe Appsignal::Transmitter do
88
69
  let(:config) { project_fixture_config('test') }
89
70
 
90
71
  it { should be_instance_of(Net::HTTP) }
91
- its(:proxy?) { should be_false }
92
72
  its(:use_ssl?) { should be_false }
93
73
  end
94
74
 
@@ -96,18 +76,9 @@ describe Appsignal::Transmitter do
96
76
  let(:config) { project_fixture_config('production') }
97
77
 
98
78
  it { should be_instance_of(Net::HTTP) }
99
- its(:proxy?) { should be_false }
100
79
  its(:use_ssl?) { should be_true }
101
80
  its(:verify_mode) { should == OpenSSL::SSL::VERIFY_PEER }
102
81
  its(:ca_file) { Appsignal::Transmitter::CA_FILE_PATH }
103
82
  end
104
-
105
- context "with a proxy" do
106
- let(:config) { project_fixture_config('production', :http_proxy => 'http://localhost:8080') }
107
-
108
- its(:proxy?) { should be_true }
109
- its(:proxy_address) { should == 'localhost' }
110
- its(:proxy_port) { should == 8080 }
111
- end
112
83
  end
113
84
  end
@@ -43,12 +43,16 @@ describe Appsignal do
43
43
  context "when config is loaded" do
44
44
  before { Appsignal.config = project_fixture_config }
45
45
 
46
- it "should start an agent" do
46
+ it "should initialize logging" do
47
47
  Appsignal.start
48
- Appsignal.agent.should be_a Appsignal::Agent
49
48
  Appsignal.logger.level.should == Logger::INFO
50
49
  end
51
50
 
51
+ it "should start native" do
52
+ Appsignal::Extension.should_receive(:start)
53
+ Appsignal.start
54
+ end
55
+
52
56
  it "should load integrations" do
53
57
  Appsignal.should_receive(:load_integrations)
54
58
  Appsignal.start
@@ -59,6 +63,16 @@ describe Appsignal do
59
63
  Appsignal.start
60
64
  end
61
65
 
66
+ it "should initialize formatters" do
67
+ Appsignal::EventFormatter.should_receive(:initialize_formatters)
68
+ Appsignal.start
69
+ end
70
+
71
+ it "should create a subscriber" do
72
+ Appsignal.start
73
+ Appsignal.subscriber.should be_a(Appsignal::Subscriber)
74
+ end
75
+
62
76
  context "when not active for this environment" do
63
77
  before { Appsignal.config = project_fixture_config('staging') }
64
78
 
@@ -124,28 +138,25 @@ describe Appsignal do
124
138
  describe '.active?' do
125
139
  subject { Appsignal.active? }
126
140
 
127
- context "without config and agent" do
141
+ context "without config" do
128
142
  before do
129
143
  Appsignal.config = nil
130
- Appsignal.agent = nil
131
144
  end
132
145
 
133
146
  it { should be_false }
134
147
  end
135
148
 
136
- context "with agent and inactive config" do
149
+ context "with inactive config" do
137
150
  before do
138
151
  Appsignal.config = project_fixture_config('nonsense')
139
- Appsignal.agent = Appsignal::Agent.new
140
152
  end
141
153
 
142
154
  it { should be_false }
143
155
  end
144
156
 
145
- context "with active agent and config" do
157
+ context "with active config" do
146
158
  before do
147
159
  Appsignal.config = project_fixture_config
148
- Appsignal.agent = Appsignal::Agent.new
149
160
  end
150
161
 
151
162
  it { should be_true }
@@ -153,14 +164,6 @@ describe Appsignal do
153
164
  end
154
165
 
155
166
  context "not active" do
156
- describe ".enqueue" do
157
- it "should do nothing" do
158
- lambda {
159
- Appsignal.enqueue(Appsignal::Transaction.create(SecureRandom.uuid, ENV))
160
- }.should_not raise_error
161
- end
162
- end
163
-
164
167
  describe ".monitor_transaction" do
165
168
  it "should do nothing but still yield the block" do
166
169
  Appsignal::Transaction.should_not_receive(:create)
@@ -195,10 +198,10 @@ describe Appsignal do
195
198
  end
196
199
  end
197
200
 
198
- describe ".add_exception" do
201
+ describe ".set_exception" do
199
202
  it "should do nothing" do
200
203
  lambda {
201
- Appsignal.add_exception(RuntimeError.new)
204
+ Appsignal.set_exception(RuntimeError.new)
202
205
  }.should_not raise_error
203
206
  end
204
207
  end
@@ -218,16 +221,6 @@ describe Appsignal do
218
221
  Appsignal.start
219
222
  end
220
223
 
221
- describe ".enqueue" do
222
- subject { Appsignal.enqueue(transaction) }
223
-
224
- it "forwards the call to the agent" do
225
- Appsignal.agent.should respond_to(:enqueue)
226
- Appsignal.agent.should_receive(:enqueue).with(transaction)
227
- subject
228
- end
229
- end
230
-
231
224
  describe ".monitor_transaction" do
232
225
  context "with a normall call" do
233
226
  it "should instrument and complete" do
@@ -236,7 +229,7 @@ describe Appsignal do
236
229
  'perform_job.something',
237
230
  :class => 'Something'
238
231
  ).and_yield
239
- transaction.should_receive(:complete!)
232
+ Appsignal::Transaction.should_receive(:complete_current!)
240
233
  object = double
241
234
  object.should_receive(:some_method)
242
235
 
@@ -253,7 +246,7 @@ describe Appsignal do
253
246
  let(:error) { VerySpecificError.new('the roof') }
254
247
 
255
248
  it "should add the error to the current transaction and complete" do
256
- Appsignal.should_receive(:add_exception).with(error)
249
+ Appsignal.should_receive(:set_exception).with(error)
257
250
  Appsignal::Transaction.should_receive(:complete_current!)
258
251
 
259
252
  lambda {
@@ -291,12 +284,6 @@ describe Appsignal do
291
284
  end
292
285
  end
293
286
 
294
- describe ".transactions" do
295
- subject { Appsignal.transactions }
296
-
297
- it { should be_a Hash }
298
- end
299
-
300
287
  describe '.logger' do
301
288
  subject { Appsignal.logger }
302
289
 
@@ -376,43 +363,14 @@ describe Appsignal do
376
363
 
377
364
  it { should be_a Appsignal::Config }
378
365
  it 'should return configuration' do
379
- subject[:endpoint].should == 'https://push.appsignal.com/1'
366
+ subject[:endpoint].should == 'https://push.appsignal.com'
380
367
  end
381
368
  end
382
369
 
383
- describe ".post_processing_middleware" do
384
- before { Appsignal.instance_variable_set(:@post_processing_chain, nil) }
385
-
386
- it "returns the default middleware stack" do
387
- Appsignal::Aggregator::PostProcessor.should_receive(:default_middleware)
388
- Appsignal.post_processing_middleware
389
- end
390
-
391
- it "returns a chain when called without a block" do
392
- instance = Appsignal.post_processing_middleware
393
- instance.should be_an_instance_of Appsignal::Aggregator::Middleware::Chain
394
- end
395
-
396
- context "when passing a block" do
397
- it "yields an appsignal middleware chain" do
398
- Appsignal.post_processing_middleware do |o|
399
- o.should be_an_instance_of Appsignal::Aggregator::Middleware::Chain
400
- end
401
- end
402
- end
403
- end
404
-
405
- describe ".send_exception" do
406
- let(:tags) { nil }
407
- let(:exception) { VerySpecificError.new }
408
- before { Appsignal::IPC.stub(:current => false) }
370
+ describe ".send_error" do
371
+ let(:tags) { nil }
409
372
 
410
373
  it "should send the exception to AppSignal" do
411
- agent = double(:shutdown => true, :active? => true)
412
- Appsignal.stub(:agent).and_return(agent)
413
- agent.should_receive(:send_queue)
414
- agent.should_receive(:enqueue).with(kind_of(Appsignal::Transaction))
415
-
416
374
  Appsignal::Transaction.should_receive(:create).and_call_original
417
375
  end
418
376
 
@@ -423,6 +381,7 @@ describe Appsignal do
423
381
  transaction = Appsignal::Transaction.create(SecureRandom.uuid, {})
424
382
  Appsignal::Transaction.stub(:create => transaction)
425
383
  transaction.should_receive(:set_tags).with(tags)
384
+ Appsignal::Transaction.should_receive(:complete_current!)
426
385
  end
427
386
  end
428
387
 
@@ -431,20 +390,12 @@ describe Appsignal do
431
390
  Appsignal::Transaction.should_not_receive(:create)
432
391
  end
433
392
 
434
- context "when given class is not an exception" do
435
- let(:exception) { double }
436
-
437
- it "should log a message" do
438
- expect( Appsignal.logger ).to receive(:error).with('Can\'t send exception, given value is not an exception')
439
- end
440
-
441
- it "should not send the exception" do
442
- expect( Appsignal::Transaction ).to_not receive(:create)
443
- end
444
- end
445
-
446
393
  after do
447
- Appsignal.send_exception(exception, tags) rescue Exception
394
+ begin
395
+ raise "I am an exception"
396
+ rescue Exception => e
397
+ Appsignal.send_exception(e, tags)
398
+ end
448
399
  end
449
400
  end
450
401
 
@@ -459,36 +410,36 @@ describe Appsignal do
459
410
  end
460
411
  end
461
412
 
462
- describe ".add_exception" do
413
+ describe ".set_exception" do
463
414
  before { Appsignal::Transaction.stub(:current => transaction) }
464
415
  let(:exception) { RuntimeError.new('I am an exception') }
465
416
 
466
417
  it "should add the exception to the current transaction" do
467
- transaction.should_receive(:add_exception).with(exception)
418
+ transaction.should_receive(:set_error).with(exception)
468
419
 
469
- Appsignal.add_exception(exception)
420
+ Appsignal.set_exception(exception)
470
421
  end
471
422
 
472
423
  it "should do nothing if there is no current transaction" do
473
424
  Appsignal::Transaction.stub(:current => nil)
474
425
 
475
- transaction.should_not_receive(:add_exception).with(exception)
426
+ transaction.should_not_receive(:set_exception).with(exception)
476
427
 
477
- Appsignal.add_exception(exception)
428
+ Appsignal.set_exception(exception)
478
429
  end
479
430
 
480
431
  it "should not add the exception if it's in the ignored list" do
481
432
  Appsignal.stub(:is_ignored_exception? => true)
482
433
 
483
- transaction.should_not_receive(:add_exception).with(exception)
434
+ transaction.should_not_receive(:set_exception).with(exception)
484
435
 
485
- Appsignal.add_exception(exception)
436
+ Appsignal.set_exception(exception)
486
437
  end
487
438
 
488
439
  it "should do nothing if the exception is nil" do
489
- transaction.should_not_receive(:add_exception)
440
+ transaction.should_not_receive(:set_exception)
490
441
 
491
- Appsignal.add_exception(nil)
442
+ Appsignal.set_exception(nil)
492
443
  end
493
444
  end
494
445
 
@@ -50,7 +50,6 @@ if rails_present?
50
50
  end
51
51
 
52
52
  it "should mention successful auth check" do
53
- @output.should include('success')
54
53
  @output.should include('AppSignal has confirmed authorization!')
55
54
  end
56
55
  end
@@ -82,22 +81,6 @@ if rails_present?
82
81
  @output.should include('Could not confirm authorization')
83
82
  end
84
83
  end
85
-
86
- context "internal failure" do
87
- before do
88
- authcheck.stub(:perform).and_throw(:error)
89
-
90
- prepare_destination
91
- run_generator_in_tmp %w(my_app_key)
92
- end
93
-
94
- it "should mention internal failure" do
95
- @output.should include(
96
- 'Something went wrong while trying to '\
97
- 'authenticate with AppSignal:'
98
- )
99
- end
100
- end
101
84
  end
102
85
 
103
86
  context "without key" do
@@ -20,13 +20,6 @@ def rails_present?
20
20
  RAILS_PRESENT
21
21
  end
22
22
 
23
- def active_record_present?
24
- require 'active_record'
25
- true
26
- rescue LoadError
27
- false
28
- end
29
-
30
23
  def running_jruby?
31
24
  defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
32
25
  end
@@ -52,20 +45,6 @@ rescue LoadError
52
45
  false
53
46
  end
54
47
 
55
- def resque_present?
56
- require 'resque'
57
- true
58
- rescue LoadError
59
- false
60
- end
61
-
62
- def padrino_present?
63
- require 'padrino'
64
- true
65
- rescue LoadError
66
- false
67
- end
68
-
69
48
  require 'appsignal'
70
49
 
71
50
  Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support/helpers','*.rb'))].each {|f| require f}
@@ -78,9 +57,22 @@ def fixtures_dir
78
57
  @fixtures_dir ||= File.expand_path(File.join(File.dirname(__FILE__), 'support/fixtures'))
79
58
  end
80
59
 
60
+ # Add way to clear subscribers between specs
61
+ module ActiveSupport
62
+ module Notifications
63
+ class Fanout
64
+ def clear_subscribers
65
+ @subscribers.clear
66
+ @listeners_for.clear
67
+ end
68
+ end
69
+ end
70
+ end
71
+
81
72
  RSpec.configure do |config|
82
73
  config.include ConfigHelpers
83
74
  config.include NotificationHelpers
75
+ config.include TimeHelpers
84
76
  config.include TransactionHelpers
85
77
 
86
78
  config.before do
@@ -91,9 +83,13 @@ RSpec.configure do |config|
91
83
  end
92
84
 
93
85
  config.after do
94
- FileUtils.rm_f(File.join(project_fixture_path, 'log/appsignal.log'))
95
86
  Appsignal.logger = nil
96
87
  end
88
+
89
+ config.after :all do
90
+ ActiveSupport::Notifications.notifier.clear_subscribers
91
+ FileUtils.rm_f(File.join(project_fixture_path, 'log/appsignal.log'))
92
+ end
97
93
  end
98
94
 
99
95
  class VerySpecificError < RuntimeError
@@ -7,7 +7,7 @@ module NotificationHelpers
7
7
  :tid => '1',
8
8
  :payload => create_payload
9
9
  }.merge(args)
10
- Appsignal::Event.new(
10
+ ActiveSupport::Notifications::Event.new(
11
11
  args[:name], args[:start], args[:ending], args[:tid], args[:payload]
12
12
  )
13
13
  end
@@ -0,0 +1,11 @@
1
+ module TimeHelpers
2
+ def fixed_time
3
+ @fixed_time ||= Time.utc(2014, 01, 15, 11, 0, 0).to_f
4
+ end
5
+
6
+ def advance_frozen_time(time, addition)
7
+ Time.at(time.to_f + addition).tap do |new_time|
8
+ Timecop.freeze(new_time)
9
+ end
10
+ end
11
+ end