bolshakov / stoplight

:traffic_light: Traffic control for code.
http://bolshakov.github.io/stoplight/
MIT License
384 stars 40 forks source link

Allow Failure#to_json to accept options #134

Closed ct-clearhaus closed 4 years ago

ct-clearhaus commented 4 years ago

When using stoplight together with stoplight-admin, this surfaces when using the /stats endpoint when there's a failure.

Steps to reproduce

Drop a failure in the datastore

$ bundle exec irn -r redis -r stoplight
redis = Redis.new(host: 'redis')
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(redis)
light = Stoplight('shiny') { 1/0 }
light.run

Launch stoplight-admin

$ cat app.rb
require 'redis'
require 'sinatra'
require 'sinatra/stoplight_admin'
require 'webrick'

set :environment, :production
set :bind, '0.0.0.0'
set :port, 8080

set :data_store, Stoplight::DataStore::Redis.new(Redis.new(host: 'redis'))

WEBrick::Utils.su 'nobody'

$ bundle exec ruby app.rb

Access /stats

$ curl localhost:8080

Output

The server will now dump this:

2020-05-15 15:00:39 - ArgumentError - wrong number of arguments (given 1, expected 0):
        /var/lib/gems/2.3.0/gems/stoplight-2.2.0/lib/stoplight/failure.rb:56:in `to_json'
        /var/lib/gems/2.3.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_common.rb:19:in `to_json'
        /var/lib/gems/2.3.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_common.rb:19:in `dump'
        /var/lib/gems/2.3.0/gems/multi_json-1.14.1/lib/multi_json/adapter.rb:25:in `dump'
        /var/lib/gems/2.3.0/gems/multi_json-1.14.1/lib/multi_json.rb:139:in `dump'
        /var/lib/gems/2.3.0/gems/sinatra-contrib-2.0.8.1/lib/sinatra/json.rb:113:in `block in resolve_encoder_action'
        /var/lib/gems/2.3.0/gems/sinatra-contrib-2.0.8.1/lib/sinatra/json.rb:112:in `each'
        /var/lib/gems/2.3.0/gems/sinatra-contrib-2.0.8.1/lib/sinatra/json.rb:112:in `resolve_encoder_action'
        /var/lib/gems/2.3.0/gems/sinatra-contrib-2.0.8.1/lib/sinatra/json.rb:98:in `json'
        /opt/clearhaus/stoplightadmin/lib/sinatra/stoplight_admin.rb:128:in `block in registered'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1636:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1636:in `block in compile!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:987:in `block (3 levels) in route!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1006:in `route_eval'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:987:in `block (2 levels) in route!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1035:in `block in process_route'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1033:in `catch'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1033:in `process_route'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:985:in `block in route!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:984:in `each'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:984:in `route!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1098:in `block in dispatch!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `block in invoke'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `catch'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `invoke'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1095:in `dispatch!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:919:in `block in call!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `block in invoke'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `catch'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1072:in `invoke'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:919:in `call!'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:908:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/xss_header.rb:18:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/path_traversal.rb:16:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/json_csrf.rb:26:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/base.rb:50:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/base.rb:50:in `call'
        /var/lib/gems/2.3.0/gems/rack-protection-2.0.8.1/lib/rack/protection/frame_options.rb:31:in `call'
        /var/lib/gems/2.3.0/gems/rack-2.2.2/lib/rack/logger.rb:17:in `call'
        /var/lib/gems/2.3.0/gems/rack-2.2.2/lib/rack/common_logger.rb:38:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:231:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:224:in `call'
        /var/lib/gems/2.3.0/gems/rack-2.2.2/lib/rack/head.rb:12:in `call'
        /var/lib/gems/2.3.0/gems/rack-2.2.2/lib/rack/method_override.rb:24:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:194:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1951:in `call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1503:in `block in call'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1730:in `synchronize'
        /var/lib/gems/2.3.0/gems/sinatra-2.0.8.1/lib/sinatra/base.rb:1503:in `call'
        /var/lib/gems/2.3.0/gems/rack-2.2.2/lib/rack/handler/webrick.rb:95:in `service'
        /usr/lib/ruby/2.3.0/webrick/httpserver.rb:140:in `service'
        /usr/lib/ruby/2.3.0/webrick/httpserver.rb:96:in `run'
        /usr/lib/ruby/2.3.0/webrick/server.rb:296:in `block in start_thread'
172.29.0.1 - - [15/May/2020:15:00:39 +0000] "GET /stats HTTP/1.1" 500 30 0.0153

Suggested solution

Let Failure#to_json accept options that are passed on to JSON.generate (see ruby-doc) due to e.g.

$ cat -n /var/lib/gems/2.3.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_common.rb|tail -n+17|head -n 4
    17        def dump(object, options = {})
    18          options.merge!(::JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty)
    19          object.to_json(options)
    20        end
bolshakov commented 4 years ago

@ct-clearhaus thank you for the PR 👍 Stoplight 2.2.1 has been released with this fix.