class Google::Cloud::ErrorReporting::Middleware
Google::Cloud::ErrorReporting::Middleware
defines a Rack Middleware
that can automatically catch upstream exceptions and report them to Stackdriver Error Reporting.
Constants
- EXCEPTION_KEYS
Attributes
A Google::Cloud::ErrorReporting::Project
client used to report error events.
Public Class Methods
Construct a new instance of Middleware
.
@param [Rack::Application] app The Rack application @param [Google::Cloud::ErrorReporting::Project] error_reporting
A
Google::Cloud::ErrorReporting::Project client for reporting exceptions
@param [Hash] kwargs Hash of configuration settings. Used for backward
API compatibility. See the [Configuration Guide](https://googleapis.dev/ruby/stackdriver/latest/file.INSTRUMENTATION_CONFIGURATION.html) for the prefered way to set configuration parameters.
@return [Google::Cloud::ErrorReporting::Middleware] A new instance of
Middleware
# File lib/google/cloud/error_reporting/middleware.rb, line 48 def initialize app, error_reporting: nil, **kwargs require "rack" require "rack/request" @app = app load_config(**kwargs) @error_reporting = error_reporting || ErrorReporting.default_reporter do ErrorReporting::AsyncErrorReporter.new( ErrorReporting.new(project: configuration.project_id, credentials: configuration.credentials) ) end end
Public Instance Methods
Implements the mandatory Rack Middleware
call method.
Catch all Exceptions from upstream and report them to Stackdriver Error Reporting. Unless the exception's class is defined to be ignored by this Middleware
.
@param [Hash] env Rack environment hash
# File lib/google/cloud/error_reporting/middleware.rb, line 74 def call env response = @app.call env # sinatra doesn't always raise the Exception, but it saves it in # env['sinatra.error'] # # some frameworks (i.e. hanami) will save a rendering exception in # env['rack.exception'] EXCEPTION_KEYS.each do |exception_key| next unless env[exception_key].is_a? Exception report_exception env, env[exception_key] end response rescue Exception => e report_exception env, e # Always raise exception backup raise e end
Creates a {Google::Cloud::ErrorReporting::ErrorEvent} based on the exception. Fill in the HttpRequestContext section of the ErrorEvent
based on the HTTP Request headers.
When used in Rails environment. It replies on ActionDispatch::ExceptionWrapper class to derive a HTTP status code based on the exception's class.
@param [Hash] env Rack environment hash @param [Exception] exception Exception to convert from
@return [Google::Cloud::ErrorReporting::ErrorEvent] The gRPC
ErrorEvent object that's based on given env and exception
# File lib/google/cloud/error_reporting/middleware.rb, line 135 def error_event_from_exception env, exception error_event = ErrorReporting::ErrorEvent.from_exception exception # Inject service_context info into error_event object error_event.service_name = configuration.service_name error_event.service_version = configuration.service_version # Inject http_request_context info into error_event object rack_request = Rack::Request.new env error_event.http_method = rack_request.request_method error_event.http_url = rack_request.url error_event.http_user_agent = rack_request.user_agent error_event.http_referrer = rack_request.referrer error_event.http_status = http_status exception error_event.http_remote_ip = rack_request.ip error_event end
Report an given exception to Stackdriver Error Reporting.
While it reports most of the exceptions. Certain Rails exceptions that maps to a HTTP status code less than 500 will be treated as not the app fault and ignored.
@param [Hash] env Rack environment hash @param [Exception] exception The Ruby exception to report.
# File lib/google/cloud/error_reporting/middleware.rb, line 106 def report_exception env, exception # Do not any exceptions that's specified by the ignore_classes list. return if configuration.ignore_classes.include? exception.class error_event = error_event_from_exception env, exception # If this exception maps to a HTTP status code less than 500, do # not report it. status_code = error_event.http_status.to_i return if status_code.positive? && status_code < 500 error_reporting.report error_event end
Private Instance Methods
@private Get Google::Cloud::ErrorReporting.configure
# File lib/google/cloud/error_reporting/middleware.rb, line 216 def configuration Google::Cloud::ErrorReporting.configure end
Helper method to derive HTTP status code base on exception class in Rails. Returns nil if not in Rails environment.
@param [Exception] exception An Ruby exception
@return [Integer] A number that represents HTTP status code or nil if
status code can't be determined
# File lib/google/cloud/error_reporting/middleware.rb, line 199 def http_status exception http_status = nil if defined?(ActionDispatch::ExceptionWrapper) && ActionDispatch::ExceptionWrapper.respond_to?( :status_code_for_exception ) http_status = ActionDispatch::ExceptionWrapper.status_code_for_exception( exception.class.name ) end http_status end
Fallback to default configuration values if not defined already
# File lib/google/cloud/error_reporting/middleware.rb, line 182 def init_default_config configuration.project_id ||= (Cloud.configure.project_id || ErrorReporting::Project.default_project_id) configuration.credentials ||= Cloud.configure.credentials configuration.service_name ||= ErrorReporting::Project.default_service_name configuration.service_version ||= ErrorReporting::Project.default_service_version configuration.ignore_classes = Array(configuration.ignore_classes) end
Consolidate configurations from various sources. Also set instrumentation config parameters to default values if not set already.
# File lib/google/cloud/error_reporting/middleware.rb, line 161 def load_config **kwargs project_id = kwargs[:project] || kwargs[:project_id] configuration.project_id = project_id unless project_id.nil? creds = kwargs[:credentials] || kwargs[:keyfile] configuration.credentials = creds unless creds.nil? service_name = kwargs[:service_name] configuration.service_name = service_name unless service_name.nil? service_vers = kwargs[:service_version] configuration.service_version = service_vers unless service_vers.nil? ignores = kwargs[:ignore_classes] configuration.ignore_classes = ignores unless ignores.nil? init_default_config end