]> git.cworth.org Git - sup/blob - lib/sup/logger.rb
Merge branch 'buffer-rolling'
[sup] / lib / sup / logger.rb
1 require "sup"
2 require 'stringio'
3 require 'thread'
4
5 module Redwood
6
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.
10 class Logger
11   include Singleton
12
13   LEVELS = %w(debug info warn error) # in order!
14
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 * ', '}"
18     @mutex = Mutex.new
19     @buf = StringIO.new
20     @sinks = []
21   end
22
23   def level; LEVELS[@level] end
24
25   def add_sink s, copy_current=true
26     @mutex.synchronize do
27       @sinks << s
28       s << @buf.string if copy_current
29     end
30   end
31
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
35
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)
40       end
41     end
42   end
43
44   ## send a message regardless of the current logging level
45   def force_message m; send_message format_message(nil, Time.now, m) end
46
47 private
48
49   ## level can be nil!
50   def format_message level, time, msg
51     prefix = case level
52       when "warn"; "WARNING: "
53       when "error"; "ERROR: "
54       else ""
55     end
56     "[#{time.to_s}] #{prefix}#{msg}\n"
57   end
58
59   ## actually distribute the message
60   def send_message m
61     @mutex.synchronize do
62       @sinks.each { |sink| sink << m }
63       @buf << m
64     end
65   end
66 end
67
68 ## include me to have top-level #debug, #info, etc. methods.
69 module LogsStuff
70   Logger::LEVELS.each { |l| define_method(l) { |s| Logger.instance.send(l, s) } }
71 end
72
73 end