namishtiwari has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, Here is my piece of code,
#!/usr/bin/perl Total_Number_Of_Transactions() ; sub Total_Number_Of_Transactions { my $logfile = $Logfile; my $logDir = $ARGV[0]; my $logPrefix = $ARGV[1]; die "usage: $0 <logDir> <logPrefix>" unless $logDir and $logPrefix; die "Log dir $logDir doesn't exist" unless -d "$logDir"; for my $logFile ( glob("$logDir/${logPrefix}*") ) { open($log, "<", $logFile) or die "Can't open $logFile for reading."; open(FP_OUT,">total_transactions") or die "cannot create file total_tr +ansactions for writing"; } my $Total_QnA_Count = 0; my $Total_OTP_Count = 0; my $Total_UP_Count = 0; my $Total_ArcotID_Count = 0; my $Success_QnA_Count =0; my $Failure_QnA_Count = 0; my $Success_ArcotID_Count = 0; my $Failure_ArcotID_Count = 0; my $Success_OTP_Count = 0; my $Failure_OTP_Count = 0; my $Success_UP_Count = 0; my $Failure_UP_Count = 0; OUTER: while( $line = <$log> ) { $line =~ tr/\r\n//d; if ($line =~ /Arcot Native Server: recvd AA_BIN_MSG_VER_CHG/) { while ($line = <$log>) { if ($line =~ /ArcotID\s*Auth\s*SUCCESS.*/) { $Success_ArcotID_Count++; next OUTER; } elsif ($line =~ /Auth failed.*/) { $Failure_ArcotID_Count++; next OUTER; } } } if ($line =~ /QNA Step - AUTH IN PROGRESS/) { while ($line = <$log>) { if ($line =~ /QNA Auth - Success.*/) { $Success_QnA_Count++; next OUTER; } elsif ($line =~ /Message: QNA Auth Failed.*/) { $Failure_QnA_Count++; next OUTER; } } } if ($line =~ /Entering OTPAuthModule::authenticate/) { while ($line = <$log>) { if ($line =~ /OTP SUCCESS.*/) { $Success_OTP_Count++; next OUTER; } elsif ($line =~ /Message: OTP FAILED.*/) { $Failure_OTP_Count++; next OUTER; } } } if ($line =~ /Entering UPAuthModule::authenticate/ .. /Sending Inv +alid credential/) { while ($line = <$log>) { if ($line =~ /UPAuth SUCCESS.*/) { $Success_UP_Count++; next OUTER; } elsif ($line =~ /UPAuth FAILED.*/) { $Failure_UP_Count++; next OUTER; } } } } $Total_ArcotID_Count = $Success_ArcotID_Count + $Failure_ArcotID_Count + ; $Total_QnA_Count = $Success_QnA_Count + $Failure_QnA_Count ; $Total_OTP_Count = $Success_OTP_Count + $Failure_OTP_Count ; $Total_UP_Count = $Success_UP_Count + $Failure_UP_Count ; printf FP_OUT "Total ApricotID count is $Total_ArcotID_Count\n"; printf FP_OUT "Total QnA count is $Total_QnA_Count\n"; printf FP_OUT "Total OTP count is $Total_OTP_Count\n"; printf FP_OUT "Total User Password count is $Total_UP_Count\n"; close(FP_OUT); close($log); }
It is not printing the correct output. the correct output is -- Total ArcotID count is -1187 Total QnA count is 74 Total OTP count is 4 Total User Password count is 2 but it is giving me- Total ArcotID count is 41 Total QnA count is 2 Total OTP count is 0 Total User Password count is 2 kindly give me some suggestions. I dont find any logic problem here. Thanks NT

Replies are listed 'Best First'.
Re: problem in output
by davorg (Chancellor) on Jun 29, 2009 at 14:16 UTC
    for my $logFile ( glob("$logDir/${logPrefix}*") ) { open($log, "<", $logFile) or die "Can't open $logFile for reading."; open(FP_OUT,">total_transactions") or die "cannot create file total_tr +ansactions for writing"; }

    This bit looks weird. How many log files do you think you'll be processing? You're opening multiple files on the same filehandle. Only the last one opened will be processed.

    And the standard suggestions about adding strict and warnings apply.

    --

    See the Copyright notice on my home node.

    Perl training courses

      Hi, There are not less than 10-15 files in a day log and that will be opened through that log handle. Then how can we modify the code to open each file with diffrent handle. And any suggestions about the output coming wrong. Thanks NT
        Then how can we modify the code to open each file with diffrent handle.

        Not sure that's the right approach. The approach I would take would be:

        • for each file
          • open file
          • process file contents
          • close file
        • next file
        And any suggestions about the output coming wrong.

        I strongly suspect that will be fixed once you process all of the files correctly.

        --

        See the Copyright notice on my home node.

        Perl training courses

