lib/tailog/watch_methods.rb in tailog-0.3.7 vs lib/tailog/watch_methods.rb in tailog-0.4.0

- old
+ new

@@ -1,112 +1,118 @@ require 'active_support/core_ext/string' -require 'active_support/configurable' require 'securerandom' require 'logger' module Tailog module WatchMethods - include ActiveSupport::Configurable - class << self - attr_accessor :request_id - def logger return @logger if @logger @logger = Logger.new(File.join Tailog.log_path, "watch_methods.log") @logger.formatter = proc do |severity, datetime, progname, message| content = "" content << "[#{datetime.strftime("%Y-%m-%d %H:%M:%S")}]" - content << "[#{Tailog::WatchMethods.request_id}]" if Tailog::WatchMethods.request_id + content << "[#{Tailog.request_id}]" if Tailog.request_id content << " #{severity.rjust(5)}" content << " (#{progname})" if progname content << ": #{message.gsub(/\n\s*/, " ")}" content << "\n" content end @logger end end - class RequestId - def initialize(app) - @app = app - end - - def call(env) - Tailog::WatchMethods.request_id = external_request_id(env) || internal_request_id - @app.call(env).tap do |_status, headers, _body| - headers["X-Request-Id"] = Tailog::WatchMethods.request_id - end - end - - private - - def external_request_id(env) - if request_id = env["HTTP_X_REQUEST_ID"].presence - request_id.gsub(/[^\w\-]/, "").first(255) - end - end - - def internal_request_id - SecureRandom.uuid - end - end - - def inject_constants targets + def inject targets targets.each do |target| begin - target.constantize.instance_methods(false).each do |method| - inject_instance_method "#{target}##{method}" + if target.include? "#" + inject_instance_method target + elsif target.include? "." + inject_class_method target + else + inject_constant target end - target.constantize.methods(false).each do |method| - inject_class_method "#{target}.#{method}" - end rescue => error - WatchMethods.logger.error "Inject constant `#{target}' failed: #{error.class}: #{error.message}" + WatchMethods.logger.error "Inject #{target} FAILED: #{error.class}: #{error.message}" end end end - def inject_methods targets + def cleanup targets targets.each do |target| - begin - if target.include? "#" - inject_instance_method target - else - inject_class_method target - end - rescue => error - WatchMethods.logger.error "Inject method `#{target}' failed: #{error.class}: #{error.message}" + if target.include? "#" + cleanup_instance_method target + elsif target.include? "." + cleanup_class_method target + else + cleanup_constant target end end end private + RAW_METHOD_PREFIX = "watch_method_raw_" + + def raw_method? method + method.to_s.start_with? RAW_METHOD_PREFIX + end + + def inject_constant target + constant = target.constantize + constant.instance_methods(false).each do |method| + inject_instance_method "#{target}##{method}" unless raw_method? method + end + constant.methods(false).each do |method| + inject_class_method "#{target}.#{method}" unless raw_method? method + end + end + + def cleanup_constant target + target.constantize.instance_methods(false).each do |method| + cleanup_instance_method "#{target}##{method}" unless raw_method? method + end + target.constantize.methods(false).each do |method| + cleanup_class_method "#{target}.#{method}" unless raw_method? method + end + end + def inject_class_method target - klass, _, method = if target.include? "." - target.rpartition(".") - else - target.rpartition("::") - end + klass, _, method = target.rpartition(".") klass.constantize.class_eval <<-EOS, __FILE__, __LINE__ class << self #{build_watch_method target, method} end EOS end + def cleanup_class_method target + klass, _, method = target.rpartition(".") + klass.constantize.class_eval <<-EOS, __FILE__, __LINE__ + class << self + #{build_cleanup_method target, method} + end + EOS + end + def inject_instance_method target klass, _, method = target.rpartition("#") klass.constantize.class_eval <<-EOS, __FILE__, __LINE__ #{build_watch_method target, method} EOS end + def cleanup_instance_method target + klass, _, method = target.rpartition("#") + klass.constantize.class_eval <<-EOS, __FILE__, __LINE__ + #{build_cleanup_method target, method} + EOS + end + def build_watch_method target, method - raw_method = "watch_method_raw_#{method}" + raw_method = "#{RAW_METHOD_PREFIX}#{method}" return <<-EOS unless instance_methods.include?(:#{raw_method}) alias_method :#{raw_method}, :#{method} def #{method} *args start = Time.now @@ -119,9 +125,19 @@ Tailog::WatchMethods.logger.error "[\#{call_id}] #{target} FAILED: \#{error.class} - \#{error.message} => \#{error.backtrace.join(", ")}" raise error end else Tailog::WatchMethods.logger.error "Inject method `#{target}' failed: already injected" + end + EOS + end + + def build_cleanup_method target, method + raw_method = "#{RAW_METHOD_PREFIX}#{method}" + return <<-EOS + if method_defined? :#{raw_method} + alias_method :#{method}, :#{raw_method} + remove_method :#{raw_method} end EOS end end end