Class | IrcLogModule |
In: |
lib/rbot/core/irclog.rb
|
Parent: | CoreBotModule |
Author: | Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com> |
nolog_rx | [RW] |
# File lib/rbot/core/irclog.rb, line 31 31: def initialize 32: super 33: @queue = Queue.new 34: @thread = Thread.new { loggers_thread } 35: @logs = Hash.new 36: logdir = @bot.path 'logs' 37: Dir.mkdir(logdir) unless File.exist?(logdir) 38: # TODO what shall we do if the logdir couldn't be created? (e.g. it existed as a file) 39: event_irclog_list_changed(@bot.config['irclog.no_log'], @bot.config['irclog.do_log']) 40: @fn_format = @bot.config['irclog.filename_format'] 41: end
# File lib/rbot/core/irclog.rb, line 43 43: def can_log_on(where) 44: return true if @dolog_rx and where.match @dolog_rx 45: return false if @nolog_rx and where.match @nolog_rx 46: return true 47: end
# File lib/rbot/core/irclog.rb, line 77 77: def cleanup 78: @queue << nil 79: @thread.join 80: @thread = nil 81: end
# File lib/rbot/core/irclog.rb, line 53 53: def event_irclog_list_changed(nolist, dolist) 54: @nolog_rx = nolist.empty? ? nil : Regexp.union(*(nolist.map { |r| r.to_irc_regexp })) 55: debug "no log: #{@nolog_rx}" 56: @dolog_rx = dolist.empty? ? nil : Regexp.union(*(dolist.map { |r| r.to_irc_regexp })) 57: debug "do log: #{@dolog_rx}" 58: @logs.inject([]) { |ar, kv| 59: ar << kv.first unless can_log_on(kv.first) 60: ar 61: }.each { |w| logfile_close(w, 'logging disabled here') } 62: end
log IRC-related message message to a file determined by where. where can be a channel name, or a nick for private message logging
# File lib/rbot/core/irclog.rb, line 73 73: def irclog(message, where="server") 74: @queue.push [message, where] 75: end
# File lib/rbot/core/irclog.rb, line 118 118: def listen(m) 119: case m 120: when PrivMessage 121: method = 'log_message' 122: else 123: method = 'log_' + m.class.name.downcase.match(/^irc::(\w+)message$/).captures.first 124: end 125: if self.respond_to?(method) 126: self.__send__(method, m) 127: else 128: warning "unhandled logging for #{m.pretty_inspect} (no such method #{method})" 129: unknown_message(m) 130: end 131: end
# File lib/rbot/core/irclog.rb, line 194 194: def log_join(m) 195: if m.address? 196: debug "joined channel #{m.channel}" 197: irclog "@ Joined channel #{m.channel}", m.channel 198: else 199: irclog "@ #{m.source} joined channel #{m.channel}", m.channel 200: end 201: end
# File lib/rbot/core/irclog.rb, line 212 212: def log_kick(m) 213: if(m.address?) 214: debug "kicked from channel #{m.channel}" 215: irclog "@ You have been kicked from #{m.channel} by #{m.source} (#{m.logmessage})", m.channel 216: else 217: irclog "@ #{m.target} has been kicked from #{m.channel} by #{m.source} (#{m.logmessage})", m.channel 218: end 219: end
# File lib/rbot/core/irclog.rb, line 133 133: def log_message(m) 134: if m.ctcp 135: who = m.private? ? "me" : m.target 136: logtarget = m.private? ? m.source : m.target 137: case m.ctcp.intern 138: when :ACTION 139: if m.public? 140: irclog "* #{m.source} #{m.logmessage}", m.target 141: else 142: irclog "* #{m.source}(#{m.sourceaddress}) #{m.logmessage}", m.source 143: end 144: when :VERSION 145: irclog "@ #{m.source} asked #{who} about version info", logtarget 146: when :SOURCE 147: irclog "@ #{m.source} asked #{who} about source info", logtarget 148: when :PING 149: irclog "@ #{m.source} pinged #{who}", logtarget 150: when :TIME 151: irclog "@ #{m.source} asked #{who} what time it is", logtarget 152: else 153: irclog "@ #{m.source} asked #{who} about #{[m.ctcp, m.message].join(' ')}", logtarget 154: end 155: else 156: if m.public? 157: irclog "<#{m.source}> #{m.logmessage}", m.target 158: else 159: irclog "<#{m.source}(#{m.sourceaddress})> #{m.logmessage}", m.source 160: end 161: end 162: end
# File lib/rbot/core/irclog.rb, line 178 178: def log_nick(m) 179: (m.is_on & @bot.myself.channels).each { |ch| 180: irclog "@ #{m.oldnick} is now known as #{m.newnick}", ch 181: } 182: end
# File lib/rbot/core/irclog.rb, line 164 164: def log_notice(m) 165: if m.private? 166: irclog "-#{m.source}(#{m.sourceaddress})- #{m.logmessage}", m.source 167: else 168: irclog "-#{m.source}- #{m.logmessage}", m.target 169: end 170: end
# File lib/rbot/core/irclog.rb, line 203 203: def log_part(m) 204: if(m.address?) 205: debug "left channel #{m.channel}" 206: irclog "@ Left channel #{m.channel} (#{m.logmessage})", m.channel 207: else 208: irclog "@ #{m.source} left channel #{m.channel} (#{m.logmessage})", m.channel 209: end 210: end
# File lib/rbot/core/irclog.rb, line 184 184: def log_quit(m) 185: (m.was_on & @bot.myself.channels).each { |ch| 186: irclog "@ Quit: #{m.source}: #{m.logmessage}", ch 187: } 188: end
def log_invite(m)
# TODO
end
# File lib/rbot/core/irclog.rb, line 225 225: def log_topic(m) 226: case m.info_or_set 227: when :set 228: if m.source == @bot.myself 229: irclog "@ I set topic \"#{m.topic}\"", m.channel 230: else 231: irclog "@ #{m.source} set topic \"#{m.topic}\"", m.channel 232: end 233: when :info 234: topic = m.channel.topic 235: irclog "@ Topic is \"#{m.topic}\"", m.channel 236: irclog "@ Topic set by #{topic.set_by} on #{topic.set_on}", m.channel 237: end 238: end
# File lib/rbot/core/irclog.rb, line 64 64: def logfile_close(where_str, reason = 'unknown reason') 65: f = @logs.delete(where_str) or return 66: stamp = timestamp(Time.now) 67: f[1].puts "#{stamp} @ Log closed by #{@bot.myself.nick} (#{reason})" 68: f[1].close 69: end
# File lib/rbot/core/irclog.rb, line 248 248: def logfilepath(where_str, now) 249: @bot.path('logs', now.strftime(@fn_format) % { :where => where_str }) 250: end
# File lib/rbot/core/irclog.rb, line 190 190: def modechange(m) 191: irclog "@ Mode #{m.logmessage} by #{m.source}", m.target 192: end
# File lib/rbot/core/irclog.rb, line 172 172: def motd(m) 173: m.message.each_line { |line| 174: irclog "MOTD: #{line}", "server" 175: } 176: end
# File lib/rbot/core/irclog.rb, line 83 83: def sent(m) 84: case m 85: when NoticeMessage 86: irclog "-#{m.source}- #{m.message}", m.target 87: when PrivMessage 88: logtarget = who = m.target 89: if m.ctcp 90: case m.ctcp.intern 91: when :ACTION 92: irclog "* #{m.source} #{m.logmessage}", logtarget 93: when :VERSION 94: irclog "@ #{m.source} asked #{who} about version info", logtarget 95: when :SOURCE 96: irclog "@ #{m.source} asked #{who} about source info", logtarget 97: when :PING 98: irclog "@ #{m.source} pinged #{who}", logtarget 99: when :TIME 100: irclog "@ #{m.source} asked #{who} what time it is", logtarget 101: else 102: irclog "@ #{m.source} asked #{who} about #{[m.ctcp, m.message].join(' ')}", logtarget 103: end 104: else 105: irclog "<#{m.source}> #{m.logmessage}", logtarget 106: end 107: when QuitMessage 108: m.was_on.each { |ch| 109: irclog "@ quit (#{m.message})", ch 110: } 111: end 112: end
# File lib/rbot/core/irclog.rb, line 49 49: def timestamp(time) 50: return time.strftime(@bot.config['irclog.timestamp_format']) 51: end
def names(m)
# TODO
end
# File lib/rbot/core/irclog.rb, line 244 244: def unknown_message(m) 245: irclog m.logmessage, ".unknown" 246: end
# File lib/rbot/core/irclog.rb, line 114 114: def welcome(m) 115: irclog "joined server #{m.server} as #{m.target}", "server" 116: end
# File lib/rbot/core/irclog.rb, line 253 253: def loggers_thread 254: ls = nil 255: debug 'loggers_thread starting' 256: while ls = @queue.pop 257: message, where = ls 258: message = message.chomp 259: now = Time.now 260: stamp = timestamp(now) 261: if where.class <= Server 262: where_str = "server" 263: else 264: where_str = where.downcase.gsub(/[:!?$*()\/\\<>|"']/, "_") 265: end 266: next unless can_log_on(where_str) 267: 268: # close the previous logfile if we're rotating 269: if @logs.has_key? where_str 270: fp = logfilepath(where_str, now) 271: logfile_close(where_str, 'log rotation') if fp != @logs[where_str][1].path 272: end 273: 274: # (re)open the logfile if necessary 275: unless @logs.has_key? where_str 276: if @logs.size > @bot.config['irclog.max_open_files'] 277: @logs.keys.sort do |a, b| 278: @logs[a][0] <=> @logs[b][0] 279: end.slice(0, @logs.size - @bot.config['irclog.max_open_files']).each do |w| 280: logfile_close w, "idle since #{@logs[w][0]}" 281: end 282: end 283: fp = logfilepath(where_str, now) 284: begin 285: dir = File.dirname(fp) 286: # first of all, we check we're not trying to build a directory structure 287: # where one of the components exists already as a file, so we 288: # backtrack along dir until we come across the topmost existing name. 289: # If it's a file, we rename to filename.old.filedate 290: up = dir.dup 291: until File.exist? up 292: up.replace(File.dirname(up)) 293: end 294: unless File.directory? up 295: backup = up.dup 296: backup << ".old." << File.atime(up).strftime('%Y%m%d%H%M%S') 297: debug "#{up} is not a directory! renaming to #{backup}" 298: File.rename(up, backup) 299: end 300: FileUtils.mkdir_p(dir) 301: # conversely, it may happen that fp exists and is a directory, in 302: # which case we rename the directory instead 303: if File.directory? fp 304: backup = fp.dup 305: backup << ".old." << File.atime(fp).strftime('%Y%m%d%H%M%S') 306: debug "#{fp} is not a file! renaming to #{backup}" 307: File.rename(fp, backup) 308: end 309: # it should be fine to create the file now 310: f = File.new(fp, "a") 311: f.sync = true 312: f.puts "#{stamp} @ Log started by #{@bot.myself.nick}" 313: rescue Exception => e 314: error e 315: next 316: end 317: @logs[where_str] = [now, f] 318: end 319: @logs[where_str][1].puts "#{stamp} #{message}" 320: @logs[where_str][0] = now 321: #debug "#{stamp} <#{where}> #{message}" 322: end 323: @logs.keys.each { |w| logfile_close(w, 'rescan or shutdown') } 324: debug 'loggers_thread terminating' 325: end