#!/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"