errplane 0.4.12 → 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/README.md CHANGED
@@ -21,7 +21,7 @@ Start by adding the gem to your Gemfile:
21
21
  Then, issue the following commands in your application's root directory:
22
22
 
23
23
  bundle
24
- rails g errplane --api-key your-api-key-goes-here
24
+ rails g errplane your-api-key-goes-here
25
25
 
26
26
  This will create `config/initializers/errplane.rb` for you automatically. If you want to make sure that everything's working correctly, just run:
27
27
 
data/Rakefile CHANGED
@@ -3,7 +3,6 @@
3
3
  if ENV["BUNDLE_GEMFILE"] == File.expand_path("Gemfile")
4
4
  ENV["BUNDLE_GEMFILE"] = "gemfiles/Gemfile.rails-3.2.x"
5
5
  end
6
- puts "RAKEFILE"
7
6
 
8
7
  require 'bundler'
9
8
  Bundler::GemHelper.install_tasks
data/lib/errplane.rb CHANGED
@@ -1,6 +1,7 @@
1
- require 'net/http'
2
- require 'net/https'
3
- require 'rubygems'
1
+ require "net/http"
2
+ require "net/https"
3
+ require "rubygems"
4
+ require "socket"
4
5
 
5
6
  require "json" unless Hash.respond_to?(:to_json)
6
7
 
@@ -30,6 +31,32 @@ module Errplane
30
31
  @configuration ||= Configuration.new
31
32
  end
32
33
 
34
+ def report(name, params = {})
35
+ Errplane::Relay.queue.push({
36
+ :name => name,
37
+ :source => "custom",
38
+ :timestamp => current_timestamp
39
+ }.merge(params))
40
+ end
41
+
42
+ def heartbeat(name, interval)
43
+ log :debug, "Starting heartbeat '#{name}' on a #{interval} second interval."
44
+ Thread.new do
45
+ while true do
46
+ log :debug, "Sleeping '#{name}' for #{interval} seconds."
47
+ sleep(interval)
48
+ report(name)
49
+ end
50
+ end
51
+ end
52
+
53
+ def time(name = nil)
54
+ start_time = Time.now
55
+ yield
56
+ elapsed_time = Time.now - start_time
57
+ report("timed_blocks/#{(name || Socket.gethostname)}", :value => (elapsed_time*1000).ceil)
58
+ end
59
+
33
60
  def transmit_unless_ignorable(e, env)
34
61
  begin
35
62
  black_box = assemble_black_box_for(e, env)
@@ -61,6 +88,10 @@ module Errplane
61
88
  end
62
89
  end
63
90
 
91
+ def current_timestamp
92
+ Time.now.utc.to_i
93
+ end
94
+
64
95
  def ignorable_exception?(e)
65
96
  configuration.ignore_current_environment? || configuration.ignored_exceptions.include?(e.class.to_s)
66
97
  end
@@ -95,4 +126,5 @@ module Errplane
95
126
  end
96
127
  end
97
128
 
129
+ require "errplane/instrumentation"
98
130
  require "errplane/sinatra" if defined?(Sinatra::Request)
@@ -40,7 +40,7 @@ module Errplane
40
40
 
41
41
  Errplane.configuration.add_custom_exception_data(self)
42
42
 
43
- payload[:request_data] = request_data if @controller || @action || !params.empty?
43
+ payload[:request_data] = request_data if @controller || @action || !@params.blank?
44
44
  payload[:hash] = hash if hash
45
45
 
46
46
  payload.to_json
@@ -20,6 +20,7 @@ module Errplane
20
20
 
21
21
  attr_accessor :environment_variables
22
22
 
23
+ attr_accessor :instrumentation_enabled
23
24
  attr_accessor :debug
24
25
  attr_accessor :reraise_global_exceptions
25
26
 
@@ -54,12 +55,17 @@ module Errplane
54
55
  @backtrace_filters = DEFAULTS[:backtrace_filters].dup
55
56
  @debug = false
56
57
  @rescue_global_exceptions = false
58
+ @instrumentation_enabled = true
57
59
  end
58
60
 
59
61
  def debug?
60
62
  !!@debug
61
63
  end
62
64
 
65
+ def instrumentation_enabled?
66
+ !!@instrumentation_enabled
67
+ end
68
+
63
69
  def reraise_global_exceptions?
64
70
  !!@reraise_global_exceptions
65
71
  end
