add --no-syslog
[god.git] / lib / god / logger.rb
blobd7735785c6793f504768f33e714d1d66f08e8a7e
1 module God
2   
3   class Logger < ::Logger
4     SYSLOG_EQUIVALENTS = {:fatal => :crit,
5                           :error => :err,
6                           :warn => :debug,
7                           :info => :debug,
8                           :debug => :debug}
9     
10     attr_accessor :logs
11     
12     class << self
13       attr_accessor :syslog
14     end
15     
16     self.syslog ||= true
17     
18     # Instantiate a new Logger object
19     def initialize
20       super($stdout)
21       self.logs = {}
22       @mutex = Mutex.new
23       @capture = nil
24       load_syslog
25     end
26     
27     # If Logger.syslog is true then attempt to load the syslog bindings. If syslog
28     # cannot be loaded, then set Logger.syslog to false and continue.
29     #
30     # Returns nothing
31     def load_syslog
32       return unless Logger.syslog
33       
34       begin
35         require 'syslog'
36         
37         # Ensure that Syslog is open
38         begin
39           Syslog.open('god')
40         rescue RuntimeError
41           Syslog.reopen('god')
42         end
43       rescue Exception
44         Logger.syslog = false
45       end
46     end
47     
48     # Log a message
49     #   +watch+ is the String name of the Watch (may be nil if not Watch is applicable)
50     #   +level+ is the log level [:debug|:info|:warn|:error|:fatal]
51     #   +text+ is the String message
52     #
53     # Returns nothing
54     def log(watch, level, text)
55       # initialize watch log if necessary
56       self.logs[watch.name] ||= Timeline.new(God::LOG_BUFFER_SIZE_DEFAULT) if watch
57       
58       # push onto capture and timeline for the given watch
59       buf = StringIO.new
60       templog = ::Logger.new(buf)
61       templog.level = Logger::INFO
62       templog.send(level, text % [])
63       @mutex.synchronize do
64         @capture.puts(buf.string) if @capture
65         self.logs[watch.name] << [Time.now, buf.string] if watch
66       end
67       templog.close
68       
69       # send to regular logger
70       self.send(level, text % [])
71       
72       # send to syslog
73       Syslog.send(SYSLOG_EQUIVALENTS[level], text) if Logger.syslog
74     end
75     
76     # Get all log output for a given Watch since a certain Time.
77     #   +watch_name+ is the String name of the Watch
78     #   +since+ is the Time since which to fetch log lines
79     #
80     # Returns String
81     def watch_log_since(watch_name, since)
82       # initialize watch log if necessary
83       self.logs[watch_name] ||= Timeline.new(God::LOG_BUFFER_SIZE_DEFAULT)
84       
85       # get and join lines since given time
86       @mutex.synchronize do
87         self.logs[watch_name].select do |x|
88           x.first > since
89         end.map do |x|
90           x[1]
91         end.join
92       end
93     end
94     
95     # private
96     
97     # Enable capturing of log
98     #
99     # Returns nothing
100     def start_capture
101       @mutex.synchronize do
102         @capture = StringIO.new
103       end
104     end
105     
106     # Disable capturing of log and return what was captured since
107     # capturing was enabled with Logger#start_capture
108     #
109     # Returns String
110     def finish_capture
111       @mutex.synchronize do
112         cap = @capture.string
113         @capture = nil
114         cap
115       end
116     end
117   end
118