crashlog 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +161 -0
- data/INSTALL +22 -0
- data/README.md +14 -4
- data/Rakefile +13 -0
- data/crashlog.gemspec +12 -3
- data/generators/crashlog/templates/initializer.rb +6 -0
- data/install.rb +2 -0
- data/lib/crash_log/backtrace/line.rb +105 -0
- data/lib/crash_log/backtrace/line_cache.rb +23 -0
- data/lib/crash_log/backtrace.rb +66 -0
- data/lib/crash_log/configuration.bak.rb +199 -0
- data/lib/crash_log/configuration.rb +188 -0
- data/lib/crash_log/logging.rb +51 -0
- data/lib/crash_log/payload.rb +157 -0
- data/lib/crash_log/rack.rb +47 -0
- data/lib/crash_log/rails/action_controller_rescue.rb +32 -0
- data/lib/crash_log/rails/controller_methods.rb +45 -0
- data/lib/crash_log/rails/middleware/debug_exception_catcher.rb +43 -0
- data/lib/crash_log/rails.rb +32 -0
- data/lib/crash_log/railtie.rb +41 -0
- data/lib/crash_log/reporter.rb +105 -0
- data/lib/crash_log/system_information.rb +64 -0
- data/lib/crash_log/templates/payload.rabl +7 -0
- data/lib/crash_log/version.rb +1 -1
- data/lib/crash_log.rb +118 -0
- data/lib/faraday/request/hmac_authentication.rb +73 -0
- data/lib/rails/generators/crashlog/crashlog_generator.rb +42 -0
- data/rails/init.rb +1 -0
- data/spec/crash_log/backtrace_spec.rb +79 -0
- data/spec/crash_log/initializer_spec.rb +53 -0
- data/spec/crash_log/payload_spec.rb +124 -0
- data/spec/crash_log/reporter_spec.rb +179 -0
- data/spec/crash_log_spec.rb +153 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/break_controller.rb +10 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +44 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/crashlog.rb +6 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +6 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/requests/rack_spec.rb +29 -0
- data/spec/requests/rails_controller_rescue_spec.rb +46 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/doing.rb +1 -0
- data/spec/support/dummy_app.rb +13 -0
- data/spec/support/hash_ext.rb +7 -0
- metadata +197 -7
@@ -0,0 +1,45 @@
|
|
1
|
+
module CrashLog
|
2
|
+
module Rails
|
3
|
+
module ControllerMethods
|
4
|
+
|
5
|
+
def crash_log_context
|
6
|
+
{ :parameters => crash_log_filter_if_filtering(params.to_hash),
|
7
|
+
:session_data => crash_log_filter_if_filtering(crash_log_session_data),
|
8
|
+
:controller => params[:controller],
|
9
|
+
:action => params[:action],
|
10
|
+
:url => crash_log_request_url,
|
11
|
+
:cgi_data => crash_log_filter_if_filtering(request.env)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def notify_crashlog(exception, custom_data = nil)
|
17
|
+
request_data = crash_log_context
|
18
|
+
#request_data[:meta_data][:custom] = custom_data if custom_data
|
19
|
+
CrashLog.notify(exception, request_data)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias_method :notify_airbrake, :notify_crashlog
|
23
|
+
|
24
|
+
def crash_log_session_data
|
25
|
+
if session.respond_to?(:to_hash)
|
26
|
+
session.to_hash
|
27
|
+
else
|
28
|
+
session.data
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def crash_log_request_url
|
33
|
+
url = "#{request.protocol}#{request.host}"
|
34
|
+
|
35
|
+
unless [80, 443].include?(request.port)
|
36
|
+
url << ":#{request.port}"
|
37
|
+
end
|
38
|
+
|
39
|
+
url << request.fullpath
|
40
|
+
url
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module CrashLog
|
2
|
+
module Rails
|
3
|
+
module Middleware
|
4
|
+
module DebugExceptionCatcher
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.send(:alias_method_chain, :render_exception, :crash_log)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Hook into the rails error rendering page to send this exception to
|
11
|
+
# CrashLog before rails handlers take over.
|
12
|
+
def render_exception_with_crash_log(env, exception)
|
13
|
+
controller = env['action_controller.instance']
|
14
|
+
|
15
|
+
env['crash_log.error_id'] = CrashLog.notify(exception) #,
|
16
|
+
# crash_log_context(controller, env))
|
17
|
+
|
18
|
+
if defined?(controller.rescue_action_in_public_without_crash_log)
|
19
|
+
controller.rescue_action_in_public_without_crash_log(exception)
|
20
|
+
end
|
21
|
+
|
22
|
+
rescue Exception => e
|
23
|
+
# If it breaks here there is possibly something wrong with us, so
|
24
|
+
# instead of crashing again, we'll just pass it on.
|
25
|
+
ensure
|
26
|
+
render_exception_without_crash_log(env, exception)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def crash_log_context(controller, env)
|
32
|
+
# TODO: Replace this with user context lookup
|
33
|
+
if controller.respond_to?(:crash_log_request_data)
|
34
|
+
controller.crash_log_request_data
|
35
|
+
else
|
36
|
+
{:rack_env => env}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "crash_log"
|
2
|
+
require "crash_log/rails/controller_methods"
|
3
|
+
require "crash_log/rails/action_controller_rescue"
|
4
|
+
|
5
|
+
# Rails 2.x support
|
6
|
+
module CrashLog
|
7
|
+
module Rails
|
8
|
+
def self.initialize
|
9
|
+
if defined?(ActionController::Base)
|
10
|
+
ActionController::Base.send(:include, CrashLog::Rails::ActionControllerRescue)
|
11
|
+
ActionController::Base.send(:include, CrashLog::Rails::ControllerMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Try to find where to log to
|
15
|
+
rails_logger = nil
|
16
|
+
if defined?(::Rails.logger)
|
17
|
+
rails_logger = ::Rails.logger
|
18
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
19
|
+
rails_logger = RAILS_DEFAULT_LOGGER
|
20
|
+
end
|
21
|
+
|
22
|
+
CrashLog.configure do |config|
|
23
|
+
config.logger = rails_logger
|
24
|
+
config.release_stage = RAILS_ENV if defined?(RAILS_ENV)
|
25
|
+
config.project_root = RAILS_ROOT if defined?(RAILS_ROOT)
|
26
|
+
config.framework = "Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
CrashLog::Rails.initialize
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'crash_log'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
# Rails 3.x support
|
5
|
+
module CrashLog
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
|
8
|
+
config.after_initialize do
|
9
|
+
CrashLog.configure do |config|
|
10
|
+
config.logger ||= ::Rails.logger
|
11
|
+
config.stage ||= ::Rails.env
|
12
|
+
config.project_root ||= ::Rails.root
|
13
|
+
config.framework = "Rails: #{::Rails::VERSION::STRING}"
|
14
|
+
end
|
15
|
+
|
16
|
+
initializer "crash_log.use_rack_middleware" do |app|
|
17
|
+
app.config.middleware.insert 0, "CrashLog::Rack"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Attach our Rails Controller methods
|
21
|
+
ActiveSupport.on_load(:action_controller) do
|
22
|
+
# Lazily load action_controller methods
|
23
|
+
require 'crash_log/rails/controller_methods'
|
24
|
+
|
25
|
+
include CrashLog::Rails::ControllerMethods
|
26
|
+
end
|
27
|
+
|
28
|
+
if defined?(::ActionDispatch::DebugExceptions)
|
29
|
+
# We should catch the exceptions in ActionDispatch::DebugExceptions in Rails 3.2.x.
|
30
|
+
require 'crash_log/rails/middleware/debug_exception_catcher'
|
31
|
+
::ActionDispatch::DebugExceptions.__send__(:include, CrashLog::Rails::Middleware::DebugExceptionCatcher)
|
32
|
+
elsif defined?(::ActionDispatch::ShowExceptions)
|
33
|
+
|
34
|
+
# ActionDispatch::DebugExceptions is not defined in Rails 3.0.x and 3.1.x so
|
35
|
+
# catch the exceptions in ShowExceptions.
|
36
|
+
require 'crash_log/rails/middleware/debug_exception_catcher'
|
37
|
+
::ActionDispatch::ShowExceptions.send(:include, CrashLog::Rails::Middleware::DebugExceptionCatcher)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday/request/hmac_authentication'
|
3
|
+
require 'uuid'
|
4
|
+
require 'yajl'
|
5
|
+
|
6
|
+
module CrashLog
|
7
|
+
class Reporter
|
8
|
+
include Logging
|
9
|
+
|
10
|
+
attr_reader :host, :port, :scheme, :endpoint, :announce_endpoint
|
11
|
+
attr_reader :result, :config, :response
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
@scheme = config.scheme
|
16
|
+
@host = config.host
|
17
|
+
@port = config.port
|
18
|
+
@endpoint = config.endpoint
|
19
|
+
@announce_endpoint = config.announce == true ?
|
20
|
+
config.announce_endpoint : nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify(payload)
|
24
|
+
#return if dry_run?
|
25
|
+
#MultiJson.use(:yajl)
|
26
|
+
response = post(endpoint, MultiJson.encode({:payload => payload}))
|
27
|
+
@response = response
|
28
|
+
report_result(response.body)
|
29
|
+
response.success?
|
30
|
+
rescue => e
|
31
|
+
log_exception e
|
32
|
+
error("Sending exception failed due to a connectivity issue")
|
33
|
+
end
|
34
|
+
|
35
|
+
def announce
|
36
|
+
return if dry_run?
|
37
|
+
return "Unknown application" unless announce_endpoint
|
38
|
+
|
39
|
+
response = post(config.announce_endpoint, JSON.dump(identification_hash))
|
40
|
+
if response.status == 201
|
41
|
+
JSON.load(response.body).symbolize_keys.fetch(:application, 'Default')
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
rescue => e
|
46
|
+
# We only want to log our mess when testing
|
47
|
+
log_exception(e) # if respond_to?(:should)
|
48
|
+
error("Failed to announce application launch")
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def report_result(body)
|
53
|
+
@result = JSON.load(body).symbolize_keys
|
54
|
+
end
|
55
|
+
|
56
|
+
def url
|
57
|
+
URI.parse("#{scheme}://#{host}:#{port}")
|
58
|
+
end
|
59
|
+
|
60
|
+
def identification_hash
|
61
|
+
{
|
62
|
+
:hostname => SystemInformation.hostname,
|
63
|
+
:timestamp => Time.now.utc.to_i
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_result
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
def dry_run?
|
72
|
+
config.dry_run == true
|
73
|
+
end
|
74
|
+
|
75
|
+
def post(endpoint, body)
|
76
|
+
connection.post do |req|
|
77
|
+
req.url(endpoint)
|
78
|
+
# req.sign!(config.project_id, config.api_key)
|
79
|
+
req.headers['Content-Type'] = 'application/json'
|
80
|
+
req.body = body
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# private
|
85
|
+
|
86
|
+
def connection
|
87
|
+
@connection ||= begin
|
88
|
+
Faraday.new(:url => url) do |faraday|
|
89
|
+
faraday.request :hmac_authentication, config.project_id, config.api_key, {:service_id => config.service_name}
|
90
|
+
faraday.adapter(adapter)
|
91
|
+
faraday.request :url_encoded
|
92
|
+
# faraday.request :token_auth, config.api_key
|
93
|
+
# faraday.response :logger
|
94
|
+
# faraday.options[:timeout] = config.http_read_timeout
|
95
|
+
# faraday.options[:open_timeout] = config.http_open_timeout
|
96
|
+
# faraday.ssl[:verify] = false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def adapter
|
102
|
+
config.adapter
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module CrashLog
|
2
|
+
class SystemInformation
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def to_hash
|
6
|
+
{
|
7
|
+
:hostname => hostname,
|
8
|
+
:ruby_version => ruby_version,
|
9
|
+
:username => username,
|
10
|
+
:environment => environment,
|
11
|
+
:libraries_loaded => libraries_loaded,
|
12
|
+
:platform => platform,
|
13
|
+
:application_root => application_root,
|
14
|
+
:stage => stage
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def hostname
|
19
|
+
require 'socket' unless defined?(Socket)
|
20
|
+
Socket.gethostname
|
21
|
+
rescue
|
22
|
+
'UNKNOWN'
|
23
|
+
end
|
24
|
+
|
25
|
+
def ruby_version
|
26
|
+
"#{RUBY_VERSION rescue '?.?.?'}-p#{RUBY_PATCHLEVEL rescue '???'} #{RUBY_RELEASE_DATE rescue '????-??-??'} #{RUBY_PLATFORM rescue '????'}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def username
|
30
|
+
ENV['LOGNAME'] || ENV['USER'] || ENV['USERNAME'] || ENV['APACHE_RUN_USER'] || 'UNKNOWN'
|
31
|
+
end
|
32
|
+
|
33
|
+
def environment
|
34
|
+
if ENV.respond_to?(:to_hash)
|
35
|
+
ENV.to_hash.reject do |k, v|
|
36
|
+
(k =~ /^HTTP_/) || CrashLog.configuration.environment_filters.include?(k)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def libraries_loaded
|
44
|
+
Hash[*Gem.loaded_specs.map {|name, gem_specification|
|
45
|
+
[name, gem_specification.version.to_s]
|
46
|
+
}.flatten]
|
47
|
+
rescue
|
48
|
+
{}
|
49
|
+
end
|
50
|
+
|
51
|
+
def platform
|
52
|
+
RUBY_PLATFORM rescue '????'
|
53
|
+
end
|
54
|
+
|
55
|
+
def application_root
|
56
|
+
CrashLog.configuration.root
|
57
|
+
end
|
58
|
+
|
59
|
+
def stage
|
60
|
+
CrashLog.configuration.stage
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/crash_log/version.rb
CHANGED
data/lib/crash_log.rb
CHANGED
@@ -1,5 +1,123 @@
|
|
1
|
+
$: << File.expand_path('..', __FILE__)
|
2
|
+
|
1
3
|
require 'crash_log/version'
|
4
|
+
begin
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
rescue LoadError
|
8
|
+
require 'activesupport'
|
9
|
+
require 'activesupport/core_ext'
|
10
|
+
end
|
11
|
+
require 'faraday'
|
12
|
+
require 'crash_log/railtie' if defined?(Rails::Railtie)
|
13
|
+
|
14
|
+
require 'crash_log/logging'
|
2
15
|
|
3
16
|
module CrashLog
|
17
|
+
extend Logging::ClassMethods
|
18
|
+
|
19
|
+
autoload :Backtrace, 'crash_log/backtrace'
|
20
|
+
autoload :Configuration, 'crash_log/configuration'
|
21
|
+
autoload :Payload, 'crash_log/payload'
|
22
|
+
autoload :Rack, 'crash_log/rack'
|
23
|
+
autoload :Reporter, 'crash_log/reporter'
|
24
|
+
autoload :SystemInformation, 'crash_log/system_information'
|
25
|
+
|
26
|
+
LOG_PREFIX = '** [CrashLog]'
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
# Sends a notification to CrashLog
|
31
|
+
#
|
32
|
+
# This is the main entry point into the exception sending stack.
|
33
|
+
#
|
34
|
+
# Examples:
|
35
|
+
#
|
36
|
+
# def something_dangerous
|
37
|
+
# raise RuntimeError, "This is too dangerous for you"
|
38
|
+
# rescue => e
|
39
|
+
# CrashLog.notify(e)
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# You can also include information about the current user and Crashlog
|
43
|
+
# will allow you to correlate errors by affected users:
|
44
|
+
#
|
45
|
+
# def something_dangerous
|
46
|
+
# raise RuntimeError, "This is too dangerous for you"
|
47
|
+
# rescue => e
|
48
|
+
# CrashLog.notify(e, {current_user: current_user})
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# This will try to serialize the current user by calling `as_crashlog_context` or `as_json`
|
52
|
+
# otherwise it will try `to_s`
|
53
|
+
#
|
54
|
+
# Returns true if successful, otherwise false
|
55
|
+
def notify(exception, context = {})
|
56
|
+
send_notification(exception, context)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sends the notice unless it is one of the default ignored exceptions.
|
60
|
+
def notify_or_ignore(exception, context = {})
|
61
|
+
send_notification(exception, context = {}) unless ignored?(exception)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Print a message at the top of the applciation's logs to say we're ready.
|
65
|
+
def report_for_duty!
|
66
|
+
application = CrashLog::Reporter.new(configuration).announce
|
67
|
+
|
68
|
+
if application
|
69
|
+
info("Initialized and ready to handle exceptions for #{application}")
|
70
|
+
else
|
71
|
+
error("Failed to report for duty, your application failed to authenticate correctly with stdin.crashlog.io")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Configure the gem to send notifications, at the very least an api_key is
|
76
|
+
# required.
|
77
|
+
def configure
|
78
|
+
yield(configuration) if block_given?
|
79
|
+
if configuration.valid?
|
80
|
+
report_for_duty!
|
81
|
+
else
|
82
|
+
error('Not configured correctly')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# The global configuration object.
|
87
|
+
def configuration
|
88
|
+
@configuration ||= Configuration.new
|
89
|
+
end
|
90
|
+
|
91
|
+
# The default logging device.
|
92
|
+
def logger
|
93
|
+
self.configuration.logger || Logger.new($stdout)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Is the logger live
|
97
|
+
#
|
98
|
+
# Returns true if the current stage is included in the release
|
99
|
+
# stages config, false otherwise.
|
100
|
+
def live?
|
101
|
+
configuration.release_stage?
|
102
|
+
end
|
103
|
+
|
104
|
+
# Looks up ignored exceptions
|
105
|
+
#
|
106
|
+
# Returns true if this exception should be ignored, false otherwise.
|
107
|
+
def ignored?(exception)
|
108
|
+
configuration.ignored?(exception)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def send_notification(exception, context = {})
|
114
|
+
build_payload(exception, context).deliver! if live?
|
115
|
+
end
|
4
116
|
|
117
|
+
def build_payload(exception, context = {})
|
118
|
+
Payload.build(exception, configuration) do |payload|
|
119
|
+
payload.add_context(context)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
5
123
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Faraday
|
2
|
+
class Request
|
3
|
+
|
4
|
+
require 'crash_log/auth_hmac'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
attr_reader :access_id, :secret
|
8
|
+
|
9
|
+
# # Sign the request with the specified `access_id` and `secret`.
|
10
|
+
# def sign!(access_id, secret)
|
11
|
+
# @access_id, @secret = access_id, secret
|
12
|
+
|
13
|
+
# #self.sign_with = access_id
|
14
|
+
# #CrashLog::AuthHMAC.keys[access_id] = secret
|
15
|
+
# end
|
16
|
+
|
17
|
+
class HMACAuthentication < Faraday::Middleware
|
18
|
+
# Modified CanonicalString to know how to pull from the Faraday-specific
|
19
|
+
# env hash.
|
20
|
+
class CanonicalString < CrashLog::AuthHMAC::CanonicalString
|
21
|
+
def request_method(request)
|
22
|
+
request[:method].to_s.upcase
|
23
|
+
end
|
24
|
+
|
25
|
+
def request_body(request)
|
26
|
+
request[:body]
|
27
|
+
end
|
28
|
+
|
29
|
+
# def request_path(request)
|
30
|
+
# URI.parse(request[:url]).path
|
31
|
+
# end
|
32
|
+
|
33
|
+
def request_path(request)
|
34
|
+
URI.parse(request[:url].to_s).path
|
35
|
+
end
|
36
|
+
|
37
|
+
def headers(request)
|
38
|
+
request[:request_headers]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
KEY = "Authorization".freeze
|
43
|
+
|
44
|
+
attr_reader :auth, :token, :secret
|
45
|
+
|
46
|
+
def initialize(app, token, secret, options = {})
|
47
|
+
options.merge!(:signature => HMACAuthentication::CanonicalString)
|
48
|
+
keys = {token => secret}
|
49
|
+
@token, @secret = token, secret
|
50
|
+
@auth = CrashLog::AuthHMAC.new(keys, options)
|
51
|
+
super(app)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Public
|
55
|
+
def call(env)
|
56
|
+
env[:request_headers][KEY] ||= hmac_auth_header(env).to_s #if sign_request?
|
57
|
+
puts env[:request_headers]
|
58
|
+
@app.call(env)
|
59
|
+
end
|
60
|
+
|
61
|
+
def hmac_auth_header(env)
|
62
|
+
auth.authorization(env, token, secret)
|
63
|
+
end
|
64
|
+
|
65
|
+
def sign_request?
|
66
|
+
!!@token && !!@secret
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Faraday.register_middleware :request, :hmac_authentication => Faraday::Request::HMACAuthentication
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
class CrashlogGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
class_option :api_key, :aliases => "-k", :type => :string, :desc => "Your CrashLog API key"
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
@_crashlog_source_root ||= File.expand_path("../../../../../generators/crashlog/templates", __FILE__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def install
|
12
|
+
ensure_api_key_was_configured
|
13
|
+
generate_initializer unless api_key_configured?
|
14
|
+
test_crashlog
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def ensure_api_key_was_configured
|
20
|
+
if !options[:api_key] && !api_key_configured?
|
21
|
+
puts "Must pass --api-key or create config/initializers/crashlog.rb"
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def api_key_expression
|
27
|
+
"'#{options[:api_key]}'"
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_initializer
|
31
|
+
template 'initializer.rb', 'config/initializers/crashlog.rb'
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_key_configured?
|
35
|
+
File.exists?('config/initializers/crashlog.rb')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_crashlog
|
39
|
+
puts run("rake crashlog:test")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "crash_log/rails"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CrashLog::Backtrace do
|
4
|
+
let(:raised_error) do
|
5
|
+
begin
|
6
|
+
raise RuntimeError, "This broke"
|
7
|
+
rescue RuntimeError => e
|
8
|
+
e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.parse' do
|
13
|
+
it 'accepts a standed caller array' do
|
14
|
+
CrashLog::Backtrace.parse(caller).to_a.size.should == caller.size
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts a ruby exception backtrace' do
|
18
|
+
CrashLog::Backtrace.parse(raised_error.backtrace).to_a.size.should ==
|
19
|
+
raised_error.backtrace.size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'lines' do
|
24
|
+
it 'are converted into a parsed Line object' do
|
25
|
+
CrashLog::Backtrace.parse(raised_error.backtrace).lines.first.should be_a(CrashLog::Backtrace::Line)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'responds to to_hash' do
|
29
|
+
CrashLog::Backtrace.parse(raised_error.backtrace).lines.first.to_hash.should have_keys(:number, :method, :file)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'captures line context' do
|
33
|
+
line = CrashLog::Backtrace.parse(raised_error.backtrace).lines.first
|
34
|
+
line.context_line.should match /raise RuntimeError/
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'captures pre_context' do
|
38
|
+
line = CrashLog::Backtrace.parse(raised_error.backtrace).lines.first
|
39
|
+
line.pre_context.should == [
|
40
|
+
"require \\'spec_helper\\'",
|
41
|
+
"",
|
42
|
+
"describe CrashLog::Backtrace do",
|
43
|
+
" let(:raised_error) do",
|
44
|
+
" begin"
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'captures pre_context' do
|
49
|
+
line = CrashLog::Backtrace.parse(raised_error.backtrace).lines.first
|
50
|
+
line.post_context.should == [
|
51
|
+
" rescue RuntimeError => e",
|
52
|
+
" e",
|
53
|
+
" end",
|
54
|
+
" end",
|
55
|
+
""
|
56
|
+
]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'filters' do
|
61
|
+
it 'should replace project root with [PROJECT_ROOT]' do
|
62
|
+
CrashLog.configuration.project_root = File.expand_path('../../', __FILE__)
|
63
|
+
filters = CrashLog.configuration.backtrace_filters
|
64
|
+
backtrace = CrashLog::Backtrace.parse(raised_error.backtrace, :filters => filters)
|
65
|
+
|
66
|
+
backtrace.lines.first.file.should match /\[PROJECT_ROOT\]/
|
67
|
+
backtrace.lines.first.file.should == '[PROJECT_ROOT]/crash_log/backtrace_spec.rb'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should not replace project root if it is not set' do
|
71
|
+
CrashLog.configuration.project_root = nil
|
72
|
+
|
73
|
+
filter = CrashLog::Configuration::DEFAULT_BACKTRACE_FILTERS
|
74
|
+
backtrace = CrashLog::Backtrace.parse(raised_error.backtrace, :filters => filter)
|
75
|
+
|
76
|
+
backtrace.lines.first.file.should_not match /\[PROJECT_ROOT\]/
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|