logging - Ruby: Proxy pattern, reducing method calls -
how proxy ruby logger , keep performance?
so, have requirement @ work, quite reasonable. when program sent signal hup log flushed , restarted.
class localobject attr_accessor :logger def initialize context # 1 less method call! yea! performance++ @logger = context.logger end def @logger.info "hello world" end end
the problem, if context.logger reset, @logger still points old one.
so, thought proxy logger:
class loggerproxy attr_accessor :logger def debug *args @logger.send :debug, args end def info *args @logger.send :info, args end end context.logger = loggerproxy.new context.logger.logger = logger.new 'my_file.log' signal.trap('hup') { context.logger.logger = logger.new 'my_file.log' } ... @logger = context.logger @logger.info "hello world"
this works fine, except i've traded 1 method call 2 method calls (1 accessor; returns logger). still have call loggerproxy.:debug, :info, ..., in turn calls original logger! ergo, 2 methods calls, there one.
i don't want monkey logger class, or overload it, because want use other loggers in future, syslog, roll own, or such.
is there way reduce number of method calls performance?
-daniel
update: in response question performance, here sample test.
require 'logger' require 'benchmark'; class mylogger attr_accessor :logger def info msg @logger.info msg end end mylogger = logger.new '/dev/null' # dev null avoid io issues myloggerproxy = mylogger.new myloggerproxy.logger = mylogger n = 100000 benchmark.bm | benchmarker | # plain logger benchmarker.report { n.times { mylogger.info 'opps' } } # via accessor benchmarker.report { n.times { myloggerproxy.logger.info 'opps' } } # via proxy benchmarker.report { n.times { myloggerproxy.info 'opps' } } end user system total real 1.580000 0.150000 1.730000 ( 1.734956) 1.600000 0.150000 1.750000 ( 1.747969) 1.610000 0.160000 1.770000 ( 1.767886)
first: question smells you're optimizing prematurely. should optimize if know code slow. (and benchmark show tiny difference)
that said, make context notify every proxy if logger ever updated:
class proxylogger attr_accessor :logger def initialize(context) context.register(self) end end class context attr_accessor :logger def initialize @proxies = [] end def logger=(val) @logger = val @proxies.each { |p| p.logger = val } end def register(proxy) @proxies << proxy end end
but again, not seem worth additional complexity.
(related: this nice presentation showing @tenderlove optimizing arel gem)
Comments
Post a Comment