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