bugsnag-maglev- 2.8.12

Sign up to get free protection for your applications and to get access to all the features.
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