2016-08-12 132 views
0

我在做它记录以下方式日志文件标记:PHP获得数按从文本文件

[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 

我努力使可以读取日志文件中总报警和总误差函数。以下代码正常工作。问题是:有没有更好的方法来做到这一点?

$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"; 
+0

不应该是这样的:'echo $ totalWarnings/$ totalErrors;'? – Ivan

+0

@Ivan为什么?他只是输出数字,而不是试图去分割它们。 –

+3

我投票结束这个问题作为题外话,因为OP是要求改进工作代码 – RamRaider

回答

2

日志文件可能会相当大。函数file将整个文件读入内存。如果文件非常大,那么PHP可能会耗尽内存,并且会出现错误。

为了避免耗尽内存,您可以使用fopen获取文件句柄,然后读取一行在同一时间使用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); 
+0

我用你的代码替换了我的代码,它的工作正常。请你详细说明为什么fopen()更好,然后file()也可以帮助其他人。 – danny

+1

将整个日志文件读入内存将在内存过大时停止工作。一次读取一行可确保只使用少量内存。 –

2

取决于你可能允许在错误信息,你的方法可能会或可能不会产生比实际日志行更多的错误/警告,因为您只查找每行中的子字符串匹配。如此一条登录线[08-12-2016 22:59:38.000000] [Error] Testing [warning]对单行产生1个错误和1个警告。

您可以尝试使用正则表达式来更加勤奋。

$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"; 
0

可以以计数字符串中的字符串匹配的数量使用PHP函数调用substr_count()

$logs = file($complete_filename); 

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

echo $totalWarnings . ' warnings and ' . $totalErrors . ' errors';