Ika*_*ari 5 php error-handling parsing
好吧,我试图解析 PHP 错误日志。因此我构建了以下类:
<?php
/**
* Created by PhpStorm.
* User: toton
* Date: 2/29/2016
* Time: 8:16 AM
*/
final class error_parser
{
private $log_file_path;
private $current_line;
private $recent;
/**
* error_parser constructor.
* Takes in the path of the error log file of PHP ERROR LOG FILE.
* And another param for checking to get the direction to traverse the file.
* @param string $log_file_path
* @param bool $recent
*/
public function __construct($log_file_path, $recent = true)
{
$this->log_file_path = $log_file_path;
$this->recent = $recent;
$this->_parse();
return true;
}
/**
* Parses the PHP ERROR LOG, and pushes an array with the following structure:
* array(
* "date" => {DATE},
* "severity" => {SEVERITY},
* "message" => {message},
* "stack_trace" => array(each({STACK_TRACE})) || false;
* );
* to the main array.
* !!!! IMPORTANT !!!!
* STACK TRACE IS NOT SUPPORTED AT THIS MOMENT
* TODO: IMPLEMENT STACK TRACE
* MILESTONE: NEXT_MAJOR RELEASE
*/
private function _parse() {
$contents = file_get_contents($this->log_file_path);
if(!$contents){
throw new Exception("Log file does not exist.", 2);
}
$lines = explode("\n", $contents);
if($this->recent) {
$lines = array_reverse($lines);
}
for($this->current_line = 0; $this->current_line < count($lines); $this->current_line++) {
parse_loop:
$current_line = trim($lines[$this->current_line]);
if(strlen($current_line) == 0) {
//If the line is empty throw it to the dustbin.
// SORRY, FOR THE GOTO.
// GOD PLEASE FORGIVE ME!
$this->current_line = $this->current_line + 1;
goto parse_loop;
}
if($current_line[0] != "[") {
// NOT SUPPORTING STACK TRACES AT THE MOMENT
$this->current_line = $this->current_line + 1;
goto parse_loop;
}
$dateArr = array();
preg_match('~^\[(.*?)\]~', $current_line, $dateArr);
$date = array(
"date" => explode(" ", $dateArr[1])[0],
"time" => explode(" ", $dateArr[1])[1]
);
$severity = "";
if(strpos($current_line, "PHP Warning")) {
$severity = "WARNING";
} elseif(strpos($current_line, "PHP Notice")) {
$severity = "NOTICE";
} elseif(strpos($current_line, "PHP Fatal error")) {
$severity = "FATAL";
} elseif(strpos($current_line, "PHP Parse error")) {
$severity = "SYNTAX_ERROR";
} else {
$severity = "UNIDENTIFIED_ERROR";
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(好吧,代码中可能有一些不好的做法:-P)
例如,一个错误可能是这样的 - [28-Dec-2015 07:51:31 UTC] PHP Warning: PHP Startup: Unable to load dynamic library 'C:\xampp\php\ext\php_pspell.dll' - The specified module could not be found.
无论如何,我能够提取错误的日期和类型。但是我找不到解析错误消息的方法。
所以我的问题是,如何从 PHP 错误日志中解析错误消息?
提前致谢,干杯!
我有点晚了,但这就是我的解决方案(它也支持堆栈跟踪):
<?php
use DateTime;
use DateTimeZone;
class ErrorLog {
private $logFilePath;
/**
* ErrorLog constructor.
*
* @param string $logFilePath
*/
public function __construct(string $logFilePath) {
$this->logFilePath = $logFilePath;
}
/**
* Parses the PHP error log to an array.
*
* @return \Generator
*/
public function getParsedLogFile(): \Generator {
$parsedLogs = [];
$logFileHandle = fopen($this->logFilePath, 'rb');
while (!feof($logFileHandle)) {
$currentLine = str_replace(PHP_EOL, '', fgets($logFileHandle));
// Normal error log line starts with the date & time in []
if ('[' === $currentLine[0]) {
if (10000 === \count($parsedLogs)) {
yield $parsedLogs;
$parsedLogs = [];
}
// Get the datetime when the error occurred and convert it to berlin timezone
try {
$dateArr = [];
preg_match('~^\[(.*?)\]~', $currentLine, $dateArr);
$currentLine = str_replace($dateArr[0], '', $currentLine);
$currentLine = trim($currentLine);
$errorDateTime = new DateTime($dateArr[1]);
$errorDateTime->setTimezone(new DateTimeZone('Europe/Berlin'));
$errorDateTime = $errorDateTime->format('Y-m-d H:i:s');
} catch (\Exception $e) {
$errorDateTime = '';
}
// Get the type of the error
if (false !== strpos($currentLine, 'PHP Warning')) {
$currentLine = str_replace('PHP Warning:', '', $currentLine);
$currentLine = trim($currentLine);
$errorType = 'WARNING';
} else if (false !== strpos($currentLine, 'PHP Notice')) {
$currentLine = str_replace('PHP Notice:', '', $currentLine);
$currentLine = trim($currentLine);
$errorType = 'NOTICE';
} else if (false !== strpos($currentLine, 'PHP Fatal error')) {
$currentLine = str_replace('PHP Fatal error:', '', $currentLine);
$currentLine = trim($currentLine);
$errorType = 'FATAL';
} else if (false !== strpos($currentLine, 'PHP Parse error')) {
$currentLine = str_replace('PHP Parse error:', '', $currentLine);
$currentLine = trim($currentLine);
$errorType = 'SYNTAX';
} else if (false !== strpos($currentLine, 'PHP Exception')) {
$currentLine = str_replace('PHP Exception:', '', $currentLine);
$currentLine = trim($currentLine);
$errorType = 'EXCEPTION';
} else {
$errorType = 'UNKNOWN';
}
if (false !== strpos($currentLine, ' on line ')) {
$errorLine = explode(' on line ', $currentLine);
$errorLine = trim($errorLine[1]);
$currentLine = str_replace(' on line ' . $errorLine, '', $currentLine);
} else {
$errorLine = substr($currentLine, strrpos($currentLine, ':') + 1);
$currentLine = str_replace(':' . $errorLine, '', $currentLine);
}
$errorFile = explode(' in /', $currentLine);
$errorFile = '/' . trim($errorFile[1]);
$currentLine = str_replace(' in ' . $errorFile, '', $currentLine);
// The message of the error
$errorMessage = trim($currentLine);
$parsedLogs[] = [
'dateTime' => $errorDateTime,
'type' => $errorType,
'file' => $errorFile,
'line' => (int)$errorLine,
'message' => $errorMessage,
'stackTrace' => []
];
} // Stack trace beginning line
else if ('Stack trace:' === $currentLine) {
$stackTraceLineNumber = 0;
while (!feof($logFileHandle)) {
$currentLine = str_replace(PHP_EOL, '', fgets($logFileHandle));
// If the current line is a stack trace line
if ('#' === $currentLine[0]) {
$parsedLogsLastKey = key($parsedLogs);
$currentLine = str_replace('#' . $stackTraceLineNumber, '', $currentLine);
$parsedLogs[$parsedLogsLastKey]['stackTrace'][] = trim($currentLine);
$stackTraceLineNumber++;
} // If the current line is the last stack trace ('thrown in...')
else {
break;
}
}
}
}
yield $parsedLogs;
}
}
Run Code Online (Sandbox Code Playgroud)