]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/logger.rb
fix: restore logging of session start/end
[user/henk/code/ruby/rbot.git] / lib / rbot / logger.rb
1 # encoding: UTF-8
2 #-- vim:sw=2:et
3 #++
4 #
5 # :title: rbot logger
6
7 require 'logger'
8 require 'thread'
9 require 'singleton'
10
11 module Irc
12 class Bot
13
14   class LoggerManager
15     include Singleton
16
17     def enable_console_logger
18       @console_logger = Logger.new(STDERR)
19       @console_logger.datetime_format = @dateformat
20       @console_logger.level = Logger::Severity::DEBUG
21     end
22
23     def disable_console_logger
24       @console_logger.close if @console_logger
25       @console_logger = nil
26     end
27
28     def initialize
29       @dateformat = "%Y/%m/%d %H:%M:%S"
30
31       enable_console_logger
32
33       @file_logger = nil
34
35       @queue = Queue.new
36       start_thread
37     end
38
39     def set_logfile(filename, keep, max_size)
40       # close previous file logger if present
41       @file_logger.close if @file_logger
42
43       @file_logger = Logger.new(filename, keep, max_size*1024*1024)
44       @file_logger.datetime_format = @dateformat
45       @file_logger.level = @console_logger.level
46
47       # make sure the thread is running, which might be false after a fork
48       # (conveniently, we call set_logfile right after the fork)
49       start_thread
50     end
51
52     def set_level(level)
53       @console_logger.level = level if @console_logger
54       @file_logger.level = level if @file_logger
55     end
56
57     def sync_log(severity, message = nil, progname = nil)
58       @console_logger.add(severity, message, progname) if @console_logger
59       @file_logger.add(severity, message, progname) if @file_logger
60     end
61
62     def async_log(severity, message=nil, who_pos=1)
63       unless @thread
64         STDERR.puts('logger thread already destroyed, cannot log message!')
65       end
66
67       call_stack = caller
68       if call_stack.length > who_pos
69         who = call_stack[who_pos].sub(%r{(?:.+)/([^/]+):(\d+)(:in .*)?}) { "#{$1}:#{$2}#{$3}" }
70       else
71         who = "(unknown)"
72       end
73       # Output each line. To distinguish between separate messages and multi-line
74       # messages originating at the same time, we blank #{who} after the first message
75       # is output.
76       # Also, we output strings as-is but for other objects we use pretty_inspect
77       message = message.kind_of?(String) ? message : (message.pretty_inspect rescue '?')
78       qmsg = Array.new
79       message.each_line { |l|
80         qmsg.push [severity, l.chomp, who]
81         who = ' ' * who.size
82       }
83       @queue.push qmsg
84     end
85
86     def log_session_start
87       if @file_logger
88         @file_logger << "\n\n=== session started on #{Time.now.strftime(@dateformat)} ===\n\n"
89       end
90     end
91
92     def log_session_end
93       if @file_logger
94         @file_logger << "\n\n=== session ended on #{Time.now.strftime(@dateformat)} ===\n\n"
95       end
96     end
97
98     def halt_logger
99       if @thread and @thread.alive?
100         @queue << nil
101         @thread.join
102         @thread = nil
103         log_session_end
104       end
105     end
106
107     def flush
108       while @queue.size > 0
109         next
110       end
111     end
112
113     private
114
115     def start_thread
116       return if @thread and @thread.alive?
117       @thread = Thread.new do
118         lines = nil
119         while lines = @queue.pop
120           lines.each { |line|
121             sync_log(*line)
122           }
123         end
124       end
125     end
126
127   end
128
129 end
130 end
131
132 def debug(message=nil, who_pos=1)
133   Irc::Bot::LoggerManager.instance.async_log(Logger::Severity::DEBUG, message, who_pos)
134 end
135
136 def log(message=nil, who_pos=1)
137   Irc::Bot::LoggerManager.instance.async_log(Logger::Severity::INFO, message, who_pos)
138 end
139
140 def warning(message=nil, who_pos=1)
141   Irc::Bot::LoggerManager.instance.async_log(Logger::Severity::WARN, message, who_pos)
142 end
143
144 def error(message=nil, who_pos=1)
145   Irc::Bot::LoggerManager.instance.async_log(Logger::Severity::ERROR, message, who_pos)
146 end
147
148 def fatal(message=nil, who_pos=1)
149   Irc::Bot::LoggerManager.instance.async_log(Logger::Severity::FATAL, message, who_pos)
150 end