A friend of mine uses the MS Exchange server. He searched a way to analyze his log-files. He sent me some sample data and I build this small log-analyzer. It offers to select a .log-file and to choose a field to search within. The result is presented in a hierarchical way (sender->mails->events).
#!/usr/bin/perl use strict; use warnings; use CGI; use CGI::Carp qw( fatalsToBrowser warningsToBrowser ); use HTML::Template; my $q = new CGI; print $q->header(), as_html($q); exit(); sub bloat { my $file = shift; my $search = shift; my $field = shift; my $rows = {}; open (FILE,"$file") || die "Error opening $file, RC=$!"; while (<FILE>) { next unless $. > 3; chomp; my @line = split /\t/, $_; next unless @line; my ($date, $time, $to, $id, $subject, $from, $event ) = @line[0,1,7,9,18,19,8]; $date =~ s/^(\d{4})\D(\d+)\D(\d+)$/$3.$2.$1/o; $time =~ s/\s+\w+$//o; if ($line[$field] =~ /$search/i) { $rows->{$from}->{$id} = {from => $from, to => $to, subject => $subject, id => $id} unless exists $rows->{$from}->{$id}; $rows->{$from}->{$id}->{events} = [] unless exists $rows->{$from}->{$id}->{events}; push @{$rows->{$from}->{$id}->{events}}, {event => $event, date => $date, time => $time,}; } } close (FILE); return $rows; } sub flatten { my $row = shift; my $set = []; @$set = map { from => $_ }, (keys %{$row}); for my $from (@$set) { push @{$from->{id}}, $_ for (keys %{$row->{$from->{from}}}); for my $msg (@{$from->{id}}) { push @{$from->{message}}, $_ for ($row->{$from->{from}}->{$msg}) +; } } return $set; } sub as_html { my $q = shift; my $template = HTML::Template->new( filename => "report_exch.tmpl", die_on_bad_params => 0, ); $q->param('action') eq 'analyze' ? $template->param( what => flatten(bloat($q->param('file'), $q->param('search') , $q->param('field') +))) : $template->param( results => 'FALSE'); my @files = map { {file=>$_,} } <*.log>; $template->param( logs => \@files ); $template->param( fields => selection() ); return $template->output; } sub selection { my @fields = qw (0 1 7 9 18 19 8); my @result = map { {option => $_, value => shift @fields} } qw (date time to id subject from event); return \@result; }
I use HTML::Template to separate code from content.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Entwurf V2.0</title> <meta name="author" content="Ronnie Neumann" /> <meta name="generator" content="Perl-Script using HTML::Template" /> <style type="text/css" media="all"> .inner { border-style: solid; border-width: 1px; border-color: #000080; background-color:#FFFFDD; visibility: hidden; position: absolute; margin: 5px; padding: 5px; } body { border-style: solid; border-width: 1px; border-color: #AAAAAA; background-color:#FFFFDF; padding: 3px; margin: 5px; } form { border-style: solid; border-width: 1px; border-color: #AAAAAA; background-color:#DDDDFF; padding: 2px; } </style> <script type="text/javascript"> <!-- function toggle(elementname) { /*if (document.getElementById(elementname).style.visibility == "" ) { document.getElementById(elementname).style.visibility = "visible";}*/ if (document.getElementById(elementname).style.visibility == "visible +" ) { document.getElementById(elementname).style.visibility = "hidden"; document.getElementById(elementname).style.position = "absolute"; //document.getElementById(elementname).style.left = "0px"; //document.getElementById(elementname).style.top = "0px"; } else { document.getElementById(elementname).style.visibility = "visible" +; document.getElementById(elementname).style.position = "relative"; } ; } // --> </script> </head> <body> <form method="POST" action="report_exch.pl"> <select name="file"> <TMPL_LOOP NAME="logs"> <option value="<TMPL_VAR NAME="file">"><TMPL_VAR NAME="file"></optio +n> </TMPL_LOOP> </select> <select name="field"> <TMPL_LOOP NAME="fields"> <option value="<TMPL_VAR NAME="value">"><TMPL_VAR NAME="option"></op +tion> </TMPL_LOOP> </select> search for:&nbsp; <input type='Text' name='search' size='20' maxlength='20' /> <input type="submit" value="analyze" name="action" /><br /> </form> <TMPL_UNLESS NAME="results"> <div id="analyze"> <TMPL_LOOP NAME="what"> Sender: <strong><TMPL_VAR NAME="from"></strong><br /> <a href="javascript:toggle('<TMPL_VAR NAME="from">');">show/hide m +ails</a> <div id="<TMPL_VAR NAME="from">" class="inner"> <TMPL_LOOP NAME="message"> <br />Recipient:&nbsp;<strong><TMPL_VAR NAME="to"></strong><br /> Subject:&nbsp;&nbsp;&nbsp;<strong><TMPL_VAR NAME="subject"></stron +g><br /> <a href="javascript:toggle('<TMPL_VAR NAME="id">');">show/hide eve +nts</a><br /> <table border="1" id="<TMPL_VAR NAME="id">" class="inner"> <tr><th>Date</th><th>Time</th><th>Event-ID</th></tr> <TMPL_LOOP NAME="events"> <tr><td><TMPL_VAR NAME="date"></td><td><TMPL_VAR NAME="time">< +/td><td><TMPL_VAR NAME="event"></td></tr> </TMPL_LOOP> </table> </TMPL_LOOP> </div> <hr /> </TMPL_LOOP> </div> </TMPL_UNLESS> </body> </html>
Of course there is room for further improvements. I'd be glad to hear some suggestions.

neniro

Replies are listed 'Best First'.
Re: Exchange Log Analyzer
by maxwin (Initiate) on Jul 21, 2004 at 13:53 UTC
    I a am new with Perl, could you explain me how to test the script with IIS ? What do I need to install this log-analyzer for Exchange ? Thanx. My email : maxwin@tiscali.fr
      Dear maxwin,
      if you're new to perl, the first step is to get Perl form Activestate. After you've installed Perl you need to get the HTML::Template modul. You can install modules easily using ppm - a commandline tool included in the Activestate distribution of Perl. That's well documented at the activestate site. To use the 'Exchange Log Analyzer' you'll have to create a new Webfolder in your IIS and put the .pl and the .tmpl-file into this folder. At this place the script also expects the .log files.

      To be fair I have to say that the script is a proof of concept and is not designed for a production enviroment. It isn't secure so you shouldn't use it accessible from the internet.

      best regards, neniro

        I install the file index.pl and the report_exch.tmpl but it did not have the file report_exch.pl that is in the code of the file report_exch.tmpl Thanx. Maxime.