$: << File.expand_path('..', __FILE__) require 'crash_log/version' begin require 'active_support' require 'active_support/core_ext' rescue LoadError require 'activesupport' require 'activesupport/core_ext' end require 'faraday' require 'crash_log/railtie' if defined?(Rails::Railtie) require 'crash_log/logging' module CrashLog extend Logging::ClassMethods autoload :Backtrace, 'crash_log/backtrace' autoload :Configuration, 'crash_log/configuration' autoload :Payload, 'crash_log/payload' autoload :Rack, 'crash_log/rack' autoload :Reporter, 'crash_log/reporter' autoload :SystemInformation, 'crash_log/system_information' LOG_PREFIX = '** [CrashLog]' class << self # Sends a notification to CrashLog # # This is the main entry point into the exception sending stack. # # Examples: # # def something_dangerous # raise RuntimeError, "This is too dangerous for you" # rescue => e # CrashLog.notify(e) # end # # You can also include information about the current user and Crashlog # will allow you to correlate errors by affected users: # # def something_dangerous # raise RuntimeError, "This is too dangerous for you" # rescue => e # CrashLog.notify(e, {current_user: current_user}) # end # # This will try to serialize the current user by calling `as_crashlog_context` or `as_json` # otherwise it will try `to_s` # # Returns true if successful, otherwise false def notify(exception, context = {}) send_notification(exception, context).tap do |notification| if notification info "Event sent to CrashLog.io" info "Event URL: http://crashlog.io/locate/#{notification[:location_id]}" if notification.has_key?(:location_id) else error "Failed to send event to CrashLog.io" log_exception(exception) end end end # Sends the notice unless it is one of the default ignored exceptions. def notify_or_ignore(exception, context = {}) send_notification(exception, context = {}) unless ignored?(exception) end # Print a message at the top of the applciation's logs to say we're ready. def report_for_duty! application = CrashLog::Reporter.new(configuration).announce if application info("Configured correctly and ready to handle exceptions for '#{application}'") else error("Failed to report for duty, your application failed to authenticate correctly with stdin.crashlog.io") end end # Configure the gem to send notifications, at the very least an api_key is # required. def configure(&block) if block_given? yield(configuration) if configuration.valid? report_for_duty! elsif !configuration.invalid_keys.include?(:api_key) error("Not configured correctly. Missing the following keys: #{configuration.invalid_keys.join(', ')}") end end end # The global configuration object. def configuration @configuration ||= Configuration.new end # The default logging device. def logger self.configuration.logger || Logger.new($stdout) end # Is the logger live # # Returns true if the current stage is included in the release # stages config, false otherwise. def live? configuration.release_stage? end # Looks up ignored exceptions # # Returns true if this exception should be ignored, false otherwise. def ignored?(exception) configuration.ignored?(exception) end private def send_notification(exception, context = {}) if live? build_payload(exception, context).deliver! end end def build_payload(exception, context = {}) Payload.build(exception, configuration) do |payload| payload.add_context(context) end end end end