Re: problem in output
by Util (Priest) on Jun 29, 2009 at 15:47 UTC

    Hidden Bug:

    if ($line =~ /Entering UPAuthModule::authenticate/ .. /Sending Invalid + credential/ )
    omits the `$line =~` from the second half of the flip-flip operands. It should read:
    if ( ( $line =~ /Entering UPAuthModule::authenticate/ ) .. ( $line =~ +/Sending Invalid credential/ ) )

    Subtle Bug: It is usually wrong to use printf() with variables imbedded in the template. From `perldoc -f printf`:

    Don't fall into the trap of using a "printf" when a simple "print" would do. The "print" is more efficient and less error prone.
    Either use print "Total is $total\n"; or printf "Total is %d\n", $total;.

    Other than that, I think davorg++ has pointed out the major problem; you are only actually processing the last log file. Here is an example of refactored flow:

Re: problem in output
by jethro (Monsignor) on Jun 29, 2009 at 14:37 UTC

    As we don't know what the input looks like, we can only guess. One problem I see: Your code assumes that between a transaction (between 'Entering xxx' and 'xxx SUCCESS' or 'XXX FAILED') no other transaction can insert lines into the logfile or it would not be counted. In most cases I know this is not true. In other words: if you step over an interleaved 'Entering yyy' while looking for a 'XXX' success or failure it doesn't get counted

    To solve this you could just count SUCCESS and FAILURE lines. You don't seem to do anything with the 'Entering' lines, so why bother?

    If that is not a good idea (because of integrity or security concerns) you would have to use a hash or something to remember which 'Entering' lines you already encountered

    BTW in lines like if ($line =~ /OTP SUCCESS.*/) the .* is useless and can be dropped without changing anything. Regexes look for string parts if you don't anker them with ^ or $

      Yes! This appears to be a simple peg count of particular lines. I don't see the need for anything complex. Maybe the Op can tell us if this works? Of course some tweaking of the regex'es...but looks like straight line code to me. I echo previous comments about "use strict; use warnings;".
      while( my $line = <$log> ) { $Success_ArcotID_Count++ if ($line =~ /ArcotID\s*Auth\s*SUCCESS.*/); $Failure_ArcotID_Count++ if ($line =~ /Auth failed.*/); $Success_QnA_Count++ if ($line =~ /QNA Auth - Success.*/); $Failure_QnA_Count++ if ($line =~ /Message: QNA Auth Failed.*/); $Success_OTP_Count++ if ($line =~ /OTP SUCCESS.*/); $Failure_OTP_Count++ if ($line =~ /Message: OTP FAILED.*/); $Success_UP_Count++ if ($line =~ /UPAuth SUCCESS.*/); $Failure_UP_Count++ if ($line =~ /UPAuth FAILED.*/); }
      If the above does indeed "work" in this application, it can be re-written so that token before either "SUCCESS" or "FAILED" creates a hash table peg count without needing this big "=0" declaration at the front.

      I think others have covered the open ">$file" "clobbers previous $file" problem. If you want append, use ">>" for the open. Glob isn't portable, but that's a different subject. Get the basic stuff working and then we'll talk about that detail.

Re: problem in output
by ikegami (Patriarch) on Jun 29, 2009 at 16:52 UTC
    The following makes no sense:
    if ($line =~ /Entering UPAuthModule::authenticate/ .. /Sending Inv +alid credential/) { while ($line = <$log>) {
    You end up entering the if when you don't want to, then skipping a whole bunch of lines that have nothing to do with UPAuthModule with the inner while

    Update: Even worse, the second m// in the above code matches against $_ instead of $line.

    if ($line =~ /Entering UPAuthModule::authenticate/ .. /Sending Invalid credential/) { while ($line = <$log>) {
Re: problem in output
by toolic (Bishop) on Jun 29, 2009 at 14:52 UTC