7 ## simple centralized logger. outputs to multiple sinks by calling << on them.
8 ## also keeps a record of all messages, so that adding a new sink will send all
9 ## previous messages to it by default.
13 LEVELS = %w(debug info warn error) # in order!
15 def initialize level=nil
16 level ||= ENV["SUP_LOG_LEVEL"] || "info"
17 @level = LEVELS.index(level) or raise ArgumentError, "invalid log level #{level.inspect}: should be one of #{LEVELS * ', '}"
23 def level; LEVELS[@level] end
25 def add_sink s, copy_current=true
28 s << @buf.string if copy_current
32 def remove_sink s; @mutex.synchronize { @sinks.delete s } end
33 def remove_all_sinks!; @mutex.synchronize { @sinks.clear } end
34 def clear!; @mutex.synchronize { @buf = StringIO.new } end
36 LEVELS.each_with_index do |l, method_level|
37 define_method(l) do |s|
38 if method_level >= @level
39 send_message format_message(l, Time.now, s)
44 ## send a message regardless of the current logging level
45 def force_message m; send_message format_message(nil, Time.now, m) end
50 def format_message level, time, msg
52 when "warn"; "WARNING: "
53 when "error"; "ERROR: "
56 "[#{time.to_s}] #{prefix}#{msg}\n"
59 ## actually distribute the message
62 @sinks.each { |sink| sink << m }
68 ## include me to have top-level #debug, #info, etc. methods.
70 Logger::LEVELS.each { |l| define_method(l) { |s| Logger.instance.send(l, s) } }