0

I am making a log file which logs in the following manner:

[08-12-2016 22:59:38.000000] [Error] Testing
[08-12-2016 22:59:45.000000] [Error] Testing
[08-12-2016 23:03:37.000000] [warning] Testing

I am trying to make a function which can read total warning and total errors in log file. The following code works fine. The question is: Is there a better way to do this?

$file = file( $complete_filename );

$totalErrors = 0;
$totalWarnings = 0;

foreach($file as $rows) {

  if(strpos( $rows,  "[warning]")) $totalWarnings ++;
  if(strpos( $rows,  "[Error]"))   $totalErrors ++;

}

echo "$totalWarnings/$totalErrors";
Pablo
  • 4,821
  • 12
  • 52
  • 82
danny
  • 407
  • 1
  • 5
  • 10

3 Answers3

2

Log files can get pretty large. The file function reads the entire file into memory. If the file is very large then PHP may run out of memory and you will get an error.

To avoid running out of memory you can use fopen to get a file handle and then read one line at a time using fgets:

$totalErrors = 0;
$totalWarnings = 0;

$fh = fopen($complete_filename, 'rb');

if ($fh) {
    while (($line = fgets($fh, 4096)) !== false) {
        if (strpos($line, "[Error]") !== false) {
            $totalErrors++;
        }
        if (strpos($line, "[warning]") !== false) {
            $totalWarnings++;
        }
    }
}
fclose($fh);
Sverri M. Olsen
  • 13,055
  • 3
  • 36
  • 52
  • I have replaced my code with yours and its working fine. can you please elaborate why fopen() is better then file() that might help others too. – danny Aug 12 '16 at 23:41
  • 1
    Reading the entire log file into memory will stop working when it gets too big to fit into memory. Reading one line at a time ensures that only a small amount of memory will be used. – Sverri M. Olsen Aug 13 '16 at 00:04
2

Depending on what you may allow in the error message, your approach may or may not yield more errors/warnings than there are actual log lines, because you're only looking for the substring match in each line. Such that a log line of [08-12-2016 22:59:38.000000] [Error] Testing [warning] yields both 1 error and 1 warning for a single line.

You could try using a regular expression instead to be more diligent.

$logResults = array_map(function($line) {
    if (preg_match('/\[.*\]\s\[(Error|warning)\]/', $line, $match)) {
        return $match[1];
    }
}, file($logFileName));

$errors = array_filter($logResults, function($l) { return $l === 'Error'; });
$warnings = array_filter($logResults, function($l) { return $l === 'warning'; });

echo "Number of errors: $errors\n";
echo "Number of warnings: $warnings\n";
Sherif
  • 11,786
  • 3
  • 32
  • 57
0

You can use a PHP function call substr_count() in order to count the number of string match inside a string.

$logs = file( $complete_filename );

$totalErrors = substr_count($logs, '[Error]');
$totalWarnings = substr_count($logs, '[warning]');

echo $totalWarnings . ' warnings and ' . $totalErrors . ' errors';
Ivan
  • 34,531
  • 8
  • 55
  • 100