dimanche 28 mars 2010

Essbase Rightlog lite version

Lately I reviewed my rightlog Perl script making a light version and correcting a few bugs. The script takes any Essbase server or application log as input.

This lite version doesn't provided a deep analysis with SQLite db as the original version and doesn't provide a native Excel output. The idea was to make it work in any Perl environment without any specific module.

You may also compile this Perl script using PAR which is a great Perl module. I installed PAR module through Perl Package Manager (graphical or command line : ppm.bat) and compiled RightLogLite.pl using the following command : pp -o x:\RightLogLite.exe c:\RightLogLite.pl

RightLogLite is also available as a download here

#!/usr/bin/perl
#!/usr/bin/perl

# Name: RightLogLite
# RightLog light edition
# Author: Sébastien Roux
# Mailto: roux.sebastien@gmail.com
# Version: 1.0 - march 2010

# Modules include
use Getopt::Std;
#use Strict;

# Set argument parameters
# -i input,    -o output,        -d date,    -c categories
# -h help,    -s separator,    -f filter,    -t header
getopts( "i:o:d:chs:f:t", \%opts ) or DisplayUsage();

# Verify arguments
DisplayHelp();
TestInputFileArg();
TestFilterArg();
TestDateFormatArg();
TestSeparatorArg();

# File output arg (-o)
if ( $opts{o} ) {
    open( OUTPUT, ">$opts{o}" )
      or die print "Error: could not open output file:\n$opts{o}\n";

    # Header arg (-t)
    if ( $opts{t} ) {
        print OUTPUT SetHeader();
    }
}

# StdOut arg
else {

    # Header arg (-t)
    if ( $opts{t} ) {
        print SetHeader();
    }
}

# For each log file
foreach $i (@i) {

    # Open logfile
    open( LOGFILE, "$i" )
      or die print "Error: '$i' not found in specified path\n";

    while () {

        # Skip blank lines
        next unless ( !/^(\s)*$/ );

        # Advanced delimiter (not "[")
        if (/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)/i) {
            chomp;
            $Line = $_;    # Current line
            EssDelimitedLog();
        }

        # Default delimiter ("[")
        elsif (/^\[(Mon|Tue|Wed|Thu|Fri|Sat|Sun)/i) {
            chomp;
            $Line  = $_;           # Current line
            $Line2 = ;    # Read next line
            chomp($Line2);
            EssClassicLog();
        }

        # Other case (description)
        else {
            chomp;
            $Line = $_;            # Current line
            Other();
        }

        # File ouput arg (-o) or
        # Excel output arg (-x) or
        # Query ouput arg (-q)
        if ( $opts{o} ) {

            # Filtering
            unless ( $Line !~ /.*$f.*$/ ) {
                print OUTPUT $Line . "\n";
            }
        }

        # StdOut output
        else {

            # Filtering
            unless ( $Line !~ /.*$f.*$/ ) {
                print $Line. "\n";
            }
        }
    }
    close(LOGFILE);
}
exit;

#------------------------------------------------------------
# FUNCTIONS
#------------------------------------------------------------
# Essbase v.5, 6, 7, 9, 11 classic delimiters ([, ])
sub EssClassicLog {

    $Line =~ s/^\[//;                # Replace opening bracket ([) with nothing
    $Line =~ s/\]/$s/;               # Replace closing bracket (])
    $Line =~ s/\ /$s/ for 1 .. 4;    # Replace 4 1st whitespace
    $Line =~ s/\//$s/gm;             # Replace slash delimiters (/)

    ChangeDateFormat();

    # Categories arg (-c)
    if ( $opts{c} ) { AddMessageCategory(); }
    else {
        $Line =~ s/[()]/$s/ for 1 .. 2;    # Replace bracket delimiters ((,))
    }

    unless ( $Line2 =~ /^(\s)*$/ ) {       # Join with next line if not empty
        $Line = $Line . $Line2;
    }

    $Line =~ s/ +/ /gm;        # Replacing multi-space by single space
    $Line =~ s/[ \t]+$//gm;    # Deleting eol tab/space
}

