Skip to content

Instantly share code, notes, and snippets.

@fj
Created May 24, 2010 19:49
Show Gist options
  • Save fj/412342 to your computer and use it in GitHub Desktop.
Save fj/412342 to your computer and use it in GitHub Desktop.
=begin
I'm writing a small framework to help me with building some things,
and I'd like to give every class in the framework opt-in access to
logging. First I do that by defining a Log class which uses Singleton
to ensure that there's only one instance of a Log for the whole
application:
=end
require 'log4r'
module Constructify
class Log
include Singleton
include Log4r
def initialize
Logger['global'].level = DEBUG
fmt = PatternFormatter.new(:pattern => "%d [%5l] (%c) %M",
:date_pattern => "%y-%m-%d %H:%M:%S")
StderrOutputter.new('stderr', :level => Log4r::INFO, :formatter => fmt)
end
def log_init(name, level, target)
Logger.new(name, Log4r.const_get(level)).outputters = target
Logger[name]
end
end
end
=begin
Next, I add a has_logging method to every class:
=end
class Module
def has_logging(level='DEBUG', target=['stderr'])
class_eval {
@log = Constructify::Log.instance.log_init(self.name,
"#{level}", target.dup)
def log
self.class.instance_variable_get :@log
end
}
end
end
=begin
Now, one should be able to add logging to a particular class like this:
=end
class Foo
has_logging
end
=begin
But instead, I get this:
/home/johnf/dev/constructify/lib/constructify/logging.rb:31:in
`class_eval': deadlock; recursive locking (ThreadError)
from <internal:prelude>:6:in `synchronize'
from <internal:prelude>:20:in `exclusive'
from /home/johnf/.rvm/gems/ruby-1.9.1-p378@standard/gems/log4r-1.1.7/src/log4r/repository.rb:34:in
`[]'
from /home/johnf/.rvm/gems/ruby-1.9.1-p378@standard/gems/log4r-1.1.7/src/log4r/repository.rb:75:in
`block in find_ancestor'
from <internal:prelude>:21:in `block in exclusive'
from <internal:prelude>:8:in `synchronize'
from <internal:prelude>:20:in `exclusive'
from /home/johnf/.rvm/gems/ruby-1.9.1-p378@standard/gems/log4r-1.1.7/src/log4r/repository.rb:73:in
`find_ancestor'
from /home/johnf/.rvm/gems/ruby-1.9.1-p378@standard/gems/log4r-1.1.7/src/log4r/logger.rb:62:in
`deal_with_inheritance'
from /home/johnf/.rvm/gems/ruby-1.9.1-p378@standard/gems/log4r-1.1.7/src/log4r/logger.rb:36:in
`initialize'
from /home/johnf/dev/constructify/lib/constructify/logging.rb:17:in `new'
from /home/johnf/dev/constructify/lib/constructify/logging.rb:17:in `log_init'
from (eval):2:in `logger'
from /home/johnf/dev/constructify/lib/constructify/logging.rb:31:in
`class_eval'
=end
=begin
I have temporarily worked around the problem by defining a MockLog class instead:
=end
module Constructify
class MockLog
def self.log_stub_method(*args)
args.each do |a|
define_method "#{a}" do |msg|
t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
$stderr.puts "[#{a.upcase}] \u00bb [#{t}] #{msg}"
end
end
end
log_stub_method :fatal, :error, :warn, :info, :debug
end
end
class Module
def has_logging(level='DEBUG', target=['stderr'])
class_eval {
# @log = Constructify::Log.instance.log_init(self.name, "#{level}", target.dup)
@log = Constructify::MockLog.new # Use MockLog instead of Log4r.
def log
self.class.instance_variable_get :@log
end
}
end
end
=begin
Commenting out the Log4r instantiation, not surprisingly, fixes the issue.
=end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment