Skip to main content

module_prepend_for_instrumentation

🔍 Instrumentation via Module#prepend

Use Module#prepend to inject behavior before or after target methods without altering the original class. This approach ensures your instrumentation runs in the proper ancestor chain and can call super to delegate to the original implementation.

module MethodProfiler
def self.prepended(base)
base.instance_methods(false).each { |m| wrap_method(base, m) }
end

def self.wrap_method(base, method)
base.define_method(method) do |*args, &blk|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
result = super(*args, &blk)
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
puts "#{method} took #{duration.round(4)}s"
result
end
end
end

class DataFetcher
def fetch; sleep(0.1); 'data'; end
prepend MethodProfiler
end

DataFetcher.new.fetch # Outputs: "fetch took 0.1001s"