@@ -0,0 +1,101 @@
1
+ require 'thread'
2
+ require "net/http"
3
+ require "uri"
4
+ require "base64"
5
+
6
+ module Errplane
7
+ class Relay
8
+ @@queue = Queue.new
9
+
10
+ def self.queue
11
+ return @@queue
12
+ end
13
+
14
+ def self.initialize
15
+ @@queue = Queue.new
16
+ end
17
+ end
18
+
19
+ class Instrumentation
20
+ class << self
21
+ include Errplane::Logger
22
+
23
+ def indent_lines(lines, num)
24
+ lines.split("\n").map {|line| (" " * num) + line}.join("\n")
25
+ end
26
+
27
+ def post_data(data)
28
+ if Errplane.configuration.ignore_current_environment?
29
+ log :debug, "Current environment is ignored, skipping POST."
30
+ else
31
+ log :info, "Posting data:\n#{indent_lines(data, 13)}"
32
+ http = Net::HTTP.new("api1.errplane.com", "8086")
33
+ url = "/api/v2/time_series/applications/#{Errplane.configuration.application_id}/environments/#{Errplane.configuration.rails_environment}?api_key=ignored"
34
+ response = http.post(url, data)
35
+ log :info, "Posting to: #{url}"
36
+ log :info, "Response code: #{response.code}"
37
+ end
38
+ end
39
+
40
+ def spawn_thread()
41
+ Thread.new do
42
+ log :debug, "Spawning background thread."
43
+ while true
44
+ log :debug, "Checking background queue."
45
+ sleep 5
46
+ begin
47
+ data = [].tap do |line|
48
+ while !Errplane::Relay.queue.empty?
49
+ log :debug, "Found data in the queue."
50
+ n = Errplane::Relay.queue.pop
51
+
52
+ case n[:source]
53
+ when "active_support"
54
+ case n[:name].to_s
55
+ when "process_action.action_controller"
56
+ timediff = n[:finish] - n[:start]
57
+ line << "controllers/#{n[:payload][:controller]}/#{n[:payload][:action]} #{(timediff*1000).ceil} #{n[:finish].utc.to_i}"
58
+ line << "views #{n[:payload][:view_runtime].ceil} #{n[:finish].utc.to_i }"
59
+ line << "db #{n[:payload][:db_runtime].ceil} #{n[:finish].utc.to_i }"
60
+ end
61
+ when "custom"
62
+ s = "#{n[:name]} #{n[:value] || 1} #{n[:timestamp]}"
63
+ s << " #{Base64.encode64(n[:message])}" if n[:message]
64
+ line << s
65
+ end
66
+ end
67
+ end
68
+ post_data(data.join("\n")) unless data.empty?
69
+ rescue => e
70
+ log :info, "Instrumentation Error! #{e.inspect}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ if defined?(ActiveSupport::Notifications) #&& Errplane.configuration.instrumentation_enabled?
79
+ ActiveSupport::Notifications.subscribe do |name, start, finish, id, payload|
80
+ h = { :name => name,
81
+ :start => start,
82
+ :finish => finish,
83
+ :nid => id,
84
+ :payload => payload,
85
+ :source => "active_support"}
86
+ Errplane::Relay.queue.push h
87
+ end
88
+ end
89
+
90
+ if defined?(PhusionPassenger)
91
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
92
+ if forked
93
+ Errplane::Relay.initialize
94
+ Errplane::Instrumentation.spawn_thread()
95
+ end
96
+ end
97
+ else
98
+ Errplane::Relay.initialize
99
+ Errplane::Instrumentation.spawn_thread()
100
+ end
101
+ end
@@ -2,8 +2,12 @@ module Errplane
2
2
  module Rails
3
3
  module AirTrafficController
4
4
  def errplane_request_data
