appsignal 0.11.7 → 0.11.8.beta.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 667d1d2dfa406916da0c6249befc7528ff83c662
4
- data.tar.gz: 5853d8a6387eba48425f5206bd1d1352e827b0d7
3
+ metadata.gz: 69c0fe4aba981d664f4b5a320c2cf47816ae4598
4
+ data.tar.gz: 546e20aa73e171ca1183c4cba04beed672ced563
5
5
  SHA512:
6
- metadata.gz: 6185e5637b0724d92dcdaaf826474e110bc8959f24ad057a0ddc391c972b175ca8efa498ed9f953211864e726450b8e344983c558082162f6d93a5848c376f3b
7
- data.tar.gz: 91b6b5e685022c0493347161fb28f5c3b040f297231b2ae7e89b70fe43f5671a9b540edc0deaf674fb482ad5f01d97591aa075f22a9cecc75fdaed072f8b0f0a
6
+ metadata.gz: dba3ef8508c2b43ef0456f926397ae29cd34a0b454de79cf3cf10e853386a2bfb90fb2d1e60ef21f9ffcf8e56c9425f6ede6669436430b35e2fb95936851be8c
7
+ data.tar.gz: 26d06743732e417cd38ddf55372f25f80be96f38d55ed5719c3740b746a32cc0579e5f399e75b1b9d31a62564a31d643778ca8a0ff8ddc02ba7142c582762cb8
@@ -1,3 +1,6 @@
1
+ # 0.11.8
2
+ * Add frontend error catcher
3
+
1
4
  # 0.11.7
2
5
  * Add option to override Job name in Delayed Job
3
6
 
@@ -195,6 +195,7 @@ require 'appsignal/marker'
195
195
  require 'appsignal/rack/listener'
196
196
  require 'appsignal/rack/instrumentation'
197
197
  require 'appsignal/rack/sinatra_instrumentation'
198
+ require 'appsignal/rack/js_exception_catcher'
198
199
  require 'appsignal/params_sanitizer'
199
200
  require 'appsignal/transaction'
200
201
  require 'appsignal/transaction/formatter'
@@ -203,3 +204,4 @@ require 'appsignal/transmitter'
203
204
  require 'appsignal/ipc'
204
205
  require 'appsignal/version'
205
206
  require 'appsignal/integrations/rails'
207
+ require 'appsignal/js_exception_transaction'
@@ -7,22 +7,24 @@ module Appsignal
7
7
  include Appsignal::CarefulLogger
8
8
 
9
9
  DEFAULT_CONFIG = {
10
- :ignore_exceptions => [],
11
- :ignore_actions => [],
12
- :send_params => true,
13
- :endpoint => 'https://push.appsignal.com/1',
14
- :slow_request_threshold => 200,
15
- :instrument_net_http => true,
16
- :skip_session_data => false
10
+ :ignore_exceptions => [],
11
+ :ignore_actions => [],
12
+ :send_params => true,
13
+ :endpoint => 'https://push.appsignal.com/1',
14
+ :slow_request_threshold => 200,
15
+ :instrument_net_http => true,
16
+ :skip_session_data => false,
17
+ :enable_frontend_error_catching => false,
18
+ :frontend_error_catching_path => '/appsignal_error_catcher'
17
19
  }.freeze
18
20
 
19
21
  attr_reader :root_path, :env, :initial_config, :config_hash
20
22
 
21
23
  def initialize(root_path, env, initial_config={}, logger=Appsignal.logger)
22
- @root_path = root_path
23
- @env = env.to_s
24
+ @root_path = root_path
25
+ @env = env.to_s
24
26
  @initial_config = initial_config
25
- @logger = logger
27
+ @logger = logger
26
28
 
27
29
  if File.exists?(config_file)
28
30
  load_config_from_disk
@@ -7,6 +7,10 @@ if defined?(::Rails)
7
7
  initializer 'appsignal.configure_rails_initialization' do |app|
8
8
  app.middleware.insert_before(
9
9
  ActionDispatch::RemoteIp,
10
+ Appsignal::Rack::JSExceptionCatcher
11
+ )
12
+ app.middleware.insert_after(
13
+ Appsignal::Rack::JSExceptionCatcher,
10
14
  Appsignal::Rack::Listener
11
15
  )
12
16
  end
