airbrakeV4rails5 4.3.8
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 +7 -0
- data/CHANGELOG +1716 -0
- data/Gemfile +3 -0
- data/Guardfile +6 -0
- data/INSTALL +20 -0
- data/LICENSE +61 -0
- data/README.md +148 -0
- data/README_FOR_HEROKU_ADDON.md +102 -0
- data/Rakefile +179 -0
- data/TESTED_AGAINST +7 -0
- data/airbrake.gemspec +41 -0
- data/bin/airbrake +12 -0
- data/features/metal.feature +34 -0
- data/features/rack.feature +60 -0
- data/features/rails.feature +324 -0
- data/features/rake.feature +33 -0
- data/features/sinatra.feature +126 -0
- data/features/step_definitions/file_steps.rb +14 -0
- data/features/step_definitions/rack_steps.rb +27 -0
- data/features/step_definitions/rails_application_steps.rb +267 -0
- data/features/step_definitions/rake_steps.rb +22 -0
- data/features/support/airbrake_shim.rb.template +11 -0
- data/features/support/aruba.rb +5 -0
- data/features/support/env.rb +39 -0
- data/features/support/matchers.rb +35 -0
- data/features/support/rails.rb +156 -0
- data/features/support/rake/Rakefile +77 -0
- data/features/user_informer.feature +57 -0
- data/generators/airbrake/airbrake_generator.rb +94 -0
- data/generators/airbrake/lib/insert_commands.rb +34 -0
- data/generators/airbrake/lib/rake_commands.rb +24 -0
- data/generators/airbrake/templates/airbrake_tasks.rake +25 -0
- data/generators/airbrake/templates/capistrano_hook.rb +6 -0
- data/generators/airbrake/templates/initializer.rb +4 -0
- data/install.rb +1 -0
- data/lib/airbrake.rb +191 -0
- data/lib/airbrake/backtrace.rb +103 -0
- data/lib/airbrake/capistrano.rb +103 -0
- data/lib/airbrake/capistrano3.rb +3 -0
- data/lib/airbrake/cli/client.rb +76 -0
- data/lib/airbrake/cli/options.rb +45 -0
- data/lib/airbrake/cli/printer.rb +33 -0
- data/lib/airbrake/cli/project.rb +17 -0
- data/lib/airbrake/cli/project_factory.rb +33 -0
- data/lib/airbrake/cli/runner.rb +49 -0
- data/lib/airbrake/cli/validator.rb +8 -0
- data/lib/airbrake/configuration.rb +366 -0
- data/lib/airbrake/jobs/send_job.rb +7 -0
- data/lib/airbrake/notice.rb +411 -0
- data/lib/airbrake/rack.rb +64 -0
- data/lib/airbrake/rails.rb +45 -0
- data/lib/airbrake/rails/action_controller_catcher.rb +32 -0
- data/lib/airbrake/rails/controller_methods.rb +146 -0
- data/lib/airbrake/rails/error_lookup.rb +35 -0
- data/lib/airbrake/rails/middleware.rb +63 -0
- data/lib/airbrake/rails3_tasks.rb +126 -0
- data/lib/airbrake/railtie.rb +44 -0
- data/lib/airbrake/rake_handler.rb +75 -0
- data/lib/airbrake/response.rb +29 -0
- data/lib/airbrake/sender.rb +213 -0
- data/lib/airbrake/shared_tasks.rb +59 -0
- data/lib/airbrake/sidekiq.rb +8 -0
- data/lib/airbrake/sinatra.rb +40 -0
- data/lib/airbrake/tasks.rb +81 -0
- data/lib/airbrake/tasks/airbrake.cap +28 -0
- data/lib/airbrake/user_informer.rb +36 -0
- data/lib/airbrake/utils/params_cleaner.rb +141 -0
- data/lib/airbrake/utils/rack_filters.rb +45 -0
- data/lib/airbrake/version.rb +3 -0
- data/lib/airbrake_tasks.rb +62 -0
- data/lib/rails/generators/airbrake/airbrake_generator.rb +155 -0
- data/lib/templates/rescue.erb +91 -0
- data/rails/init.rb +1 -0
- data/resources/README.md +34 -0
- data/resources/airbrake_2_4.xsd +89 -0
- data/resources/airbrake_3_0.json +52 -0
- data/resources/ca-bundle.crt +3376 -0
- data/script/integration_test.rb +35 -0
- data/test/airbrake_tasks_test.rb +161 -0
- data/test/backtrace_test.rb +215 -0
- data/test/capistrano_test.rb +44 -0
- data/test/configuration_test.rb +303 -0
- data/test/controller_methods_test.rb +230 -0
- data/test/helper.rb +233 -0
- data/test/integration.rb +13 -0
- data/test/integration/catcher_test.rb +371 -0
- data/test/logger_test.rb +79 -0
- data/test/notice_test.rb +494 -0
- data/test/notifier_test.rb +288 -0
- data/test/params_cleaner_test.rb +204 -0
- data/test/rack_test.rb +62 -0
- data/test/rails_initializer_test.rb +36 -0
- data/test/recursion_test.rb +10 -0
- data/test/response_test.rb +18 -0
- data/test/sender_test.rb +335 -0
- data/test/support/response_shim.xml +4 -0
- data/test/user_informer_test.rb +29 -0
- metadata +469 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path( "../runner", __FILE__)
|
2
|
+
|
3
|
+
module Client
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def options
|
7
|
+
Runner.options
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch_projects
|
11
|
+
uri = URI.parse "http://#{options.account}.airbrake.io"\
|
12
|
+
"/data_api/v1/projects.xml?auth_token=#{options.auth_token}"
|
13
|
+
http = Net::HTTP.new(uri.host,uri.port)
|
14
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
15
|
+
response = http.request(request)
|
16
|
+
response.body
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_project
|
20
|
+
uri = URI.parse "http://#{options.account}.airbrake.io"\
|
21
|
+
"/data_api/v1/projects.xml"
|
22
|
+
http = Net::HTTP.new(uri.host,uri.port)
|
23
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
24
|
+
request.set_form_data('project[name]' => options.name,'auth_token' => options.auth_token)
|
25
|
+
response = http.request(request)
|
26
|
+
response.body
|
27
|
+
|
28
|
+
print_project_response(response.body)
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_deploy
|
32
|
+
uri = URI.parse "http://airbrake.io/deploys.txt"
|
33
|
+
http = Net::HTTP.new(uri.host,uri.port)
|
34
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
35
|
+
opts = { 'api_key' => options.api_key }.merge!(deploy_opts)
|
36
|
+
request.set_form_data(opts)
|
37
|
+
response = http.request(request)
|
38
|
+
puts response.message if response.respond_to?(:message)
|
39
|
+
end
|
40
|
+
|
41
|
+
def deploy_opts
|
42
|
+
opts = {}
|
43
|
+
['rails_env', 'scm_revision', 'scm_repository', 'local_username'].each do |attr|
|
44
|
+
opts.merge!("deploy[#{attr}]" => options.send(attr))
|
45
|
+
end
|
46
|
+
opts
|
47
|
+
end
|
48
|
+
|
49
|
+
def print_projects
|
50
|
+
factory = ProjectFactory.new
|
51
|
+
projects = fetch_projects
|
52
|
+
factory.create_projects_from_xml(projects)
|
53
|
+
abort "No projects were fetched. Did you provide the correct auth token?" if projects.match(/error/m)
|
54
|
+
puts "\nProjects\n" + "".rjust(63,"#")
|
55
|
+
factory.projects.each do |project|
|
56
|
+
puts project
|
57
|
+
end
|
58
|
+
puts
|
59
|
+
end
|
60
|
+
|
61
|
+
def print_project_response(response)
|
62
|
+
case response
|
63
|
+
when /errors/
|
64
|
+
puts "Error creating project: #{response.gsub("\n","").scan(/.*<error[^>]*>(.*?)<\/error>.*/).last.first.gsub(/\s{1,}/," ")}"
|
65
|
+
when /project/
|
66
|
+
project = Project.new(:id => response[/<id[^>]*>(.*?)<\/id>/,1],
|
67
|
+
:name => response[/<name[^>]*>(.*?)<\/name>/,1],
|
68
|
+
:api_key => response[/<api-key[^>]*>(.*?)<\/api-key>/,1])
|
69
|
+
puts "\nProject details\n" + "".rjust(63,"#")
|
70
|
+
puts project
|
71
|
+
else
|
72
|
+
puts "Unexpected error. Please try again!\n"
|
73
|
+
puts response
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Options
|
2
|
+
|
3
|
+
ATTRIBUTES = [:error, :message, :api_key, :host, :port, :auth_token, :name,
|
4
|
+
:account, :rails_env, :scm_revision, :scm_repository, :local_username]
|
5
|
+
|
6
|
+
ATTRIBUTES.each do |attribute|
|
7
|
+
attr_reader attribute
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# You should not write to this from outside
|
13
|
+
ATTRIBUTES.each do |attribute|
|
14
|
+
attr_writer attribute
|
15
|
+
end
|
16
|
+
|
17
|
+
public
|
18
|
+
|
19
|
+
# Parses all the options passed and stores them in attributes
|
20
|
+
def initialize(array = [])
|
21
|
+
opts = Hash[*array]
|
22
|
+
self.error = opts.delete("-e") || opts.delete("--error") { RuntimeError }
|
23
|
+
self.message = opts.delete("-m") || opts.delete("--message") { "I've made a huge mistake" }
|
24
|
+
self.api_key = opts.delete("-k") || opts.delete("--api-key") || config_from_file.api_key || ENV["AIRBRAKE_API_KEY"]
|
25
|
+
self.host = opts.delete("-h") || opts.delete("--host") || config_from_file.host
|
26
|
+
self.port = opts.delete("-p") || opts.delete("--port") || config_from_file.port
|
27
|
+
self.auth_token = opts.delete("-t") || opts.delete("--auth-token") || ENV["AIRBRAKE_AUTH_TOKEN"]
|
28
|
+
self.name = opts.delete("-n") || opts.delete("--name")
|
29
|
+
self.account = opts.delete("-a") || opts.delete("--account") || ENV["AIRBRAKE_ACCOUNT"]
|
30
|
+
self.rails_env = opts.delete("-E") || opts.delete("--rails-env") || ENV["RAILS_ENV"] || "production"
|
31
|
+
self.scm_revision = opts.delete("-r") || opts.delete("--scm-revision") || ENV["REVISION"]
|
32
|
+
self.scm_repository = opts.delete("-R") || opts.delete("--scm-repository") || ENV["REPO"]
|
33
|
+
self.local_username = opts.delete("-u") || opts.delete("--local-username") || ENV["USER"]
|
34
|
+
opts
|
35
|
+
end
|
36
|
+
|
37
|
+
# Fallback to read from the initializer
|
38
|
+
def config_from_file
|
39
|
+
begin
|
40
|
+
load "config/initializers/airbrake.rb"
|
41
|
+
rescue LoadError
|
42
|
+
end
|
43
|
+
Airbrake.configuration
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Printer
|
2
|
+
def self.print(collection)
|
3
|
+
collection.each do |element|
|
4
|
+
puts element
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.print_usage
|
9
|
+
puts <<-USAGE
|
10
|
+
Usage: airbrake [COMMAND] [OPTION]...
|
11
|
+
Commands:
|
12
|
+
raise # Raise an exception specified by ERROR and MESSAGE.
|
13
|
+
list # List all the projects for given AUTH_TOKEN and ACCOUNT.
|
14
|
+
create # Create a project with the given NAME.
|
15
|
+
deploy # Send a new deployment notification to a project that matches the API_KEY.
|
16
|
+
|
17
|
+
Options:
|
18
|
+
-e, [--error=ERROR] # Error class to raise. Default: RuntimeError
|
19
|
+
-m, [--message=MESSAGE] # Error message. Default: "I've made a huge mistake"
|
20
|
+
-k, [--api-key=API_KEY] # Api key of your Airbrake application
|
21
|
+
-h, [--host=HOST] # URL of the Airbrake API server. Default: api.airbrake.io
|
22
|
+
-p, [--port=PORT] # Port of the Airbrake API server. Default: 80
|
23
|
+
-t, [--auth-token=AUTH_TOKEN] # The auth token used for API requests
|
24
|
+
-a, [--account=ACCOUNT] # The account used for API requests
|
25
|
+
-n, [--name=NAME] # The name of the project you're trying to create
|
26
|
+
-E, [--rails-env=NAME] # The name of the environment you're deploying to. Default: production
|
27
|
+
-r, [--scm-revision=REVISION] # SCM revision for deployment info
|
28
|
+
-R, [--scm-repository=REPO] # SCM repository for deployment info
|
29
|
+
-u, [--local-username=USER] # The name of the user who is deploying
|
30
|
+
-h, [--help] # Show this usage
|
31
|
+
USAGE
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Project
|
2
|
+
attr_writer :name, :id, :api_key
|
3
|
+
|
4
|
+
def initialize(attributes = {})
|
5
|
+
attributes.keys.each do |key|
|
6
|
+
instance_variable_set("@#{key}",attributes[key])
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{@name}".rjust(20) + "(#{@id}):".rjust(10) + " #{@api_key}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
@name && @id && @api_key
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path( "../project", __FILE__)
|
2
|
+
# Responsible for creating projects when needed.
|
3
|
+
# Creates them from XML received.
|
4
|
+
class ProjectFactory
|
5
|
+
attr_reader :project, :projects
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@project = Project.new
|
9
|
+
@projects = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_projects_from_xml(xml)
|
13
|
+
xml.split("\n").each do |line|
|
14
|
+
/<name[^>]*>(.*)<\/name>/ =~ line
|
15
|
+
name = $1
|
16
|
+
project.name = name.capitalize if name
|
17
|
+
/<id[^>]*>(.*)<\/id>/ =~ line
|
18
|
+
id = $1
|
19
|
+
project.id = id if id
|
20
|
+
/<api-key[^>]*>(.*)<\/api-key>/ =~ line
|
21
|
+
api_key = $1
|
22
|
+
project.api_key = api_key if api_key
|
23
|
+
check_project
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_project
|
28
|
+
if @project.valid?
|
29
|
+
projects << @project
|
30
|
+
@project = Project.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path( "../project_factory", __FILE__)
|
2
|
+
require File.expand_path( "../options", __FILE__)
|
3
|
+
require File.expand_path( "../validator", __FILE__)
|
4
|
+
require File.expand_path( "../printer", __FILE__)
|
5
|
+
require File.expand_path( "../client", __FILE__)
|
6
|
+
|
7
|
+
module Runner
|
8
|
+
extend Validator
|
9
|
+
|
10
|
+
extend self
|
11
|
+
|
12
|
+
attr_accessor :options
|
13
|
+
|
14
|
+
def run!(command, cli_options = {})
|
15
|
+
|
16
|
+
self.options = Options.new(cli_options)
|
17
|
+
|
18
|
+
case command
|
19
|
+
when 'raise'
|
20
|
+
validates :api_key
|
21
|
+
Airbrake.configure do |c|
|
22
|
+
c.api_key = options.api_key
|
23
|
+
c.host = options.host if options.host
|
24
|
+
c.port = options.port if options.port
|
25
|
+
c.secure = options.port.to_i == 443
|
26
|
+
end
|
27
|
+
exception_id = Airbrake.notify(:error_class => options.error,
|
28
|
+
:error_message => "#{options.error}: #{options.message}",
|
29
|
+
:cgi_data => ENV)
|
30
|
+
abort "Error sending exception to Airbrake server. Try again later." unless exception_id
|
31
|
+
puts "Exception sent successfully: http://airbrake.io/locate/#{exception_id}"
|
32
|
+
|
33
|
+
when "list"
|
34
|
+
validates :auth_token, :account
|
35
|
+
Client.print_projects
|
36
|
+
|
37
|
+
when "create"
|
38
|
+
validates :auth_token, :account
|
39
|
+
Client.create_project
|
40
|
+
|
41
|
+
when "deploy"
|
42
|
+
validates :api_key
|
43
|
+
Client.create_deploy
|
44
|
+
|
45
|
+
else
|
46
|
+
Printer.print_usage
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,366 @@
|
|
1
|
+
module Airbrake
|
2
|
+
# Used to set up and modify settings for the notifier.
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
OPTIONS = [:api_key, :backtrace_filters, :development_environments,
|
6
|
+
:development_lookup, :environment_name, :host,
|
7
|
+
:http_open_timeout, :http_read_timeout, :ignore, :ignore_by_filters,
|
8
|
+
:ignore_user_agent, :notifier_name, :notifier_url, :notifier_version,
|
9
|
+
:params_filters, :params_whitelist_filters, :project_root, :port, :protocol, :proxy_host,
|
10
|
+
:proxy_pass, :proxy_port, :proxy_user, :secure, :use_system_ssl_cert_chain,
|
11
|
+
:framework, :user_information, :rescue_rake_exceptions, :rake_environment_filters,
|
12
|
+
:test_mode].freeze
|
13
|
+
|
14
|
+
# The API key for your project, found on the project edit form.
|
15
|
+
attr_accessor :api_key
|
16
|
+
|
17
|
+
# The host to connect to (defaults to airbrake.io).
|
18
|
+
attr_accessor :host
|
19
|
+
|
20
|
+
# The port on which your Airbrake server runs (defaults to 443 for secure
|
21
|
+
# connections, 80 for insecure connections).
|
22
|
+
attr_writer :port
|
23
|
+
|
24
|
+
# +true+ for https connections, +false+ for http connections.
|
25
|
+
attr_accessor :secure
|
26
|
+
|
27
|
+
# +true+ to use whatever CAs OpenSSL has installed on your system. +false+ to use the ca-bundle.crt file included in Airbrake itself (reccomended and default)
|
28
|
+
attr_accessor :use_system_ssl_cert_chain
|
29
|
+
|
30
|
+
# The HTTP open timeout in seconds (defaults to 2).
|
31
|
+
attr_accessor :http_open_timeout
|
32
|
+
|
33
|
+
# The HTTP read timeout in seconds (defaults to 5).
|
34
|
+
attr_accessor :http_read_timeout
|
35
|
+
|
36
|
+
# The hostname of your proxy server (if using a proxy)
|
37
|
+
attr_accessor :proxy_host
|
38
|
+
|
39
|
+
# The port of your proxy server (if using a proxy)
|
40
|
+
attr_accessor :proxy_port
|
41
|
+
|
42
|
+
# The username to use when logging into your proxy server (if using a proxy)
|
43
|
+
attr_accessor :proxy_user
|
44
|
+
|
45
|
+
# The password to use when logging into your proxy server (if using a proxy)
|
46
|
+
attr_accessor :proxy_pass
|
47
|
+
|
48
|
+
# A list of parameters that should be filtered out of what is sent to Airbrake.
|
49
|
+
# By default, all "password" attributes will have their contents replaced.
|
50
|
+
attr_accessor :params_filters
|
51
|
+
|
52
|
+
# A list of whitelisted parameters that will be sent to Airbrake.
|
53
|
+
# All other parameters will be filtered and their content replaced.
|
54
|
+
# By default this list is empty (all parameters are whitelisted).
|
55
|
+
attr_accessor :params_whitelist_filters
|
56
|
+
|
57
|
+
# A list of filters for cleaning and pruning the backtrace. See #filter_backtrace.
|
58
|
+
attr_reader :backtrace_filters
|
59
|
+
|
60
|
+
# A list of filters for ignoring exceptions. See #ignore_by_filter.
|
61
|
+
attr_reader :ignore_by_filters
|
62
|
+
|
63
|
+
# A list of environment keys that will be ignored from what is sent to Airbrake server
|
64
|
+
# Empty by default and used only in rake handler
|
65
|
+
attr_reader :rake_environment_filters
|
66
|
+
|
67
|
+
# A list of exception classes to ignore during server requests. The array can be appended to.
|
68
|
+
attr_reader :ignore
|
69
|
+
|
70
|
+
# A list of exception classes to ignore during Rake tasks. The array can be appended to.
|
71
|
+
attr_reader :ignore_rake
|
72
|
+
|
73
|
+
# A list of user agents that are being ignored. The array can be appended to.
|
74
|
+
attr_reader :ignore_user_agent
|
75
|
+
|
76
|
+
# A list of environments in which notifications should not be sent.
|
77
|
+
attr_accessor :development_environments
|
78
|
+
|
79
|
+
# +true+ if you want to check for production errors matching development errors, +false+ otherwise.
|
80
|
+
attr_accessor :development_lookup
|
81
|
+
|
82
|
+
# The name of the environment the application is running in
|
83
|
+
attr_accessor :environment_name
|
84
|
+
|
85
|
+
# The path to the project in which the error occurred, such as the Rails.root
|
86
|
+
attr_accessor :project_root
|
87
|
+
|
88
|
+
# The name of the notifier library being used to send notifications (such as "Airbrake Notifier")
|
89
|
+
attr_accessor :notifier_name
|
90
|
+
|
91
|
+
# The version of the notifier library being used to send notifications (such as "1.0.2")
|
92
|
+
attr_accessor :notifier_version
|
93
|
+
|
94
|
+
# The url of the notifier library being used to send notifications
|
95
|
+
attr_accessor :notifier_url
|
96
|
+
|
97
|
+
# The logger used by Airbrake
|
98
|
+
attr_accessor :logger
|
99
|
+
|
100
|
+
# The text that the placeholder is replaced with. {{error_id}} is the actual error number.
|
101
|
+
attr_accessor :user_information
|
102
|
+
|
103
|
+
# The framework Airbrake is configured to use
|
104
|
+
attr_accessor :framework
|
105
|
+
|
106
|
+
# Should Airbrake catch exceptions from Rake tasks?
|
107
|
+
# (boolean or nil; set to nil to catch exceptions when rake isn't running from a terminal; default is nil)
|
108
|
+
attr_accessor :rescue_rake_exceptions
|
109
|
+
alias_method :rescue_rake_exceptions?, :rescue_rake_exceptions
|
110
|
+
|
111
|
+
# User attributes that are being captured
|
112
|
+
attr_reader :user_attributes
|
113
|
+
|
114
|
+
# Only used for JSON API
|
115
|
+
attr_reader :project_id
|
116
|
+
|
117
|
+
# Setting this to true will use the CollectingSender instead of
|
118
|
+
# the default one which will cause storing the last notice locally
|
119
|
+
attr_accessor :test_mode
|
120
|
+
alias_method :test_mode?, :test_mode
|
121
|
+
|
122
|
+
DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
|
123
|
+
DEFAULT_PARAMS_WHITELIST_FILTERS = [].freeze
|
124
|
+
|
125
|
+
DEFAULT_USER_ATTRIBUTES = %w(id).freeze
|
126
|
+
|
127
|
+
VALID_USER_ATTRIBUTES = %w(id name username email).freeze
|
128
|
+
|
129
|
+
DEFAULT_BACKTRACE_FILTERS = [
|
130
|
+
lambda { |line|
|
131
|
+
if defined?(Airbrake.configuration.project_root) && Airbrake.configuration.project_root.to_s != ''
|
132
|
+
line.sub(/#{Airbrake.configuration.project_root}/, "[PROJECT_ROOT]")
|
133
|
+
else
|
134
|
+
line
|
135
|
+
end
|
136
|
+
},
|
137
|
+
lambda { |line| line.gsub(/^\.\//, "") },
|
138
|
+
lambda { |line|
|
139
|
+
Gem.path.each{ |path| line.sub!(/#{path}/, "[GEM_ROOT]") unless path.to_s.strip.empty? } if defined?(Gem)
|
140
|
+
line
|
141
|
+
},
|
142
|
+
lambda { |line| line if line !~ %r{lib/airbrake} }
|
143
|
+
].freeze
|
144
|
+
|
145
|
+
IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
|
146
|
+
'ActionController::RoutingError',
|
147
|
+
'ActionController::InvalidAuthenticityToken',
|
148
|
+
'CGI::Session::CookieStore::TamperedWithCookie',
|
149
|
+
'ActionController::UnknownHttpMethod',
|
150
|
+
'ActionController::UnknownAction',
|
151
|
+
'AbstractController::ActionNotFound',
|
152
|
+
'Mongoid::Errors::DocumentNotFound',
|
153
|
+
'ActionController::UnknownFormat']
|
154
|
+
|
155
|
+
alias_method :secure?, :secure
|
156
|
+
alias_method :use_system_ssl_cert_chain?, :use_system_ssl_cert_chain
|
157
|
+
|
158
|
+
def initialize
|
159
|
+
@secure = false
|
160
|
+
@use_system_ssl_cert_chain= false
|
161
|
+
@host = 'api.airbrake.io'
|
162
|
+
@port = nil
|
163
|
+
@http_open_timeout = 2
|
164
|
+
@http_read_timeout = 5
|
165
|
+
@params_filters = DEFAULT_PARAMS_FILTERS.dup
|
166
|
+
@params_whitelist_filters = DEFAULT_PARAMS_WHITELIST_FILTERS.dup
|
167
|
+
@backtrace_filters = DEFAULT_BACKTRACE_FILTERS.dup
|
168
|
+
@ignore_by_filters = [] # These filters are applied to both server requests and Rake tasks
|
169
|
+
@ignore = IGNORE_DEFAULT.dup
|
170
|
+
@ignore_rake = [] # Rake tasks don't ignore any exception classes by default
|
171
|
+
@ignore_user_agent = []
|
172
|
+
@development_environments = %w(development test cucumber)
|
173
|
+
@development_lookup = true
|
174
|
+
@notifier_name = 'Airbrake Notifier'
|
175
|
+
@notifier_version = VERSION
|
176
|
+
@notifier_url = 'https://github.com/airbrake/airbrake'
|
177
|
+
@framework = 'Standalone'
|
178
|
+
@user_information = 'Airbrake Error {{error_id}}'
|
179
|
+
@rescue_rake_exceptions = nil
|
180
|
+
@user_attributes = DEFAULT_USER_ATTRIBUTES.dup
|
181
|
+
@rake_environment_filters = []
|
182
|
+
@async = nil
|
183
|
+
end
|
184
|
+
|
185
|
+
# Takes a block and adds it to the list of backtrace filters. When the filters
|
186
|
+
# run, the block will be handed each line of the backtrace and can modify
|
187
|
+
# it as necessary.
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# config.filter_bracktrace do |line|
|
191
|
+
# line.gsub(/^#{Rails.root}/, "[Rails.root]")
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# @param [Proc] block The new backtrace filter.
|
195
|
+
# @yieldparam [String] line A line in the backtrace.
|
196
|
+
def filter_backtrace(&block)
|
197
|
+
self.backtrace_filters << block
|
198
|
+
end
|
199
|
+
|
200
|
+
# Takes a block and adds it to the list of ignore filters.
|
201
|
+
# When the filters run, the block will be handed the exception.
|
202
|
+
# @example
|
203
|
+
# config.ignore_by_filter do |exception_data|
|
204
|
+
# true if exception_data[:error_class] == "RuntimeError"
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# @param [Proc] block The new ignore filter
|
208
|
+
# @yieldparam [Hash] data The exception data given to +Airbrake.notify+
|
209
|
+
# @yieldreturn [Boolean] If the block returns true the exception will be ignored, otherwise it will be processed by airbrake.
|
210
|
+
def ignore_by_filter(&block)
|
211
|
+
self.ignore_by_filters << block
|
212
|
+
end
|
213
|
+
|
214
|
+
# Overrides the list of default ignored errors.
|
215
|
+
#
|
216
|
+
# @param [Array<Exception>] names A list of exceptions to ignore.
|
217
|
+
def ignore_only=(names)
|
218
|
+
@ignore = [names].flatten
|
219
|
+
end
|
220
|
+
|
221
|
+
# Overrides the list of default ignored errors during Rake tasks.
|
222
|
+
#
|
223
|
+
# @param [Array<Exception>] names A list of rake exceptions to ignore.
|
224
|
+
def ignore_rake_only=(names)
|
225
|
+
@ignore_rake = [names].flatten
|
226
|
+
end
|
227
|
+
|
228
|
+
# Overrides the list of default ignored user agents
|
229
|
+
#
|
230
|
+
# @param [Array<String>] A list of user agents to ignore
|
231
|
+
def ignore_user_agent_only=(names)
|
232
|
+
@ignore_user_agent = [names].flatten
|
233
|
+
end
|
234
|
+
|
235
|
+
# Allows config options to be read like a hash
|
236
|
+
#
|
237
|
+
# @param [Symbol] option Key for a given attribute
|
238
|
+
def [](option)
|
239
|
+
send(option)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Returns a hash of all configurable options
|
243
|
+
def to_hash
|
244
|
+
OPTIONS.inject({}) do |hash, option|
|
245
|
+
hash[option.to_sym] = self.send(option)
|
246
|
+
hash
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Returns a hash of all configurable options merged with +hash+
|
251
|
+
#
|
252
|
+
# @param [Hash] hash A set of configuration options that will take precedence over the defaults
|
253
|
+
def merge(hash)
|
254
|
+
to_hash.merge(hash)
|
255
|
+
end
|
256
|
+
|
257
|
+
# Determines if the notifier will send notices.
|
258
|
+
# @return [Boolean] Returns +true+ if an api string exists, +false+ otherwise.
|
259
|
+
def configured?
|
260
|
+
!api_key.nil? && !api_key.empty?
|
261
|
+
end
|
262
|
+
|
263
|
+
# Determines if the notifier will send notices.
|
264
|
+
# @return [Boolean] Returns +false+ if in a development environment, +true+ otherwise.
|
265
|
+
def public?
|
266
|
+
@public ||= !development_environments.include?(environment_name)
|
267
|
+
end
|
268
|
+
|
269
|
+
def port
|
270
|
+
@port || default_port
|
271
|
+
end
|
272
|
+
|
273
|
+
# Determines whether protocol should be "http" or "https".
|
274
|
+
# @return [String] Returns +"http"+ if you've set secure to +false+ in
|
275
|
+
# configuration, and +"https"+ otherwise.
|
276
|
+
def protocol
|
277
|
+
if secure?
|
278
|
+
'https'
|
279
|
+
else
|
280
|
+
'http'
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def user_attributes=(user_attributes)
|
285
|
+
@user_attributes = validate_user_attributes user_attributes
|
286
|
+
end
|
287
|
+
|
288
|
+
# Should Airbrake send notifications asynchronously
|
289
|
+
# (boolean, nil or callable; default is nil).
|
290
|
+
# Can be used as callable-setter when block provided.
|
291
|
+
def async(&block)
|
292
|
+
if block_given?
|
293
|
+
@async = block
|
294
|
+
end
|
295
|
+
@async
|
296
|
+
end
|
297
|
+
alias_method :async?, :async
|
298
|
+
|
299
|
+
def async=(use_default_or_this)
|
300
|
+
@async = use_default_or_this == true ?
|
301
|
+
default_async_processor :
|
302
|
+
use_default_or_this
|
303
|
+
end
|
304
|
+
|
305
|
+
def rescue_rake_exceptions=(val)
|
306
|
+
if val && !defined?(Airbrake::RakeHandler)
|
307
|
+
raise LoadError, "you must require 'airbrake/rake_handler' to rescue from rake exceptions"
|
308
|
+
end
|
309
|
+
@rescue_rake_exceptions = val
|
310
|
+
end
|
311
|
+
|
312
|
+
def ca_bundle_path
|
313
|
+
if use_system_ssl_cert_chain?
|
314
|
+
OpenSSL::X509::DEFAULT_CERT_FILE if File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE)
|
315
|
+
else
|
316
|
+
local_cert_path # ca-bundle.crt built from source, see resources/README.md
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def local_cert_path
|
321
|
+
File.expand_path(File.join("..", "..", "..", "resources", "ca-bundle.crt"), __FILE__)
|
322
|
+
end
|
323
|
+
|
324
|
+
def project_id=(project_id)
|
325
|
+
@project_id = "#{project_id}"
|
326
|
+
end
|
327
|
+
|
328
|
+
private
|
329
|
+
# Determines what port should we use for sending notices.
|
330
|
+
# @return [Fixnum] Returns 443 if you've set secure to true in your
|
331
|
+
# configuration, and 80 otherwise.
|
332
|
+
def default_port
|
333
|
+
if secure?
|
334
|
+
443
|
335
|
+
else
|
336
|
+
80
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
# Async notice delivery defaults to girl friday
|
341
|
+
def default_async_processor
|
342
|
+
if defined?(SuckerPunch)
|
343
|
+
lambda {|notice| SendJob.new.async.perform(notice)}
|
344
|
+
elsif defined?(GirlFriday)
|
345
|
+
queue = GirlFriday::WorkQueue.new(nil, :size => 3) do |notice|
|
346
|
+
Airbrake.sender.send_to_airbrake(notice)
|
347
|
+
end
|
348
|
+
lambda {|notice| queue << notice}
|
349
|
+
else
|
350
|
+
warn "[AIRBRAKE] You can't use the default async handler without sucker_punch or girl_friday."\
|
351
|
+
" Please make sure you have sucker_punch or girl_friday installed (sucker_punch is recommended)."
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def validate_user_attributes(user_attributes)
|
356
|
+
user_attributes.reject do |attribute|
|
357
|
+
unless VALID_USER_ATTRIBUTES.include? attribute.to_s
|
358
|
+
warn "[AIRBRAKE] Unsupported user attribute: '#{attribute}'. "\
|
359
|
+
"This attribute will not be shown in the Airbrake UI. "\
|
360
|
+
"Check http://git.io/h6YRpA for more info."
|
361
|
+
true
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|