]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/core/irclog.rb
httputil: remove obsolete version_1_2 declaration
[user/henk/code/ruby/rbot.git] / lib / rbot / core / irclog.rb
index 61fdc5611bc3201dd96ddc75b4ddac72b5d6e213..3b3134c205ebe67ce7e0022a839fc4489cd4332b 100644 (file)
@@ -23,6 +23,9 @@ class IrcLogModule < CoreBotModule
   Config.register Config::StringValue.new('irclog.filename_format',
     :default => '%%{where}', :requires_rescan => true,
     :desc => "filename pattern for the IRC log. You can put typical strftime keys such as %Y for year and %m for month, plus the special %%{where} key for location (channel name or user nick)")
+  Config.register Config::StringValue.new('irclog.timestamp_format',
+    :default => '[%Y/%m/%d %H:%M:%S]', :requires_rescan => true,
+    :desc => "timestamp pattern for the IRC log, using typical strftime keys")
 
   attr :nolog_rx, :dolog_rx
   def initialize
@@ -30,7 +33,9 @@ class IrcLogModule < CoreBotModule
     @queue = Queue.new
     @thread = Thread.new { loggers_thread }
     @logs = Hash.new
-    Dir.mkdir("#{@bot.botclass}/logs") unless File.exist?("#{@bot.botclass}/logs")
+    logdir = @bot.path 'logs'
+    Dir.mkdir(logdir) unless File.exist?(logdir)
+    # TODO what shall we do if the logdir couldn't be created? (e.g. it existed as a file)
     event_irclog_list_changed(@bot.config['irclog.no_log'], @bot.config['irclog.do_log'])
     @fn_format = @bot.config['irclog.filename_format']
   end
@@ -41,6 +46,10 @@ class IrcLogModule < CoreBotModule
     return true
   end
 
+  def timestamp(time)
+    return time.strftime(@bot.config['irclog.timestamp_format'])
+  end
+
   def event_irclog_list_changed(nolist, dolist)
     @nolog_rx = nolist.empty? ? nil : Regexp.union(*(nolist.map { |r| r.to_irc_regexp }))
     debug "no log: #{@nolog_rx}"
@@ -54,8 +63,8 @@ class IrcLogModule < CoreBotModule
 
   def logfile_close(where_str, reason = 'unknown reason')
     f = @logs.delete(where_str) or return
-    stamp = Time.now.strftime '%Y/%m/%d %H:%M:%S'
-    f[1].puts "[#{stamp}] @ Log closed by #{@bot.myself.nick} (#{reason})"
+    stamp = timestamp(Time.now)
+    f[1].puts "#{stamp} @ Log closed by #{@bot.myself.nick} (#{reason})"
     f[1].close
   end
 
@@ -144,7 +153,7 @@ class IrcLogModule < CoreBotModule
         irclog "@ #{m.source} asked #{who} about #{[m.ctcp, m.message].join(' ')}", logtarget
       end
     else
-      if m.public? 
+      if m.public?
         irclog "<#{m.source}> #{m.logmessage}", m.target
       else
         irclog "<#{m.source}(#{m.sourceaddress})> #{m.logmessage}", m.source
@@ -167,13 +176,13 @@ class IrcLogModule < CoreBotModule
   end
 
   def log_nick(m)
-    m.is_on.each { |ch|
+    (m.is_on & @bot.myself.channels).each { |ch|
       irclog "@ #{m.oldnick} is now known as #{m.newnick}", ch
     }
   end
 
   def log_quit(m)
-    m.was_on.each { |ch|
+    (m.was_on & @bot.myself.channels).each { |ch|
       irclog "@ Quit: #{m.source}: #{m.logmessage}", ch
     }
   end
@@ -237,7 +246,7 @@ class IrcLogModule < CoreBotModule
   end
 
   def logfilepath(where_str, now)
-    File.join(@bot.botclass, 'logs', now.strftime(@fn_format) % { :where => where_str })
+    @bot.path('logs', now.strftime(@fn_format) % { :where => where_str })
   end
 
   protected
@@ -248,13 +257,13 @@ class IrcLogModule < CoreBotModule
       message, where = ls
       message = message.chomp
       now = Time.now
-      stamp = now.strftime("%Y/%m/%d %H:%M:%S")
+      stamp = timestamp(now)
       if where.class <= Server
         where_str = "server"
       else
         where_str = where.downcase.gsub(/[:!?$*()\/\\<>|"']/, "_")
       end
-      return unless can_log_on(where_str)
+      next unless can_log_on(where_str)
 
       # close the previous logfile if we're rotating
       if @logs.has_key? where_str
@@ -272,15 +281,44 @@ class IrcLogModule < CoreBotModule
           end
         end
         fp = logfilepath(where_str, now)
-        FileUtils.mkdir_p File.dirname(fp)
-        f = File.new(fp, "a")
-        f.sync = true
-        f.puts "[#{stamp}] @ Log started by #{@bot.myself.nick}"
+        begin
+          dir = File.dirname(fp)
+          # first of all, we check we're not trying to build a directory structure
+          # where one of the components exists already as a file, so we
+          # backtrack along dir until we come across the topmost existing name.
+          # If it's a file, we rename to filename.old.filedate
+          up = dir.dup
+          until File.exist? up
+            up.replace(File.dirname(up))
+          end
+          unless File.directory? up
+            backup = up.dup
+            backup << ".old." << File.atime(up).strftime('%Y%m%d%H%M%S')
+            debug "#{up} is not a directory! renaming to #{backup}"
+            File.rename(up, backup)
+          end
+          FileUtils.mkdir_p(dir)
+          # conversely, it may happen that fp exists and is a directory, in
+          # which case we rename the directory instead
+          if File.directory? fp
+            backup = fp.dup
+            backup << ".old." << File.atime(fp).strftime('%Y%m%d%H%M%S')
+            debug "#{fp} is not a file! renaming to #{backup}"
+            File.rename(fp, backup)
+          end
+          # it should be fine to create the file now
+          f = File.new(fp, "a")
+          f.sync = true
+          f.puts "#{stamp} @ Log started by #{@bot.myself.nick}"
+        rescue Exception => e
+          error e
+          next
+        end
         @logs[where_str] = [now, f]
       end
-      @logs[where_str][1].puts "[#{stamp}] #{message}"
+      @logs[where_str][1].puts "#{stamp} #{message}"
       @logs[where_str][0] = now
-      #debug "[#{stamp}] <#{where}> #{message}"
+      #debug "#{stamp} <#{where}> #{message}"
     end
     @logs.keys.each { |w| logfile_close(w, 'rescan or shutdown') }
     debug 'loggers_thread terminating'