@@ -0,0 +1,46 @@
1
+ module Appsignal
2
+ class JSExceptionTransaction
3
+
4
+ def initialize(data)
5
+ @data = data
6
+ @time = Time.now.to_i
7
+ end
8
+
9
+ def type
10
+ :exception
11
+ end
12
+
13
+ def action
14
+ @data['action']
15
+ end
16
+
17
+ def clear_events!; end
18
+ def convert_values_to_primitives!; end
19
+ def events; []; end
20
+
21
+ def to_hash
22
+ {
23
+ :request_id => SecureRandom.uuid,
24
+ :log_entry => {
25
+ :action => action,
26
+ :path => @data['path'],
27
+ :kind => 'frontend',
28
+ :time => @time,
29
+ :environment => @data['environment'],
30
+ :revision => Appsignal.agent.revision
31
+ },
32
+ :exception => {
33
+ :exception => @data['name'],
34
+ :message => @data['message'],
35
+ :backtrace => @data['backtrace']
36
+ },
37
+ :failed => true
38
+ }
39
+ end
40
+
41
+ def complete!
42
+ Appsignal.enqueue(self)
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ module Appsignal
2
+ module Rack
3
+ class JSExceptionCatcher
4
+ def initialize(app, options = {})
5
+ Appsignal.logger.debug 'Initializing Appsignal::Rack::JSExceptionCatcher'
6
+ @app, @options = app, options
7
+ end
8
+
9
+ def call(env)
10
+ if env['PATH_INFO'] == Appsignal.config[:frontend_error_catching_path]
11
+ if Appsignal.config.active? &&
12
+ Appsignal.config[:enable_frontend_error_catching] == true
13
+
14
+ body = JSON.parse(env['rack.input'].read)
15
+ transaction = JSExceptionTransaction.new(body)
16
+ transaction.complete!
17
+ end
18
+ return [ 200, {}, []]
19
+ else
20
+ @app.call(env)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module Appsignal
2
- VERSION = '0.11.7'
2
+ VERSION = '0.11.8.beta.0'
3
3
  end
@@ -16,16 +16,18 @@ describe Appsignal::Config do
16
16
 
17
17
  it "should merge with the default config and fill the config hash" do
18
18
  subject.config_hash.should == {
19
- :ignore_exceptions => [],
20
- :ignore_actions => [],
21
- :instrument_net_http => true,
22
- :skip_session_data => false,
23
- :send_params => true,
24
- :endpoint => 'https://push.appsignal.com/1',
25
- :slow_request_threshold => 200,
26
- :push_api_key => 'abc',
27
- :name => 'TestApp',
28
- :active => true
19
+ :ignore_exceptions => [],
20
+ :ignore_actions => [],
21
+ :instrument_net_http => true,
22
+ :skip_session_data => false,
23
+ :send_params => true,
24
+ :endpoint => 'https://push.appsignal.com/1',
25
+ :slow_request_threshold => 200,
26
+ :push_api_key => 'abc',
27
+ :name => 'TestApp',
28
+ :active => true,
29
+ :enable_frontend_error_catching => false,
30
+ :frontend_error_catching_path => '/appsignal_error_catcher'
29
31
  }
30
32
  end
31
33
 
@@ -127,15 +129,17 @@ describe Appsignal::Config do
127
129
  )
128
130
 
129
131
  subject.config_hash.should == {
130
- :push_api_key => 'push_api_key',
131
- :ignore_exceptions => [],
132
- :ignore_actions => [],
133
- :send_params => true,
134
- :instrument_net_http => true,
135
- :skip_session_data => false,
136
- :endpoint => 'https://push.appsignal.com/1',
137
- :slow_request_threshold => 200,
138
- :active => true
132
+ :push_api_key => 'push_api_key',
133
+ :ignore_exceptions => [],
134
+ :ignore_actions => [],
135
+ :send_params => true,
136
+ :instrument_net_http => true,
137
+ :skip_session_data => false,
138
+ :endpoint => 'https://push.appsignal.com/1',
139
+ :slow_request_threshold => 200,
140
+ :active => true,
141
+ :enable_frontend_error_catching => false,
142
+ :frontend_error_catching_path => '/appsignal_error_catcher'
139
143
  }
140
144
  end
141
145
 
@@ -40,6 +40,10 @@ if rails_present?
40
40
  MyApp::Application.middleware.to_a.should include Appsignal::Rack::Listener
41
41
  end
42
42
 
43
+ it "should have added the js exception catcher middleware" do
44
+ MyApp::Application.middleware.to_a.should include Appsignal::Rack::JSExceptionCatcher
45
+ end
46
+
43
47
  it "should not have added the instrumentation middleware" do
44
48
  MyApp::Application.middleware.to_a.should_not include Appsignal::Rack::Instrumentation
