#!/usr/local/bin/ruby # # convert Postfix log to CSV text # # usage: pflog [-d] ... # -d: output unknown format to stderr # # output: # id # arrived time # processed time # smtp client hostname / uid # smtp client IP address / username # envelope from # envelope to # message-id # status # information (reason of defered, local mailbox name, successful message...) Year = 2002 $mon = [0, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] if ARGV[0] == '-d' then $debug = true ARGV.shift end def toTime(d) mon, day, hour, min, sec = d.split /\s+|:/ mon = $mon.index mon Time::local(Year, mon, day.to_i, hour.to_i, min.to_i, sec.to_i) end def unknown_format(line) $stderr.puts "unknown format: <<<<<<<< #{line} >>>>>>>>" if $debug end $arrive_time = {} $hostname = {} $ipaddr = {} $msgid = {} $from = {} $size = {} ARGF.each do |line| line.chomp! unless line =~ /^([A-Z][a-z][a-z] ?\d+ \d+:\d+:\d+) (\S+) postfix\/\w+\[\d+\]: (?:\[.*\] )?(.*)$/ unknown_format line next end datetime = $1 hostname = $2 c = $3 next if c =~ /^(dis)?connect from / unless c =~ /^([A-Z0-9]+): (.*)$/ unknown_format line next end id = $1 c = $2 case c when /^client=(\S+)\[(.*)\]/ $arrive_time[id] = toTime(datetime) if not $arrive_time.include? id $hostname[id] = $1 $ipaddr[id] = $2 when /^uid=(\d+) from=<(.*)>/ $arrive_time[id] = toTime(datetime) if not $arrive_time.include? id $hostname[id] = $2 $ipaddr[id] = $1 when /^message-id=(.*)/ $msgid[id] = $1 when /^from=<(.*)>, size=(\d+),/ $from[id] = $1 $size[id] = $1 when /^to=<(.*)>,.* status=(\S+) \((.*)\)/ to = $1 status = $2 info = $3 action_time = toTime(datetime).strftime('%Y/%m/%d %H:%M:%S') at = $arrive_time[id] ? $arrive_time[id].strftime('%Y/%m/%d %H:%M:%S') : nil puts [id,at,action_time,$hostname[id],$ipaddr[id],$from[id],to,$msgid[id],status,info].join(',') else unknown_format line end end