lib/hanami/logger.rb in hanami-utils-1.0.4 vs lib/hanami/logger.rb in hanami-utils-1.1.0.beta1

- old
+ new

@@ -1,10 +1,11 @@ require 'set' require 'json' require 'logger' require 'hanami/utils/string' require 'hanami/utils/json' +require 'hanami/utils/hash' require 'hanami/utils/class_attribute' module Hanami # Hanami logger # @@ -115,19 +116,17 @@ include Utils::ClassAttribute class_attribute :subclasses self.subclasses = Set.new - def self.fabricate(formatter, application_name) - case formatter - when Symbol - (subclasses.find { |s| s.eligible?(formatter) } || self).new - when nil - new - else - formatter - end.tap { |f| f.application_name = application_name } + def self.fabricate(formatter, application_name, filters) + fabricated_formatter = _formatter_instance(formatter) + + fabricated_formatter.application_name = application_name + fabricated_formatter.hash_filter = HashFilter.new(filters) + + fabricated_formatter end # @api private def self.inherited(subclass) super @@ -137,18 +136,36 @@ # @api private def self.eligible?(name) name == :default end + # @api private + # @since 1.1.0 + def self._formatter_instance(formatter) + case formatter + when Symbol + (subclasses.find { |s| s.eligible?(formatter) } || self).new + when nil + new + else + formatter + end + end + private_class_method :_formatter_instance + # @since 0.5.0 # @api private attr_writer :application_name # @since 1.0.0 # @api private attr_reader :application_name + # @since 1.1.0 + # @api private + attr_writer :hash_filter + # @since 0.5.0 # @api private # # @see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger/Formatter.html#method-i-call def call(severity, time, _progname, msg) @@ -166,11 +183,11 @@ # @since 0.8.0 # @api private def _message_hash(message) # rubocop:disable Metrics/MethodLength case message when Hash - message + @hash_filter.filter(message) when Exception Hash[ message: message.message, backtrace: message.backtrace || [], error: message.class @@ -204,10 +221,71 @@ end end result end + + # Filtering logic + # + # @since 1.1.0 + # @api private + class HashFilter + # @since 1.1.0 + # @api private + attr_reader :filters + + # @since 1.1.0 + # @api private + def initialize(filters = []) + @filters = filters + end + + # @since 1.1.0 + # @api private + def filter(hash) + _filtered_keys(hash).each do |key| + *keys, last = _actual_keys(hash, key.split('.')) + keys.inject(hash, :fetch)[last] = '[FILTERED]' + end + + hash + end + + private + + # @since 1.1.0 + # @api private + def _filtered_keys(hash) + _key_paths(hash).select { |key| filters.any? { |filter| key =~ %r{(\.|\A)#{filter}(\.|\z)} } } + end + + # @since 1.1.0 + # @api private + def _key_paths(hash, base = nil) + hash.inject([]) do |results, (k, v)| + results + (v.respond_to?(:each) ? _key_paths(v, _build_path(base, k)) : [_build_path(base, k)]) + end + end + + # @since 1.1.0 + # @api private + def _build_path(base, key) + [base, key.to_s].compact.join('.') + end + + # @since 1.1.0 + # @api private + def _actual_keys(hash, keys) + search_in = hash + + keys.inject([]) do |res, key| + correct_key = search_in.key?(key.to_sym) ? key.to_sym : key + search_in = search_in[correct_key] + res + [correct_key] + end + end + end end # Hanami::Logger JSON formatter. # This formatter returns string in JSON format. # @@ -373,16 +451,16 @@ # # logger = Hanami::Logger.new(formatter: :json) # logger.info "Hello World" # # # => {"app":"Hanami","severity":"DEBUG","time":"2017-03-30T13:57:59Z","message":"Hello World"} - def initialize(application_name = nil, *args, stream: $stdout, level: DEBUG, formatter: nil) + def initialize(application_name = nil, *args, stream: $stdout, level: DEBUG, formatter: nil, filter: []) # rubocop:disable Metrics/ParameterLists super(stream, *args) @level = _level(level) @stream = stream @application_name = application_name - @formatter = Formatter.fabricate(formatter, self.application_name) + @formatter = Formatter.fabricate(formatter, self.application_name, filter) end # Returns the current application name, this is used for tagging purposes # # @return [String] the application name