45
49
  end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Appsignal::JSExceptionTransaction do
4
+ let(:transaction) { Appsignal::JSExceptionTransaction.new(data) }
5
+ let(:data) do
6
+ {
7
+ 'name' => 'TypeError',
8
+ 'message' => 'foo is not a valid method',
9
+ 'action' => 'ExceptionIncidentComponent',
10
+ 'path' => 'foo.bar/moo',
11
+ 'environment' => 'development',
12
+ 'backtrace' => [
13
+ 'foo.bar/js:11:1',
14
+ 'foo.bar/js:22:2',
15
+ ]
16
+ }
17
+ end
18
+
19
+ describe "#type" do
20
+ it "should return `:exception`" do
21
+ expect( transaction.type ).to eql :exception
22
+ end
23
+ end
24
+
25
+ describe "#action" do
26
+ it "should return the action" do
27
+ expect( transaction.action ).to eql 'ExceptionIncidentComponent'
28
+ end
29
+ end
30
+
31
+ describe "#clear_events" do
32
+ it "should respond to `clear_events!`" do
33
+ expect( transaction ).to respond_to :clear_events!
34
+ end
35
+ end
36
+
37
+ describe "#convert_values_to_primitives!" do
38
+ it "should respond to `convert_values_to_primitives!`" do
39
+ expect( transaction ).to respond_to :convert_values_to_primitives!
40
+ end
41
+ end
42
+
43
+ describe "#events" do
44
+ it "should respond to `events` with an empty array" do
45
+ expect( transaction.events ).to eql []
46
+ end
47
+ end
48
+
49
+ describe "#to_hash" do
50
+ around do |sample|
51
+ Timecop.freeze(Time.at(123)) { sample.run }
52
+ end
53
+
54
+ before do
55
+ SecureRandom.stub(:uuid => 'uuid')
56
+ Appsignal.stub(:agent => double(:revision => 'abcdef'))
57
+ end
58
+
59
+ it "should generate a hash based on the given data" do
60
+ expect( transaction.to_hash).to eql({
61
+ :request_id => 'uuid',
62
+ :log_entry => {
63
+ :action => 'ExceptionIncidentComponent',
64
+ :path => 'foo.bar/moo',
65
+ :kind => 'frontend',
66
+ :time => 123,
67
+ :environment => 'development',
68
+ :revision => 'abcdef'
69
+ },
70
+ :exception => {
71
+ :exception => 'TypeError',
72
+ :message => 'foo is not a valid method',
73
+ :backtrace => [
74
+ 'foo.bar/js:11:1',
75
+ 'foo.bar/js:22:2',
76
+ ]
77
+ },
78
+ :failed => true
79
+ })
80
+ end
81
+
82
+ describe "#complete!" do
83
+ it "should enqueue itself" do
84
+ expect( Appsignal ).to receive(:enqueue).with(transaction)
85
+
86
+ transaction.complete!
87
+ end
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe Appsignal::Rack::JSExceptionCatcher do
4
+ let(:app) { double(:call => true) }
5
+ let(:options) { double }
6
+ let(:active) { true }
7
+ let(:config_options) { {:enable_frontend_error_catching => true} }
8
+ let(:config) { project_fixture_config('production', config_options) }
9
+
10
+ before do
11
+ Appsignal.stub(:config => config)
12
+ config.stub(:active? => active)
13
+ end
14
+
15
+ describe "#initialize" do
16
+ it "should log to the logger" do
17
+ expect( Appsignal.logger ).to receive(:debug)
18
+ .with('Initializing Appsignal::Rack::JSExceptionCatcher')
19
+
20
+ Appsignal::Rack::JSExceptionCatcher.new(app, options)
21
+ end
22
+ end
23
+
24
+ describe "#call" do
25
+ let(:catcher) { Appsignal::Rack::JSExceptionCatcher.new(app, options) }
26
+
27
+ context "when path is not `/appsignal_error_catcher`" do
28
+ let(:env) { {'PATH_INFO' => '/foo'} }
29
+
30
+ it "should call the next middleware" do
31
+ expect( app ).to receive(:call).with(env)
32
+ end
33
+ end
34
+
35
+ context "when path is `/appsignal_error_catcher`" do
36
+ let(:transaction) { double(:complete! => true) }
37
+ let(:env) do
38
+ {
39
+ 'PATH_INFO' => '/appsignal_error_catcher',
40
+ 'rack.input' => double(:read => '{"foo": "bar"}')
41
+ }
42
+ end
43
+
44
+ it "should create a JSExceptionTransaction" do
45
+ expect( Appsignal::JSExceptionTransaction ).to receive(:new)
46
+ .with({'foo' => 'bar'})
47
+ .and_return(transaction)
48
+
49
+ expect( transaction ).to receive(:complete!)
50
+ end
51
+
52
+ context "when appsignal is not active" do
53
+ let(:active) { false }
54
+
55
+ it "should not create a transaction" do
56
+ expect( Appsignal::JSExceptionTransaction ).to_not receive(:new)
57
+ end
58
+ end
59
+
60
+ context "when `enable_frontend_error_catching` is disabled" do
61
+ let(:config_options) { {:enable_frontend_error_catching => false} }
62
+
63
+ it "should not create a transaction" do
64
+ expect( Appsignal::JSExceptionTransaction ).to_not receive(:new)
65
+ end
66
+ end
67
+
68
+ context "when `frontend_error_catching_path` is different" do
69
+ let(:config_options) do
70
+ {
71
+ :enable_frontend_error_catching => true,
72
+ :frontend_error_catching_path => '/foo'
73
+ }
74
+ end
75
+
76
+ it "should not create a transaction" do
77
+ expect( Appsignal::JSExceptionTransaction ).to_not receive(:new)
78
+ end
79
+
80
+ it "should call the next middleware" do
81
+ expect( app ).to receive(:call).with(env)
82
+ end
83
+ end
84
+ end
85
+
86
+ after { catcher.call(env) }
87
+ end
88
+
89
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.7
4
+ version: 0.11.8.beta.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-02-20 00:00:00.000000000 Z
15
+ date: 2015-03-03 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rack
@@ -170,9 +170,11 @@ files:
170
170
  - lib/appsignal/integrations/sinatra.rb