#--------------------------------
# Essbase v. 6, 7, 9, 11 advanced delimiters
# DELIMITEDMSG setting in config file with parameter: *, :, &, #, ~
sub EssDelimitedLog {

    my @f = split /[~^*&:]/, $Line;    # Split according to defined pattern
                                       # and fill a list
    $lastf = scalar(@f);
    $Line =
        join( $s, @f[ 0 .. 3 ] ) . ':'
      . join( ':', @f[ 4 .. 5 ] )
      . $s
      . join( $s,  @f[ 6 .. 11 ] )
      . join( '',  @f[ 12 .. 13 ] ) . ' '
      . join( ' ', @f[ 14 .. $lastf ] );

    ChangeDateFormat();

    # Categories arg (-c)
    if ( $opts{c} ) { AddMessageCategory(); }
    else {
        $Line =~ s/[()]/$s/ for 1 .. 2;    # Replace bracket delimiters ((,))
    }

    $Line =~ s/ +/ /gm;        # Replacing multi-space by single space
    $Line =~ s/[ \t]+$//gm;    # Deleting eol tab/space
}

#--------------------------------
sub Other {

    # Date arg (-d)
    if ( $opts{d} ) {

        # Categories arg (-c)
        if ( $opts{c} ) {
            $Line = "$s$s$s$s$s$s$s$s$s$Line";
        }
        else {
            $Line = "$s$s$s$s$s$s$s$s$Line";
        }
    }
    else {
        if ( $opts{c} ) {
            $Line = "$s$s$s$s$s$s$s$s$s$s$s$s$Line";
        }
        else {
            $Line = "$s$s$s$s$s$s$s$s$s$s$s$Line";
        }
    }
    $Line =~ s/ +/ /gm;        # Replacing multi-space by single space
    $Line =~ s/\t//gm;         # Deleting tab
    $Line =~ s/[ \t]+$//gm;    # Deleting eol tab/space
}

#--------------------------------
sub DisplayHelp {

    # Help arg (-h) or
    # no arg
    if ( $opts{h} || @ARGV > 0 ) {
        print "DESCRIPTION:\n"
          . "RightLogLite : parse ANY Essbase (v.5-v.11) server and application logs.\n"
          . "Generate a full custom delimited spreadsheet/database ready output\n"
          . "for enhanced analysis.\n"
          . "Options available: advanced date formatting, headers insertion,\n"
          . "detailed message categories, filtering, custom separator,\n"
          . "Stdout or file output\n\n";
        print "VERSION:\n" . "v.1.0 - march 2010\n\n";
        print "AUTHOR:\n"
          . "Written by Sebastien Roux \n\n";
        print "LICENSE:\n" . "GNU General Public License version 3 (GPLv3)\n\n";
        print "NOTES:\n"
          . "Use at your own risk!\n"
          . "You will be solely responsible for any damage\n"
          . "to your computer system or loss of data\n"
          . "that may result from the download\n"
          . "or the use of the following application/script.\n\n";
        DisplayUsage();
    }
}

#--------------------------------
sub DisplayUsage {

    print "USAGE: EssbaseRightLog -i \n"
      . "[-o , -c, -d , -t, -s , -f , -h]\n\n";
    print " -i specify Essbase log(s), args: \n";
    print " -o specify output file, arg: \n";
    print " -c specify message categories\n";
    print " -d specify date format, arg: \n";
    print " -t specify headers on top\n";
    print " -s specify separator, arg: <*>\n";
    print " -f specify filter (case sensitive), arg: \n";
    print " -h display usage\n";
    exit;
}

#--------------------------------
sub TestInputFileArg {

    if ( $opts{i} ) {
        @i = split /;/, $opts{i};

        foreach $i (@i) {
            if ( !-e $i ) {
                print "Error: input file '$i' does not exists!\n";
                DisplayUsage();
            }
        }
    }
    else {
        DisplayUsage();
    }
}