5
+ use_params = params.to_hash
6
+ if respond_to?(:filter_parameters)
7
+ use_params = filter_parameters(use_params)
8
+ end
5
9
  {
6
- :params => params.to_hash,
10
+ :params => use_params,
7
11
  :session_data => errplane_session_data,
8
12
  :controller => params[:controller],
9
13
  :action => params[:action],
@@ -42,7 +42,13 @@ module Errplane
42
42
  response = ::Rails.application.call(env)
43
43
 
44
44
  if response.try(:first) == 500
45
- puts "Done. Check your email or http://errplane.com for the exception notice."
45
+ if Errplane.transmitter.last_response.nil?
46
+ puts "Uh oh. Your app threw an exception, but we didn't get a response. Check your network connection and try again."
47
+ elsif Errplane.transmitter.last_response.code == "201"
48
+ puts "Done. Check your email or http://errplane.com for the exception notice."
49
+ else
50
+ puts "That didn't work. The Errplane API said: #{Errplane.transmitter.last_response.body}"
51
+ end
46
52
  else
47
53
  puts "Request failed: #{response}"
48
54
 
@@ -51,7 +57,13 @@ module Errplane
51
57
  response = ::Rails.application.call(env)
52
58
 
53
59
  if response.try(:first) == 500
54
- puts "Done. Check your email or http://errplane.com for the exception notice."
60
+ if Errplane.transmitter.last_response.nil?
61
+ puts "Uh oh. Your app threw an exception, but we didn't get a response. Check your network connection and try again."
62
+ elsif Errplane.transmitter.last_response.code == "201"
63
+ puts "Done. Check your email or http://errplane.com for the exception notice."
64
+ else
65
+ puts "That didn't work. The Errplane API said: #{Errplane.transmitter.last_response.body}"
66
+ end
55
67
  else
56
68
  puts "Request failed: #{response}"
57
69
  puts "We didn't get the exception we were expecting. Contact support@errplane.com and send them all of this output."
@@ -2,6 +2,8 @@ module Errplane
2
2
  class Transmitter
3
3
  include Errplane::Logger
4
4
 
5
+ attr_reader :last_response
6
+
5
7
  HTTP_ERRORS = [ EOFError,
6
8
  Errno::ECONNREFUSED,
7
9
  Errno::ECONNRESET,
@@ -12,6 +14,7 @@ module Errplane
12
14
  Timeout::Error ].freeze
13
15
 
14
16
  def initialize(params = {})
17
+ @last_response = nil
15
18
  end
16
19
 
17
20
  def relay(black_box, deployment = false)
@@ -26,6 +29,7 @@ module Errplane
26
29
  log :error, "HTTP error contacting Errplane API! #{e.class}: #{e.message}"
27
30
  end
28
31
 
32
+ @last_response = response
29
33
  if response.is_a?(Net::HTTPSuccess)
30
34
  log :info, "Request Succeeded: #{response.inspect}"
31
35
  else
@@ -1,3 +1,3 @@
1
1
  module Errplane
2
- VERSION = "0.4.12"
2
+ VERSION = "0.5.0"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,6 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
3
  ENV["RAILS_ENV"] ||= "test"
4
4
 
5
- puts "CALLING"
6
5
  require 'rails/version'
7
6
 
8
7
  if Rails::VERSION::MAJOR > 2
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: errplane
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.12
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-06 00:00:00.000000000 Z
12
+ date: 2012-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &70275484338460 !ruby/object:Gem::Requirement
16
+ requirement: &70165371262220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70275484338460
24
+ version_requirements: *70165371262220
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activesupport
27
- requirement: &70275484337800 !ruby/object:Gem::Requirement
27
+ requirement: &70165371261120 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.3.14
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70275484337800
35
+ version_requirements: *70165371261120
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: actionpack
38
- requirement: &70275484337140 !ruby/object:Gem::Requirement
38
+ requirement: &70165371260600 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.3.14
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70275484337140
46
+ version_requirements: *70165371260600
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &70275484336380 !ruby/object:Gem::Requirement
49
+ requirement: &70165371259960 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70275484336380
57
+ version_requirements: *70165371259960
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: fakeweb
60
- requirement: &70275484335580 !ruby/object:Gem::Requirement
60
+ requirement: &70165371259200 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70275484335580
68
+ version_requirements: *70165371259200
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: guard
71
- requirement: &70275484335060 !ruby/object:Gem::Requirement
71
+ requirement: &70165371258360 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70275484335060
79
+ version_requirements: *70165371258360
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: guard-rspec
82
- requirement: &70275484334340 !ruby/object:Gem::Requirement
82
+ requirement: &70165371257800 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70275484334340
90
+ version_requirements: *70165371257800
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rake
93
- requirement: &70275484349900 !ruby/object:Gem::Requirement
93
+ requirement: &70165371257320 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70275484349900
101
+ version_requirements: *70165371257320
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: rdoc
104
- requirement: &70275484349140 !ruby/object:Gem::Requirement
104
+ requirement: &70165371256800 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70275484349140
112
+ version_requirements: *70165371256800
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rspec
115
- requirement: &70275484348380 !ruby/object:Gem::Requirement
115
+ requirement: &70165371256240 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70275484348380
123
+ version_requirements: *70165371256240
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: tzinfo
126
- requirement: &70275484347640 !ruby/object:Gem::Requirement
126
+ requirement: &70165371255740 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *70275484347640
134
+ version_requirements: *70165371255740
135
135
  description: This gem provides exception reporting with Errplane for Rails 3.x applications.
136
136
  email:
137
137
  - todd@errplane.com
@@ -159,6 +159,7 @@ files:
159
159
  - lib/errplane/capistrano.rb
160
160
  - lib/errplane/configuration.rb
161
161
  - lib/errplane/errplane_chef_handler.rb
162
+ - lib/errplane/instrumentation.rb
162
163
  - lib/errplane/logger.rb
163
164
  - lib/errplane/rack.rb
164
165
  - lib/errplane/rails.rb