From a557e877388cbba34c42423013336f2844b3649c Mon Sep 17 00:00:00 2001 From: petems Date: Sat, 13 Jul 2013 00:15:46 +0100 Subject: [PATCH] Added filter method for logger middleware Allows you to filter sensitive information with a regex, allowing a gsub with redaction: ```ruby conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday| faraday.response :logger do | logger | logger.filter(/(api_key=)(\w+)/,'\1[REMOVED]') end end ``` --- README.md | 8 ++++++++ lib/faraday/response/logger.rb | 19 ++++++++++++++----- test/adapters/logger_test.rb | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4ae634327..edeecf21a 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,14 @@ conn = Faraday.new(:url => 'http://sushi.com') do |faraday| faraday.adapter Faraday.default_adapter # make requests with Net::HTTP end +# filter sensitive information from logs with a regex matcher + +conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday| + faraday.response :logger do | logger | + logger.filter(/(api_key=)(\w+)/,'\1[REMOVED]') + end +end + ## GET ## response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json diff --git a/lib/faraday/response/logger.rb b/lib/faraday/response/logger.rb index 0b4d7140d..e34ca8366 100644 --- a/lib/faraday/response/logger.rb +++ b/lib/faraday/response/logger.rb @@ -12,22 +12,24 @@ def initialize(app, logger = nil, options = {}) require 'logger' ::Logger.new(STDOUT) end + @filter = [] @options = DEFAULT_OPTIONS.merge(options) + yield self if block_given? end def_delegators :@logger, :debug, :info, :warn, :error, :fatal def call(env) - info "#{env.method} #{env.url.to_s}" - debug('request') { dump_headers env.request_headers } - debug('request') { dump_body(env[:body]) } if env[:body] && log_body?(:request) + info "#{env.method} #{apply_filters(env.url.to_s)}" + debug('request') { apply_filters(dump_headers env.request_headers) } + debug('request') { apply_filters(dump_body(env[:body])) } if env[:body] && log_body?(:request) super end def on_complete(env) info('Status') { env.status.to_s } - debug('response') { dump_headers env.response_headers } - debug('response') { dump_body env[:body] } if env[:body] && log_body?(:response) + debug('response') { apply_filters(dump_headers env.response_headers) } + debug('response') { apply_filters(dump_body env[:body]) } if env[:body] && log_body?(:response) end private @@ -55,5 +57,12 @@ def log_body?(type) else @options[:bodies] end end + + def apply_filters(output) + @filter.each do |pattern, replacement| + output = output.to_s.gsub(pattern, replacement) + end + output + end end end diff --git a/test/adapters/logger_test.rb b/test/adapters/logger_test.rb index f75dcf5a5..9be4ee30a 100644 --- a/test/adapters/logger_test.rb +++ b/test/adapters/logger_test.rb @@ -9,6 +9,10 @@ def conn(logger, logger_options={}) Faraday.new do |b| b.response :logger, logger, logger_options + b.response :logger, @logger do | logger | + logger.filter(/foo/,'[REDACTED]') + logger.filter(/(api_key:).*"(.+)."/,'\1[API_KEY]') + end b.adapter :test do |stubs| stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] } stubs.post('/ohai') { [200, {'Content-Type' => 'text/html'}, 'fred'] } @@ -79,5 +83,22 @@ def test_log_response_body_object app.get '/rubbles', nil, :accept => 'text/html' assert_match %([\"Barney\", \"Betty\", \"Bam Bam\"]\n), @io.string end + + def test_logs_filter_url + app = conn(@logger) + app.get '/foo', nil, :accept => 'text/html' + assert_match %([REDACTED]), @io.string + refute_match %(foo), @io.string + end + + def test_logs_filter_header + app = conn(@logger) + app.headers = {'api_key' => 'ABC123'} + app.get '/bar', nil, :accept => 'text/html' + assert_match %(api_key:), @io.string + assert_match %([API_KEY]), @io.string + refute_match %(ABC123), @io.string + end + end end