171
171
  - lib/appsignal/integrations/unicorn.rb
172
172
  - lib/appsignal/ipc.rb
173
+ - lib/appsignal/js_exception_transaction.rb
173
174
  - lib/appsignal/marker.rb
174
175
  - lib/appsignal/params_sanitizer.rb
175
176
  - lib/appsignal/rack/instrumentation.rb
177
+ - lib/appsignal/rack/js_exception_catcher.rb
176
178
  - lib/appsignal/rack/listener.rb
177
179
  - lib/appsignal/rack/sinatra_instrumentation.rb
178
180
  - lib/appsignal/transaction.rb
@@ -213,9 +215,11 @@ files:
213
215
  - spec/lib/appsignal/integrations/sinatra_spec.rb
214
216
  - spec/lib/appsignal/integrations/unicorn_spec.rb
215
217
  - spec/lib/appsignal/ipc_spec.rb
218
+ - spec/lib/appsignal/js_exception_transaction_spec.rb
216
219
  - spec/lib/appsignal/marker_spec.rb
217
220
  - spec/lib/appsignal/params_sanitizer_spec.rb
218
221
  - spec/lib/appsignal/rack/instrumentation_spec.rb
222
+ - spec/lib/appsignal/rack/js_exception_catcher_spec.rb
219
223
  - spec/lib/appsignal/rack/listener_spec.rb
220
224
  - spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb
221
225
  - spec/lib/appsignal/transaction/formatter_spec.rb
@@ -250,9 +254,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
250
254
  version: '1.9'
251
255
  required_rubygems_version: !ruby/object:Gem::Requirement
252
256
  requirements:
253
- - - ">="
257
+ - - ">"
254
258
  - !ruby/object:Gem::Version
255
- version: '0'
259
+ version: 1.3.1
256
260
  requirements: []
257
261
  rubyforge_project:
258
262
  rubygems_version: 2.2.2
@@ -284,9 +288,11 @@ test_files:
284
288
  - spec/lib/appsignal/integrations/sinatra_spec.rb
285
289
  - spec/lib/appsignal/integrations/unicorn_spec.rb
286
290
  - spec/lib/appsignal/ipc_spec.rb
291
+ - spec/lib/appsignal/js_exception_transaction_spec.rb
287
292
  - spec/lib/appsignal/marker_spec.rb
288
293
  - spec/lib/appsignal/params_sanitizer_spec.rb
289
294
  - spec/lib/appsignal/rack/instrumentation_spec.rb
295
+ - spec/lib/appsignal/rack/js_exception_catcher_spec.rb
290
296
  - spec/lib/appsignal/rack/listener_spec.rb
291
297
  - spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb
292
298
  - spec/lib/appsignal/transaction/formatter_spec.rb