From 81343e8282e8fc06d2a0df8afa23376923b59f72 Mon Sep 17 00:00:00 2001 From: Nick Carboni Date: Tue, 19 Dec 2017 17:20:33 -0500 Subject: [PATCH] Make ContainerLogger respond to #instrument In a container, the instance of ContainerLogger is sent every message recieved by the other logger instances In the case of FogLogger we have had to add additional messages to deal with the Econ gem's requirements around logging requests. This failure manifests itself as a failure to validate credentials on providers which use Fog when running in a container. Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1527546 --- lib/vmdb/loggers.rb | 65 ++++++++++++++++++++++++++++ lib/vmdb/loggers/container_logger.rb | 2 + lib/vmdb/loggers/fog_logger.rb | 63 +-------------------------- 3 files changed, 68 insertions(+), 62 deletions(-) diff --git a/lib/vmdb/loggers.rb b/lib/vmdb/loggers.rb index 0658c52e644..4d540d922ea 100644 --- a/lib/vmdb/loggers.rb +++ b/lib/vmdb/loggers.rb @@ -11,6 +11,71 @@ def self.rails_logger end module Loggers + module Instrument + # To be used as Excon's request logger, the logger must respond to + # #instrument as in ActiveSupport::Notifications. + # Implementation derived from Excon::StandardInstrumentor + def instrument(name, params = {}) + method, message = + case name + when "excon.request" then [:debug, message_for_excon_request(params)] + when "excon.response" then [:debug, message_for_excon_response(params)] + when "excon.error" then [:debug, message_for_excon_error(params)] + else [:debug, message_for_other(params)] + end + + send(method, "#{name.ljust(14)} #{message}") + yield if block_given? + end + + private + + def message_for_excon_request(params) + uri_parts = params.values_at(:scheme, nil, :host, :port, nil, :path, nil, nil, nil) + uri_parts[3] = uri_parts[3].to_i if uri_parts[3] # port + uri = {:uri => URI::Generic.build(uri_parts).to_s} + log_params(uri.merge!(params.slice(:query, :method, :headers, :body).delete_nils)) + end + + def message_for_excon_response(params) + log_params(params.slice(:status, :headers, :body)) + end + + def message_for_excon_error(params) + params[:error].pretty_inspect + end + + def message_for_other(params) + log_params(params.except(:instrumentor, :instrumentor_name, :connection, :stack, :middlewares)) + end + + def log_params(params) + sanitized = sanitize_params(params) + sanitized[:body] = parse_body(sanitized[:body]) + "\n#{sanitized.pretty_inspect}" + end + + def parse_body(body) + JSON.parse(body) if body + rescue JSON::ParserError + body + end + + def sanitize_params(params) + if params.key?(:headers) && params[:headers].key?('Authorization') + params[:headers] = params[:headers].dup + params[:headers]['Authorization'] = "********" + end + if params.key?(:password) + params[:password] = "********" + end + if params.key?(:body) + params[:body] = params[:body].to_s.gsub(/"password":".+?"\}/, '"password":"********"}') + end + params + end + end + def self.init return if @initialized create_loggers diff --git a/lib/vmdb/loggers/container_logger.rb b/lib/vmdb/loggers/container_logger.rb index f86c43af0bf..a70160ef4e2 100644 --- a/lib/vmdb/loggers/container_logger.rb +++ b/lib/vmdb/loggers/container_logger.rb @@ -1,5 +1,7 @@ module Vmdb::Loggers class ContainerLogger < VMDBLogger + include Instrument + def initialize(logdev = STDOUT, *args) super self.level = DEBUG diff --git a/lib/vmdb/loggers/fog_logger.rb b/lib/vmdb/loggers/fog_logger.rb index cfdde898988..2bc59b323e7 100644 --- a/lib/vmdb/loggers/fog_logger.rb +++ b/lib/vmdb/loggers/fog_logger.rb @@ -1,66 +1,5 @@ module Vmdb::Loggers class FogLogger < VMDBLogger - # To be used as Excon's request logger, the logger must respond to - # #instrument as in ActiveSupport::Notifications. - # Implementation derived from Excon::StandardInstrumentor - def instrument(name, params = {}) - method, message = - case name - when "excon.request" then [:debug, message_for_excon_request(params)] - when "excon.response" then [:debug, message_for_excon_response(params)] - when "excon.error" then [:debug, message_for_excon_error(params)] - else [:debug, message_for_other(params)] - end - - send(method, "#{name.ljust(14)} #{message}") - yield if block_given? - end - - private - - def message_for_excon_request(params) - uri_parts = params.values_at(:scheme, nil, :host, :port, nil, :path, nil, nil, nil) - uri_parts[3] = uri_parts[3].to_i if uri_parts[3] # port - uri = {:uri => URI::Generic.build(uri_parts).to_s} - log_params(uri.merge!(params.slice(:query, :method, :headers, :body).delete_nils)) - end - - def message_for_excon_response(params) - log_params(params.slice(:status, :headers, :body)) - end - - def message_for_excon_error(params) - params[:error].pretty_inspect - end - - def message_for_other(params) - log_params(params.except(:instrumentor, :instrumentor_name, :connection, :stack, :middlewares)) - end - - def log_params(params) - sanitized = sanitize_params(params) - sanitized[:body] = parse_body(sanitized[:body]) - "\n#{sanitized.pretty_inspect}" - end - - def parse_body(body) - JSON.parse(body) if body - rescue JSON::ParserError - body - end - - def sanitize_params(params) - if params.key?(:headers) && params[:headers].key?('Authorization') - params[:headers] = params[:headers].dup - params[:headers]['Authorization'] = "********" - end - if params.key?(:password) - params[:password] = "********" - end - if params.key?(:body) - params[:body] = params[:body].to_s.gsub(/"password":".+?"\}/, '"password":"********"}') - end - params - end + include Instrument end end