#--------------------------------
sub TestDateFormatArg {

    # Date arg (-d)
    if (   $opts{d}
        && ( uc( $opts{d} ) ne "ISO" )
        && ( uc( $opts{d} ) ne "EUR" )
        && ( uc( $opts{d} ) ne "US" ) )
    {
        print
          "Error: '$opts{d}' is not a valid argument for date format (-d)!\n";
        DisplayUsage();
    }
}

#--------------------------------
# Add category for message code
sub AddMessageCategory {

    my $MsgCode;
    my $MsgType;

    if ( $Line =~ m/\d{7,7}/ ) {
        $MsgCode = $&;

        if ( $MsgCode ge 1001000 && $MsgCode le 1001999 ) {
            $MsgType = "Report writer";
        }
        elsif ( $MsgCode ge 1002000 && $MsgCode le 1002999 ) {
            $MsgType = "General server";
        }
        elsif ( $MsgCode ge 1003000 && $MsgCode le 1003999 ) {
            $MsgType = "Data load";
        }
        elsif ( $MsgCode ge 1004000 && $MsgCode le 1004999 ) {
            $MsgType = "General server";
        }
        elsif ( $MsgCode ge 1005000 && $MsgCode le 1005999 ) {
            $MsgType = "Backup, export, or validate";
        }
        elsif ( $MsgCode ge 1006000 && $MsgCode le 1006999 ) {
            $MsgType = "Data cache";
        }
        elsif ( $MsgCode ge 1007000 && $MsgCode le 1007999 ) {
            $MsgType = "Outline restructure";
        }
        elsif ( $MsgCode ge 1008000 && $MsgCode le 1008999 ) {
            $MsgType = "System calls, portable layer, ASD, or agent";
        }
        elsif ( $MsgCode ge 1009000 && $MsgCode le 1009999 ) {
            $MsgType = "Restoring ASCII data";
        }
        elsif ( $MsgCode ge 1010000 && $MsgCode le 1010999 ) {
            $MsgType = "Internal - block numbering";
        }
        elsif ( $MsgCode ge 1011000 && $MsgCode le 1011999 ) {
            $MsgType = "Internal - utilities";
        }
        elsif ( $MsgCode ge 1012000 && $MsgCode le 1012999 ) {
            $MsgType = "Calculator";
        }
        elsif ( $MsgCode ge 1013000 && $MsgCode le 1013999 ) {
            $MsgType = "Requestor";
        }
        elsif ( $MsgCode ge 1014000 && $MsgCode le 1014999 ) {
            $MsgType = "Lock manager";
        }
        elsif ( $MsgCode ge 1015000 && $MsgCode le 1015999 ) {
            $MsgType = "Alias table";
        }
        elsif ( $MsgCode ge 1016000 && $MsgCode le 1016999 ) {
            $MsgType = "Report writer";
        }
        elsif ( $MsgCode ge 1017000 && $MsgCode le 1017999 ) {
            $MsgType = "Currency";
        }
        elsif ( $MsgCode ge 1018000 && $MsgCode le 1018999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1019000 && $MsgCode le 1019999 ) {
            $MsgType = "Database artifacts";
        }
        elsif ( $MsgCode ge 1020000 && $MsgCode le 1020999 ) {
            $MsgType = "Spreadsheet extractor";
        }
        elsif ( $MsgCode ge 1021000 && $MsgCode le 1021999 ) {
            $MsgType = "Essbase SQL interface";
        }
        elsif ( $MsgCode ge 1022000 && $MsgCode le 1022999 ) {
            $MsgType = "Security";
        }
        elsif ( $MsgCode ge 1023000 && $MsgCode le 1023999 ) {
            $MsgType = "Partitioning";
        }
        elsif ( $MsgCode ge 1024000 && $MsgCode le 1024999 ) {
            $MsgType = "Query extractor";
        }
        elsif ( $MsgCode ge 1030000 && $MsgCode le 1030999 ) {
            $MsgType = "API";
        }
        elsif ( $MsgCode ge 1040000 && $MsgCode le 1040999 ) {
            $MsgType = "General network";
        }
        elsif ( $MsgCode ge 1041000 && $MsgCode le 1041999 ) {
            $MsgType = "Network - Named Pipes";
        }
        elsif ( $MsgCode ge 1042000 && $MsgCode le 1042999 ) {
            $MsgType = "Network - TCP";
        }
        elsif ( $MsgCode ge 1043000 && $MsgCode le 1049999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1050000 && $MsgCode le 1055999 ) {
            $MsgType = "Agent";
        }
        elsif ( $MsgCode ge 1056000 && $MsgCode le 1059999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1060000 && $MsgCode le 1060999 ) {
            $MsgType = "Outline API";
        }
        elsif ( $MsgCode ge 1061000 && $MsgCode le 1069999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1070000 && $MsgCode le 1070999 ) {
            $MsgType = "Index manager";
        }
        elsif ( $MsgCode ge 1071000 && $MsgCode le 1079999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1080000 && $MsgCode le 1080099 ) {
            $MsgType = "Transaction manager";
        }
        elsif ( $MsgCode ge 1081000 && $MsgCode le 1089999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1090000 && $MsgCode le 1099999 ) {
            $MsgType = "Rules file processing";
        }
        elsif ( $MsgCode ge 1010000 && $MsgCode le 1019999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1100000 && $MsgCode le 1100999 ) {
            $MsgType = "Not currently used";
        }
        elsif ( $MsgCode ge 1110000 && $MsgCode le 1119999 ) {
            $MsgType = "Web Analysis";
        }
        elsif ( $MsgCode ge 1120000 && $MsgCode le 1129999 ) {
            $MsgType = "Grid API";
        }
        elsif ( $MsgCode ge 1130000 && $MsgCode le 1139999 ) {
            $MsgType = "Miscellaneous";
        }
        elsif ( $MsgCode ge 1140000 && $MsgCode le 1149999 ) {
            $MsgType = "Linked Reporting Objects";
        }
        elsif ( $MsgCode ge 1150000 && $MsgCode le 1159999 ) {
            $MsgType = "Outline synchronization";
        }
        elsif ( $MsgCode ge 1160000 && $MsgCode le 1169999 ) {
            $MsgType = "Outline change records";
        }
        elsif ( $MsgCode ge 1170000 && $MsgCode le 1179999 ) {
            $MsgType = "Attributes";
        }
        elsif ( $MsgCode ge 1180000 && $MsgCode le 1189999 ) {
            $MsgType = "Showcase";
        }
        elsif ( $MsgCode ge 1190000 && $MsgCode le 1199999 ) {
            $MsgType = "Enterprise Integration Services";
        }
        elsif ( $MsgCode ge 1200000 && $MsgCode le 1200999 ) {
            $MsgType = "Calculator framework";
        }
        else { $MsgType = "Other"; }
        $Line =~ s/\(\d{7,7}\)/$s$MsgCode$s$MsgType$s/;
    }
}

