-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Sebastian Ohm <[email protected]>
- Loading branch information
Marc Tudurí
and
Sebastian Ohm
authored
Jan 6, 2022
1 parent
2c987cb
commit bf6a617
Showing
8 changed files
with
171 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,5 @@ source "https://rubygems.org" | |
|
||
gem "rspec" | ||
gem "timecop" | ||
gem "rack" | ||
gem "webmock" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
require 'periskop/client/collector' | ||
require 'periskop/client/exporter' | ||
require 'periskop/client/models' | ||
|
||
module Periskop | ||
module Rack | ||
class Middleware | ||
attr_accessor :collector | ||
|
||
def initialize(app, options = {}) | ||
@app = app | ||
@pushgateway_address = options.fetch(:pushgateway_address) | ||
@collector = Periskop::Client::ExceptionCollector.new | ||
@exporter = Periskop::Client::Exporter.new(@collector) | ||
end | ||
|
||
def call(env) | ||
begin | ||
response = @app.call(env) | ||
rescue Exception => ex | ||
report_push(env, ex) | ||
raise(ex) | ||
end | ||
|
||
maybe_ex = framework_exception(env) | ||
report_push(env, maybe_ex) if maybe_ex | ||
|
||
response | ||
end | ||
|
||
private | ||
|
||
# Web framework middlewares often store rescued exceptions inside the | ||
# Rack env, but Rack doesn't have a standard key for it: | ||
# | ||
# - Rails uses action_dispatch.exception: https://goo.gl/Kd694n | ||
# - Sinatra uses sinatra.error: https://goo.gl/LLkVL9 | ||
# - Goliath uses rack.exception: https://goo.gl/i7e1nA | ||
def framework_exception(env) | ||
env['rack.exception'] || | ||
env['sinatra.error'] || | ||
env['action_dispatch.exception'] | ||
end | ||
|
||
def find_request(env) | ||
if defined?(ActionDispatch::Request) | ||
ActionDispatch::Request.new(env) | ||
elsif defined?(Sinatra::Request) | ||
Sinatra::Request.new(env) | ||
else | ||
::Rack::Request.new(env) | ||
end | ||
end | ||
|
||
def get_http_headers(request_env) | ||
header_prefixes = %w[ | ||
HTTP_ | ||
CONTENT_TYPE | ||
CONTENT_LENGTH | ||
].freeze | ||
|
||
request_env.map.with_object({}) do |(key, value), headers| | ||
if header_prefixes.any? { |prefix| key.to_s.start_with?(prefix) } | ||
headers[key] = value | ||
end | ||
headers | ||
end | ||
end | ||
|
||
def get_http_context(env) | ||
request = find_request(env) | ||
Periskop::Client::HTTPContext.new(request.request_method, request.url, get_http_headers(request.env), nil) | ||
end | ||
|
||
def report_push(env, maybe_ex) | ||
ex = | ||
if maybe_ex.is_a?(Exception) | ||
maybe_ex | ||
else | ||
RuntimeError.new(maybe_ex.to_s) | ||
end | ||
@collector.report_with_context(ex, get_http_context(env)) | ||
@exporter.push_to_gateway(@pushgateway_address) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require 'rack' | ||
require 'periskop/rack/middleware' | ||
require 'webmock/rspec' | ||
|
||
describe Periskop::Rack::Middleware do | ||
class App | ||
def call(_) | ||
raise StandardError | ||
end | ||
end | ||
|
||
let :middleware do | ||
stub_request(:post, 'http://localhost:7878/errors') | ||
Periskop::Rack::Middleware.new(App.new, pushgateway_address: 'http://localhost:7878') | ||
end | ||
|
||
it 'captures exception on error' do | ||
begin | ||
middleware.call env_for('http://example.com?q=s', {}) | ||
rescue StandardError | ||
expect(middleware.collector.aggregated_exceptions_dict.size).to eq(1) | ||
end | ||
end | ||
|
||
def env_for(url, opts = {}) | ||
Rack::MockRequest.env_for(url, opts) | ||
end | ||
end |