From 4c393c5ad07ca1a68e13ef06108ce20e2c423828 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 5 Mar 2019 14:24:08 +0100 Subject: [PATCH] Add ExceptionLogUtil to parse the exception logs --- .../files/acp/templates/exceptionLogView.tpl | 2 +- .../acp/page/ExceptionLogViewPage.class.php | 60 ++---------- .../files/lib/util/ExceptionLogUtil.class.php | 98 +++++++++++++++++++ 3 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php diff --git a/wcfsetup/install/files/acp/templates/exceptionLogView.tpl b/wcfsetup/install/files/acp/templates/exceptionLogView.tpl index 9c99c36699..fbd26c71fc 100644 --- a/wcfsetup/install/files/acp/templates/exceptionLogView.tpl +++ b/wcfsetup/install/files/acp/templates/exceptionLogView.tpl @@ -79,7 +79,7 @@
{lang}wcf.acp.exceptionLog.exception.date{/lang}
-
{$exception[date]|strtotime|plainTime}
+
{$exception[date]|plainTime}
diff --git a/wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php b/wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php index c4c9a28c04..d5cc42c700 100644 --- a/wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php +++ b/wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php @@ -8,7 +8,7 @@ use wcf\system\Regex; use wcf\system\request\LinkHandler; use wcf\system\WCF; use wcf\util\DirectoryUtil; -use wcf\util\JSON; +use wcf\util\ExceptionLogUtil; use wcf\util\StringUtil; /** @@ -123,24 +123,10 @@ class ExceptionLogViewPage extends MultipleLinkPage { return; } - // unify newlines - $contents = StringUtil::unifyNewlines($contents); - - // split contents - $split = new Regex('(?:^|\n<<<<\n\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\n|$)'); - $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER); - - // even items become keys, odd items become values try { - $this->exceptions = call_user_func_array('array_merge', array_map( - function($v) { - return [$v[0] => $v[1]]; - }, - array_chunk($contents, 2) - )); + $this->exceptions = ExceptionLogUtil::splitLog($contents); } catch (\Exception $e) { - // logfile contents are pretty malformed, abort return; } @@ -151,23 +137,6 @@ class ExceptionLogViewPage extends MultipleLinkPage { $this->calculateNumberOfPages(); $i = 0; - $exceptionRegex = new Regex("(?P[MTWFS][a-z]{2}, \d{1,2} [JFMASOND][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4})\s*\n". -"Message: (?P.*?)\s*\n". -"PHP version: (?P.*?)\s*\n". -"WoltLab Suite version: (?P.*?)\s*\n". -"Request URI: (?P.*?)\s*\n". -"Referrer: (?P.*?)\s*\n". -"User Agent: (?P.*?)\s*\n". -"Peak Memory Usage: (?\d+)/(?(?:\d+|-1))\s*\n". -"(?======\n". -".*)", Regex::DOT_ALL); - $chainRegex = new Regex("======\n". -"Error Class: (?P.*?)\s*\n". -"Error Message: (?P.*?)\s*\n". -"Error Code: (?P\d+)\s*\n". -"File: (?P.*?) \((?P\d+)\)\s*\n". -"Extra Information: (?P(?:-|[a-zA-Z0-9+/]+={0,2}))\s*\n". -"Stack Trace: (?P\[[^\n]+\])", Regex::DOT_ALL); foreach ($this->exceptions as $key => $val) { $i++; @@ -175,29 +144,12 @@ class ExceptionLogViewPage extends MultipleLinkPage { unset($this->exceptions[$key]); continue; } - - if (!$exceptionRegex->match($val)) { + try { + $this->exceptions[$key] = ExceptionLogUtil::parseException($val); + } + catch (\InvalidArgumentException $e) { unset($this->exceptions[$key]); - continue; } - $matches = $exceptionRegex->getMatches(); - $chainRegex->match($matches['chain'], true, Regex::ORDER_MATCH_BY_SET); - - $chainMatches = array_map(function ($item) { - if ($item['information'] === '-') { - $item['information'] = null; - } - else { - $item['information'] = unserialize(base64_decode($item['information']), ['allowed_classes' => false]); - } - - $item['stack'] = JSON::decode($item['stack']); - - return $item; - }, $chainRegex->getMatches()); - - $matches['chain'] = $chainMatches; - $this->exceptions[$key] = $matches; } } diff --git a/wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php b/wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php new file mode 100644 index 0000000000..3cc6392f02 --- /dev/null +++ b/wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php @@ -0,0 +1,98 @@ + + * @package WoltLabSuite\Core\Util + * @since 5.2 + */ +final class ExceptionLogUtil { + /** + * Splits the given string of Exceptions into an array. + * + * @param string $contents + * @return string[] + */ + public static function splitLog($contents) { + // unify newlines + $contents = StringUtil::unifyNewlines($contents); + + // split contents + $split = new Regex('(?:^|\n<<<<\n\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\n|$)'); + $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER); + + // even items become keys, odd items become values + return array_merge(...array_map( + function($v) { + return [$v[0] => $v[1]]; + }, + array_chunk($contents, 2) + )); + } + + /** + * Parses the given log entry. + * + * @param string $entry + * @return mixed[] + */ + public static function parseException($entry) { + static $regex = null; + static $chainRegex = null; + if ($regex === null || $chainRegex === NULL) { + $regex = new Regex("(?P[MTWFS][a-z]{2}, \d{1,2} [JFMASOND][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4})\s*\n". + "Message: (?P.*?)\s*\n". + "PHP version: (?P.*?)\s*\n". + "WoltLab Suite version: (?P.*?)\s*\n". + "Request URI: (?P.*?)\s*\n". + "Referrer: (?P.*?)\s*\n". + "User Agent: (?P.*?)\s*\n". + "Peak Memory Usage: (?\d+)/(?(?:\d+|-1))\s*\n". + "(?======\n". + ".*)", Regex::DOT_ALL); + $chainRegex = new Regex("======\n". + "Error Class: (?P.*?)\s*\n". + "Error Message: (?P.*?)\s*\n". + "Error Code: (?P\d+)\s*\n". + "File: (?P.*?) \((?P\d+)\)\s*\n". + "Extra Information: (?P(?:-|[a-zA-Z0-9+/]+={0,2}))\s*\n". + "Stack Trace: (?P\[[^\n]+\])", Regex::DOT_ALL); + } + + if (!$regex->match($entry)) { + throw new \InvalidArgumentException('The given entry is malformed'); + } + $matches = $regex->getMatches(); + $chainRegex->match($matches['chain'], true, Regex::ORDER_MATCH_BY_SET); + + $chainMatches = array_map(function ($item) { + if ($item['information'] === '-') { + $item['information'] = null; + } + else { + $item['information'] = unserialize(base64_decode($item['information']), ['allowed_classes' => false]); + } + + $item['stack'] = JSON::decode($item['stack']); + + return $item; + }, $chainRegex->getMatches()); + + $matches['date'] = strtotime($matches['date']); + $matches['chain'] = $chainMatches; + + return $matches; + } + + /** + * Forbid creation of ExceptionLogUtil objects. + */ + private function __construct() { + // does nothing + } +} -- 2.20.1