#!/usr/bin/env ruby
require 'optparse'
require 'ostruct'
require 'parsedate'
@my_args = ARGV.empty? ? [ "-h" ] : ARGV
@options = OpenStruct.new
opts = OptionParser.new
opts.on("-d","--directory DIRECTORY", String, "Directory full of log files to parse") { |val| @options.dir = val }
opts.on("-t","--to ADDRESS", String, "Find emails sent to a specific address") { |val| @options.to = val }
opts.on("-f","--from ADDRESS", String, "Find email sent from a specific address") { |val| @options.from = val }
opts.on("-s","--show-detail", "Output detail instead of summary information") { |val| @options.detail = val }
opts.on("-z=","--time-zone=", "Offset in hours from UTC") { |val| @options.tz }
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
opts.parse!(@my_args)
puts "Exchange 2003 Log Analyzer v.1\n" if !@options.detail
puts "Finding all messages sent to: '#{@options.to}'" if @options.to && !@options.detail
puts "Finding all messages sent from: '#{@options.from}'" if @options.from && !@options.detail
@smtp_in = 0
@smtp_out = 0
@local_deliver = 0
@msgids = Array.new
@options.tz = -7 if !@options.tz
# this function calculates the various statistics -
# messages are tracked so that they are not counted more than once
def process_line(line)
msgid = line[/^([^\t]+\t){9}([^\t]+)/, 2]
if !@msgids.index(msgid)
if line =~ /^([^\t]+\t){8}1019/ then @smtp_in += 1
elsif line =~ /^([^\t]+\t){8}1031/ then @smtp_out += 1
elsif line =~ /^([^\t]+\t){8}1023/ then @local_deliver += 1
else
# make sure that the current msgid is not added to the msgids array
return
end
# we only keep track of the last 50 msgid's processed -
# this should be sufficient to ensure an accurate record count
@msgids << msgid
@msgids.shift if @msgids.length > 50
# dump detail information to standard output if the -s flag is set
if @options.detail
sdate, stime = line.match(/^([\d]{4}-[\d]{1,2}-[\d]{1,2})\t([\d]{1,2}:[\d]{1,2}:[\d]{1,2})/).captures
res = ParseDate.parsedate(sdate + ' ' + stime)
utc = Time.utc(*res)
local = utc - (@options.tz * 60 * 60)
datestr = local.strftime('%m-%d-%Y %I:%M:%S %p')
data = line.split("\t")
puts '"'+datestr+'","'+data[19]+'","'+data[7]+'","'+data[18]+'"'
end
end
end
# process each .log file in the directory
Dir.glob(@options.dir+'/*.log') do |entry|
puts "Processing file: #{entry}\n" if !@options.detail
if @options.to && @options.from
regexp_to = /^([^\t]+\t){7}#{@options.to}/
regexp_from = /^([^\t]+\t){19}#{@options.from}/
File.open(entry, 'r').grep(regexp_to).grep(regexp_from) { |line| process_line(line) }
elsif @options.to
regexp = /^([^\t]+\t){7}#{@options.to}/
File.open(entry, 'r').grep(regexp) { |line| process_line(line) }
elsif @options.from
regexp = /^([^\t]+\t){19}#{@options.from}/
File.open(entry, 'r').grep(regexp) { |line| process_line(line) }
else
File.open(entry, 'r').each { |line| process_line(line) }
end
end
puts "#{@smtp_in} inbound total"
puts "#{@smtp_out} outbound total"
puts "#{@local_deliver} local messages"