2016-08-12 56 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';