#--------------------------------
sub ChangeDateFormat {

    ChangeMonthString();

    my @l = split /[$s]/, $Line;
    my $last;

    # Set date format to ISO 8601 extended style (YYYY-MM-DD)
    if ( uc( $opts{d} ) eq "ISO" ) {
        $last = scalar(@l);
        $Line =
            @l[ 4 .. 4 ] . '-'
          . @l[ 1 .. 1 ] . '-'
          . @l[ 2 .. 2 ]
          . $s
          . join( $s, @l[ 3 .. 3 ] )
          . $s
          . join( $s, @l[ 5 .. $last - 1 ] );
    }

    # Set date format to US style (MM/DD/YYYY)
    elsif ( uc( $opts{d} ) eq "US" ) {
        $last = scalar(@l);
        $Line =
            @l[ 1 .. 1 ] . '/'
          . @l[ 2 .. 2 ] . '/'
          . @l[ 4 .. 4 ]
          . $s
          . join( $s, @l[ 3 .. 3 ] )
          . $s
          . join( $s, @l[ 5 .. $last - 1 ] );
    }

    # Set date format to European style (DD/MM/YYYY)
    elsif ( uc( $opts{d} ) eq "EUR" ) {
        $last = scalar(@l);
        $Line =
            @l[ 2 .. 2 ] . '/'
          . @l[ 1 .. 1 ] . '/'
          . @l[ 4 .. 4 ]
          . $s
          . join( $s, @l[ 3 .. 3 ] )
          . $s
          . join( $s, @l[ 5 .. $last - 1 ] );
    }
}

