forked from airbrake/airbrake
/
airbrake.rb
172 lines (146 loc) · 5.47 KB
/
airbrake.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
begin
require "girl_friday"
rescue LoadError
end
require 'openssl'
require 'net/http'
require 'net/https'
require 'rubygems'
require 'logger'
require 'airbrake/version'
require 'airbrake/utils/rack_filters'
require 'airbrake/utils/params_cleaner'
require 'airbrake/configuration'
require 'airbrake/notice'
require 'airbrake/sender'
require 'airbrake/response'
require 'airbrake/backtrace'
require 'airbrake/rack'
require 'airbrake/sinatra'
require 'airbrake/user_informer'
require 'airbrake/railtie' if defined?(Rails::Railtie)
module Airbrake
API_VERSION = "2.4"
LOG_PREFIX = "** [Airbrake] "
class << self
# The sender object is responsible for delivering formatted data to the Airbrake server.
# Must respond to #send_to_airbrake. See Airbrake::Sender.
attr_accessor :sender
# A Airbrake configuration object. Must act like a hash and return sensible
# values for all Airbrake configuration options. See Airbrake::Configuration.
attr_writer :configuration
# Tell the log that the Notifier is good to go
def report_ready
write_verbose_log("Notifier #{VERSION} ready to catch errors")
end
# Prints out the environment info to the log for debugging help
def report_environment_info
write_verbose_log("Environment Info: #{environment_info}")
end
# Prints out the response body from Airbrake for debugging help
def report_response_body(response)
write_verbose_log("Response from Airbrake: \n#{Response.pretty_format(response)}")
end
# Prints out the details about the notice that wasn't sent to server
def report_notice(notice)
write_verbose_log("Notice details: \n#{notice}")
end
# Returns the Ruby version, Rails version, and current Rails environment
def environment_info
info = "[Ruby: #{RUBY_VERSION}]"
info << " [#{configuration.framework}]" if configuration.framework
info << " [Env: #{configuration.environment_name}]" if configuration.environment_name
info
end
# Writes out the given message to the #logger
def write_verbose_log(message)
logger.debug LOG_PREFIX + message if logger
end
# Look for the Rails logger currently defined
def logger
self.configuration.logger ||
Logger.new(nil)
end
# Call this method to modify defaults in your initializers.
#
# @example
# Airbrake.configure do |config|
# config.api_key = '1234567890abcdef'
# config.secure = false
# end
def configure(silent = false)
yield(configuration)
self.sender = if configuration.test_mode?
CollectingSender.new(configuration)
else
Sender.new(configuration)
end
report_ready unless silent
self.sender
end
# The configuration object.
# @see Airbrake.configure
def configuration
@configuration ||= Configuration.new
end
# Sends an exception manually using this method, even when you are not in a controller.
#
# @param [Exception] exception The exception you want to notify Airbrake about.
# @param [Hash] opts Data that will be sent to Airbrake.
#
# @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Airbrake uses for identification.
# @option opts [String] :error_message The error returned by the exception (or the message you want to log).
# @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
# @option opts [String] :rack_env The Rack environment.
# @option opts [String] :session The contents of the user's session.
# @option opts [String] :environment_name The application environment name.
def notify(exception, opts = {})
send_notice(build_notice_for(exception, opts))
end
# Sends the notice unless it is one of the default ignored exceptions
# @see Airbrake.notify
def notify_or_ignore(exception, opts = {})
notice = build_notice_for(exception, opts)
send_notice(notice) unless notice.ignore?
end
def build_lookup_hash_for(exception, options = {})
notice = build_notice_for(exception, options)
result = {}
result[:action] = notice.action rescue nil
result[:component] = notice.component rescue nil
result[:error_class] = notice.error_class if notice.error_class
result[:environment_name] = 'production'
unless notice.backtrace.lines.empty?
result[:file] = notice.backtrace.lines.first.file
result[:line_number] = notice.backtrace.lines.first.number
end
result
end
private
def send_notice(notice)
if configuration.public?
if configuration.async?
configuration.async.call(notice)
nil # make sure we never set env["airbrake.error_id"] for async notices
else
sender.send_to_airbrake(notice)
end
end
end
def build_notice_for(exception, opts = {})
exception = unwrap_exception(exception)
opts = opts.merge(:exception => exception) if exception.is_a?(Exception)
opts = opts.merge(exception.to_hash) if exception.respond_to?(:to_hash)
Notice.new(configuration.merge(opts))
end
def unwrap_exception(exception)
if exception.respond_to?(:original_exception)
exception.original_exception
elsif exception.respond_to?(:continued_exception)
exception.continued_exception
else
exception
end
end
end
end