bugsnag-maglev- 2.8.12

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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +52 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +15 -0
  6. data/CHANGELOG.md +425 -0
  7. data/CONTRIBUTING.md +43 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +804 -0
  11. data/Rakefile +29 -0
  12. data/VERSION +1 -0
  13. data/bugsnag.gemspec +32 -0
  14. data/lib/bugsnag.rb +129 -0
  15. data/lib/bugsnag/capistrano.rb +7 -0
  16. data/lib/bugsnag/capistrano2.rb +32 -0
  17. data/lib/bugsnag/configuration.rb +129 -0
  18. data/lib/bugsnag/delay/resque.rb +21 -0
  19. data/lib/bugsnag/delayed_job.rb +57 -0
  20. data/lib/bugsnag/delivery.rb +18 -0
  21. data/lib/bugsnag/delivery/synchronous.rb +51 -0
  22. data/lib/bugsnag/delivery/thread_queue.rb +53 -0
  23. data/lib/bugsnag/deploy.rb +35 -0
  24. data/lib/bugsnag/helpers.rb +127 -0
  25. data/lib/bugsnag/mailman.rb +28 -0
  26. data/lib/bugsnag/meta_data.rb +7 -0
  27. data/lib/bugsnag/middleware/callbacks.rb +19 -0
  28. data/lib/bugsnag/middleware/mailman.rb +13 -0
  29. data/lib/bugsnag/middleware/rack_request.rb +72 -0
  30. data/lib/bugsnag/middleware/rails2_request.rb +52 -0
  31. data/lib/bugsnag/middleware/rails3_request.rb +42 -0
  32. data/lib/bugsnag/middleware/rake.rb +23 -0
  33. data/lib/bugsnag/middleware/sidekiq.rb +13 -0
  34. data/lib/bugsnag/middleware/warden_user.rb +39 -0
  35. data/lib/bugsnag/middleware_stack.rb +98 -0
  36. data/lib/bugsnag/notification.rb +452 -0
  37. data/lib/bugsnag/rack.rb +53 -0
  38. data/lib/bugsnag/rails.rb +66 -0
  39. data/lib/bugsnag/rails/action_controller_rescue.rb +62 -0
  40. data/lib/bugsnag/rails/active_record_rescue.rb +20 -0
  41. data/lib/bugsnag/rails/controller_methods.rb +44 -0
  42. data/lib/bugsnag/railtie.rb +78 -0
  43. data/lib/bugsnag/rake.rb +25 -0
  44. data/lib/bugsnag/resque.rb +40 -0
  45. data/lib/bugsnag/sidekiq.rb +38 -0
  46. data/lib/bugsnag/tasks.rb +3 -0
  47. data/lib/bugsnag/tasks/bugsnag.cap +48 -0
  48. data/lib/bugsnag/tasks/bugsnag.rake +89 -0
  49. data/lib/bugsnag/version.rb +3 -0
  50. data/lib/generators/bugsnag/bugsnag_generator.rb +24 -0
  51. data/rails/init.rb +3 -0
  52. data/spec/code_spec.rb +86 -0
  53. data/spec/fixtures/crashes/end_of_file.rb +9 -0
  54. data/spec/fixtures/crashes/short_file.rb +1 -0
  55. data/spec/fixtures/crashes/start_of_file.rb +9 -0
  56. data/spec/fixtures/middleware/internal_info_setter.rb +11 -0
  57. data/spec/fixtures/middleware/public_info_setter.rb +11 -0
  58. data/spec/fixtures/tasks/Rakefile +15 -0
  59. data/spec/helper_spec.rb +144 -0
  60. data/spec/integration_spec.rb +110 -0
  61. data/spec/middleware_spec.rb +181 -0
  62. data/spec/notification_spec.rb +822 -0
  63. data/spec/rack_spec.rb +56 -0
  64. data/spec/spec_helper.rb +53 -0
  65. metadata +198 -0
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'bundler/gem_tasks'
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts "Run `bundle install` to install missing gems"
11
+ exit e.status_code
12
+ end
13
+
14
+ require 'rdoc/task'
15
+ RDoc::Task.new do |rdoc|
16
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
17
+
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = "bugsnag #{version}"
20
+ rdoc.rdoc_files.include('README*')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ # RSpec tasks
25
+ require 'rspec/core'
26
+ require "rspec/core/rake_task"
27
+ RSpec::Core::RakeTask.new(:spec)
28
+
29
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.8.12
@@ -0,0 +1,32 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "bugsnag-maglev-"
3
+ s.version = File.read("VERSION").strip
4
+
5
+ s.authors = ["James Smith"]
6
+ s.email = "james@bugsnag.com"
7
+
8
+ s.description = "Ruby notifier for bugsnag.com"
9
+ s.summary = "Ruby notifier for bugsnag.com"
10
+ s.homepage = "http://github.com/bugsnag/bugsnag-ruby"
11
+ s.licenses = ["MIT"]
12
+
13
+ s.files = `git ls-files`.split("\n").reject {|file| file.start_with? "example/"}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE.txt",
16
+ "README.md"
17
+ ]
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency 'json', '~> 1.7', '>= 1.7.5'
21
+
22
+ if RUBY_VERSION < "1.9"
23
+ s.add_development_dependency "rake", "~> 10.1.1"
24
+ else
25
+ s.add_development_dependency 'rake'
26
+ end
27
+
28
+ s.add_development_dependency 'rspec'
29
+ s.add_development_dependency 'rdoc'
30
+ s.add_development_dependency 'pry'
31
+ s.add_development_dependency 'webmock'
32
+ end
@@ -0,0 +1,129 @@
1
+ require "rubygems"
2
+ require "thread"
3
+
4
+ require "bugsnag/version"
5
+ require "bugsnag/configuration"
6
+ require "bugsnag/meta_data"
7
+ require "bugsnag/notification"
8
+ require "bugsnag/helpers"
9
+ require "bugsnag/deploy"
10
+
11
+ require "bugsnag/delivery"
12
+ require "bugsnag/delivery/synchronous"
13
+ require "bugsnag/delivery/thread_queue"
14
+
15
+ require "bugsnag/rack"
16
+ require "bugsnag/railtie" if defined?(Rails::Railtie)
17
+
18
+ require "bugsnag/middleware/rack_request"
19
+ require "bugsnag/middleware/warden_user"
20
+ require "bugsnag/middleware/callbacks"
21
+ require "bugsnag/middleware/rails3_request"
22
+ require "bugsnag/middleware/sidekiq"
23
+ require "bugsnag/middleware/mailman"
24
+ require "bugsnag/middleware/rake"
25
+ require "bugsnag/middleware/callbacks"
26
+
27
+ module Bugsnag
28
+ LOG_PREFIX = "** [Bugsnag] "
29
+ LOCK = Mutex.new
30
+
31
+ class << self
32
+ # Configure the Bugsnag notifier application-wide settings.
33
+ def configure(config_hash=nil)
34
+ if config_hash
35
+ config_hash.each do |k,v|
36
+ configuration.send("#{k}=", v) rescue nil if configuration.respond_to?("#{k}=")
37
+ end
38
+ end
39
+
40
+ yield(configuration) if block_given?
41
+
42
+ # Use resque for asynchronous notification if required
43
+ require "bugsnag/delay/resque" if configuration.delay_with_resque && defined?(Resque)
44
+
45
+ # Log that we are ready to rock
46
+ if configuration.api_key && !@logged_ready
47
+ log "Bugsnag exception handler #{VERSION} ready, api_key=#{configuration.api_key}"
48
+ @logged_ready = true
49
+ end
50
+ end
51
+
52
+ # Explicitly notify of an exception
53
+ def notify(exception, overrides=nil, request_data=nil)
54
+ notification = Notification.new(exception, configuration, overrides, request_data)
55
+ notification.deliver
56
+ notification
57
+ end
58
+
59
+ # Notify of an exception unless it should be ignored
60
+ def notify_or_ignore(exception, overrides=nil, request_data=nil)
61
+ notification = Notification.new(exception, configuration, overrides, request_data)
62
+
63
+ unless notification.ignore?
64
+ notification.deliver
65
+ notification
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ # Auto notify of an exception, called from rails and rack exception
72
+ # rescuers, unless auto notification is disabled, or we should ignore this
73
+ # error class
74
+ def auto_notify(exception, overrides=nil, request_data=nil)
75
+ overrides ||= {}
76
+ overrides.merge!({:severity => "error"})
77
+ notify_or_ignore(exception, overrides, request_data) if configuration.auto_notify
78
+ end
79
+
80
+ # Log wrapper
81
+ def log(message)
82
+ configuration.logger.info("#{LOG_PREFIX}#{message}")
83
+ end
84
+
85
+ # Warning logger
86
+ def warn(message)
87
+ configuration.logger.warn("#{LOG_PREFIX}#{message}")
88
+ end
89
+
90
+ # Debug logger
91
+ def debug(message)
92
+ configuration.logger.info("#{LOG_PREFIX}#{message}") if configuration.debug
93
+ end
94
+
95
+ # Configuration getters
96
+ def configuration
97
+ @configuration || LOCK.synchronize { @configuration ||= Bugsnag::Configuration.new }
98
+ end
99
+
100
+ # Set "per-request" data, temporal data for use in bugsnag middleware
101
+ def set_request_data(key, value)
102
+ Bugsnag.configuration.set_request_data(key, value)
103
+ end
104
+
105
+ # Clear all "per-request" data, temporal data for use in bugsnag middleware
106
+ # This method should be called after each distinct request or session ends
107
+ # Eg. After completing a page request in a web app
108
+ def clear_request_data
109
+ Bugsnag.configuration.clear_request_data
110
+ end
111
+
112
+ # Allow access to "before notify" callbacks
113
+ def before_notify_callbacks
114
+ Bugsnag.configuration.request_data[:before_callbacks] ||= []
115
+ end
116
+
117
+ # Allow access to "after notify" callbacks
118
+ def after_notify_callbacks
119
+ Bugsnag.configuration.request_data[:after_callbacks] ||= []
120
+ end
121
+ end
122
+ end
123
+
124
+ [:resque, :sidekiq, :mailman, :delayed_job].each do |integration|
125
+ begin
126
+ require "bugsnag/#{integration}"
127
+ rescue LoadError
128
+ end
129
+ end
@@ -0,0 +1,7 @@
1
+ require "bugsnag/deploy"
2
+
3
+ if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
4
+ load File.expand_path('../tasks/bugsnag.cap', __FILE__)
5
+ else
6
+ require_relative 'capistrano2'
7
+ end
@@ -0,0 +1,32 @@
1
+ module Bugsnag
2
+ module Capistrano
3
+ def self.load_into(configuration)
4
+ configuration.load do
5
+ after "deploy", "bugsnag:deploy"
6
+ after "deploy:migrations", "bugsnag:deploy"
7
+
8
+ namespace :bugsnag do
9
+ desc "Notify Bugsnag that new production code has been deployed"
10
+ task :deploy, :except => { :no_release => true }, :on_error => :continue do
11
+ begin
12
+ Bugsnag::Deploy.notify({
13
+ :api_key => fetch(:bugsnag_api_key, ENV["BUGSNAG_API_KEY"]),
14
+ :release_stage => fetch(:rails_env, ENV["BUGSNAG_RELEASE_STAGE"] || "production"),
15
+ :revision => fetch(:current_revision, ENV["BUGSNAG_REVISION"]),
16
+ :repository => fetch(:repository, ENV["BUGSNAG_REPOSITORY"]),
17
+ :branch => fetch(:branch, ENV["BUGSNAG_BRANCH"],
18
+ :app_version => fetch(:app_version, ENV["BUGSNAG_APP_VERSION"]))
19
+ })
20
+ rescue
21
+ logger.important("Bugnsag deploy notification failed, #{$!.inspect}")
22
+ end
23
+
24
+ logger.info "Bugsnag deploy notification complete."
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ Bugsnag::Capistrano.load_into(Capistrano::Configuration.instance) if Capistrano::Configuration.instance
@@ -0,0 +1,129 @@
1
+ require "set"
2
+ require "socket"
3
+ require "logger"
4
+ require "bugsnag/middleware_stack"
5
+
6
+ module Bugsnag
7
+ class Configuration
8
+ attr_accessor :api_key
9
+ attr_accessor :release_stage
10
+ attr_accessor :notify_release_stages
11
+ attr_accessor :auto_notify
12
+ attr_accessor :use_ssl
13
+ attr_accessor :ca_file
14
+ attr_accessor :send_environment
15
+ attr_accessor :send_code
16
+ attr_accessor :project_root
17
+ attr_accessor :app_version
18
+ attr_accessor :app_type
19
+ attr_accessor :params_filters
20
+ attr_accessor :ignore_user_agents
21
+ attr_accessor :endpoint
22
+ attr_accessor :logger
23
+ attr_accessor :middleware
24
+ attr_accessor :internal_middleware
25
+ attr_accessor :delay_with_resque
26
+ attr_accessor :debug
27
+ attr_accessor :proxy_host
28
+ attr_accessor :proxy_port
29
+ attr_accessor :proxy_user
30
+ attr_accessor :proxy_password
31
+ attr_accessor :timeout
32
+ attr_accessor :hostname
33
+ attr_accessor :delivery_method
34
+ attr_writer :ignore_classes
35
+
36
+ THREAD_LOCAL_NAME = "bugsnag_req_data"
37
+
38
+ DEFAULT_ENDPOINT = "notify.bugsnag.com"
39
+
40
+ DEFAULT_PARAMS_FILTERS = [
41
+ /authorization/i,
42
+ /cookie/i,
43
+ /password/i,
44
+ /secret/i,
45
+ "rack.request.form_vars"
46
+ ].freeze
47
+
48
+ DEFAULT_IGNORE_CLASSES = [
49
+ "AbstractController::ActionNotFound",
50
+ "ActionController::InvalidAuthenticityToken",
51
+ "ActionController::ParameterMissing",
52
+ "ActionController::RoutingError",
53
+ "ActionController::UnknownAction",
54
+ "ActionController::UnknownFormat",
55
+ "ActionController::UnknownHttpMethod",
56
+ "ActiveRecord::RecordNotFound",
57
+ "CGI::Session::CookieStore::TamperedWithCookie",
58
+ "Mongoid::Errors::DocumentNotFound",
59
+ "SignalException",
60
+ "SystemExit",
61
+ ].freeze
62
+
63
+ DEFAULT_IGNORE_USER_AGENTS = [].freeze
64
+
65
+ DEFAULT_DELIVERY_METHOD = :thread_queue
66
+
67
+ def initialize
68
+ @mutex = Mutex.new
69
+
70
+ # Set up the defaults
71
+ self.auto_notify = true
72
+ self.use_ssl = true
73
+ self.send_environment = false
74
+ self.send_code = true
75
+ self.params_filters = Set.new(DEFAULT_PARAMS_FILTERS)
76
+ self.ignore_classes = Set.new(DEFAULT_IGNORE_CLASSES)
77
+ self.ignore_user_agents = Set.new(DEFAULT_IGNORE_USER_AGENTS)
78
+ self.endpoint = DEFAULT_ENDPOINT
79
+ self.hostname = default_hostname
80
+ self.delivery_method = DEFAULT_DELIVERY_METHOD
81
+ self.timeout = 15
82
+
83
+ # Read the API key from the environment
84
+ self.api_key = ENV["BUGSNAG_API_KEY"]
85
+
86
+ # Set up logging
87
+ self.logger = Logger.new(STDOUT)
88
+ self.logger.level = Logger::WARN
89
+
90
+ # Configure the bugsnag middleware stack
91
+ self.internal_middleware = Bugsnag::MiddlewareStack.new
92
+
93
+ self.middleware = Bugsnag::MiddlewareStack.new
94
+ self.middleware.use Bugsnag::Middleware::Callbacks
95
+ end
96
+
97
+ # Accept both String and Class instances as an ignored class
98
+ def ignore_classes
99
+ @mutex.synchronize { @ignore_classes.map! { |klass| klass.is_a?(Class) ? klass.name : klass } }
100
+ end
101
+
102
+ def should_notify?
103
+ @release_stage.nil? || @notify_release_stages.nil? || @notify_release_stages.include?(@release_stage)
104
+ end
105
+
106
+ def request_data
107
+ Thread.current[THREAD_LOCAL_NAME] ||= {}
108
+ end
109
+
110
+ def set_request_data(key, value)
111
+ self.request_data[key] = value
112
+ end
113
+
114
+ def unset_request_data(key, value)
115
+ self.request_data.delete(key)
116
+ end
117
+
118
+ def clear_request_data
119
+ Thread.current[THREAD_LOCAL_NAME] = nil
120
+ end
121
+
122
+ private
123
+
124
+ def default_hostname
125
+ # Don't send the hostname on Heroku
126
+ Socket.gethostname unless ENV["DYNO"]
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,21 @@
1
+ module Bugsnag
2
+ module Delay
3
+ class Resque
4
+ @queue = "bugsnag"
5
+ def self.perform(*args)
6
+ Bugsnag::Notification.deliver_exception_payload_without_resque(*args)
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ Bugsnag::Notification.class_eval do
13
+ class << self
14
+ def deliver_exception_payload_with_resque(*args)
15
+ Resque.enqueue(Bugsnag::Delay::Resque, *args)
16
+ end
17
+
18
+ alias_method :deliver_exception_payload_without_resque, :deliver_exception_payload
19
+ alias_method :deliver_exception_payload, :deliver_exception_payload_with_resque
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ require 'delayed_job'
2
+
3
+ # See Issue #99
4
+ unless defined?(Delayed::Plugin)
5
+ raise LoadError, "bugsnag requires delayed_job > 3.x"
6
+ end
7
+
8
+ unless defined? Delayed::Plugins::Bugsnag
9
+ module Delayed
10
+ module Plugins
11
+
12
+
13
+ class Bugsnag < Plugin
14
+ module Notify
15
+ def error(job, error)
16
+ overrides = {
17
+ :job => {
18
+ :class => job.class.name,
19
+ :id => job.id,
20
+ }
21
+ }
22
+ if payload = job.payload_object
23
+ p = {
24
+ :class => payload.class.name,
25
+ }
26
+ p[:id] = payload.id if payload.respond_to?(:id)
27
+ p[:display_name] = payload.display_name if payload.respond_to?(:display_name)
28
+ p[:method_name] = payload.method_name if payload.respond_to?(:method_name)
29
+ p[:args] = payload.args if payload.respond_to?(:args)
30
+ if payload.is_a?(::Delayed::PerformableMethod) && (object = payload.object)
31
+ p[:object] = {
32
+ :class => object.class.name,
33
+ }
34
+ p[:object][:id] = object.id if object.respond_to?(:id)
35
+ end
36
+ overrides[:job][:payload] = p
37
+ end
38
+
39
+ ::Bugsnag.auto_notify(error, overrides)
40
+
41
+ super if defined?(super)
42
+ end
43
+ end
44
+
45
+ callbacks do |lifecycle|
46
+ lifecycle.before(:invoke_job) do |job|
47
+ payload = job.payload_object
48
+ payload = payload.object if payload.is_a? Delayed::PerformableMethod
49
+ payload.extend Notify
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ Delayed::Worker.plugins << Delayed::Plugins::Bugsnag
57
+ end