#--------------------------------
# Replace month label by month number
sub ChangeMonthString {

    my $MonthIndex;

    if ( $Line =~ m/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)/ ) {
        if    ( lc($&) eq "jan" ) { $MonthIndex = "01"; }
        elsif ( lc($&) eq "feb" ) { $MonthIndex = "02"; }
        elsif ( lc($&) eq "mar" ) { $MonthIndex = "03"; }
        elsif ( lc($&) eq "apr" ) { $MonthIndex = "04"; }
        elsif ( lc($&) eq "may" ) { $MonthIndex = "05"; }
        elsif ( lc($&) eq "jun" ) { $MonthIndex = "06"; }
        elsif ( lc($&) eq "jul" ) { $MonthIndex = "07"; }
        elsif ( lc($&) eq "aug" ) { $MonthIndex = "08"; }
        elsif ( lc($&) eq "sep" ) { $MonthIndex = "09"; }
        elsif ( lc($&) eq "oct" ) { $MonthIndex = "10"; }
        elsif ( lc($&) eq "nov" ) { $MonthIndex = "11"; }
        elsif ( lc($&) eq "dec" ) { $MonthIndex = "12"; }
        $Line =~ s/$&/$MonthIndex/;
    }
}

#--------------------------------
# Set default separator (|) if separator arg not specified
sub TestSeparatorArg {

    my $defaultseparator = "    ";

    # Separator arg (-s)
    if   ( not( $opts{s} ) ) { $s = $defaultseparator; }
    else                     { $s = $opts{s}; }

    return $s;
}

#--------------------------------
# Set default filter to empty if filter arg not specified
sub TestFilterArg {

    my $defaultfilter = "";

    # Filter arg (-f)
    if ( not( $opts{f} ) ) {
        $f = $defaultfilter;
    }
    else {
        $f = $opts{f};
    }

    return $f;
}

#--------------------------------
sub SetHeader {

    my $Header;

    # Date arg (-d)
    if ( $opts{d} ) {

        # Categories arg (-c)
        if ( $opts{c} ) {
            $Header =
                "date" 
              . $s . "time" 
              . $s 
              . "server" 
              . $s
              . "application"
              . $s
              . "database"
              . $s . "user"
              . $s
              . "msglevel"
              . $s
              . "msgcode"
              . $s
              . "msgcat"
              . $s
              . "description\n";
        }

        # No categories
        else {
            $Header =
                "date" 
              . $s . "time" 
              . $s 
              . "server" 
              . $s
              . "application"
              . $s
              . "database"
              . $s . "user"
              . $s
              . "msglevel"
              . $s
              . "msgcode"
              . $s
              . "description\n";
        }
    }

    # Default date format
    else {

        # Categories
        if ( $opts{c} ) {
            $Header =
                "day" 
              . $s . "month" 
              . $s 
              . "daynum" 
              . $s . "time" 
              . $s . "year"
              . $s
              . "server"
              . $s
              . "application"
              . $s
              . "database"
              . $s . "user"
              . $s
              . "msglevel"
              . $s
              . "msgcode"
              . $s
              . "msgcat"
              . $s
              . "description\n";
        }

        # No categories
        else {
            $Header =
                "day" 
              . $s . "month" 
              . $s 
              . "daynum" 
              . $s . "time" 
              . $s . "year"
              . $s
              . "server"
              . $s
              . "application"
              . $s
              . "database"
              . $s . "user"
              . $s
              . "msglevel"
              . $s
              . "msgcode"
              . $s
              . "description\n";
        }
    }
    return $Header;
}
__END__

Aucun commentaire:

Enregistrer un commentaire

your comment here please!