Add ExceptionLogUtil to parse the exception logs
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 5 Mar 2019 13:24:08 +0000 (14:24 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 5 Mar 2019 13:24:08 +0000 (14:24 +0100)
wcfsetup/install/files/acp/templates/exceptionLogView.tpl
wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php
wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php [new file with mode: 0644]

index 9c99c36699c81c97678454708aef7166513007a7..fbd26c71fcc99833c452365efe2aa536affe0234 100644 (file)
@@ -79,7 +79,7 @@
                                
                                <dl>
                                        <dt>{lang}wcf.acp.exceptionLog.exception.date{/lang}</dt>
-                                       <dd>{$exception[date]|strtotime|plainTime}</dd>
+                                       <dd>{$exception[date]|plainTime}</dd>
                                </dl>
                                
                                <dl>
index c4c9a28c0494090ea5b80c0ebfe9b06df49e6e15..d5cc42c700edf82221bea2461d68dc0c80847e5c 100644 (file)
@@ -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<date>[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<message>.*?)\s*\n".
-"PHP version: (?P<phpVersion>.*?)\s*\n".
-"WoltLab Suite version: (?P<wcfVersion>.*?)\s*\n".
-"Request URI: (?P<requestURI>.*?)\s*\n".
-"Referrer: (?P<referrer>.*?)\s*\n".
-"User Agent: (?P<userAgent>.*?)\s*\n".
-"Peak Memory Usage: (?<peakMemory>\d+)/(?<maxMemory>(?:\d+|-1))\s*\n".
-"(?<chain>======\n".
-".*)", Regex::DOT_ALL);
-               $chainRegex = new Regex("======\n".
-"Error Class: (?P<class>.*?)\s*\n".
-"Error Message: (?P<message>.*?)\s*\n".
-"Error Code: (?P<code>\d+)\s*\n".
-"File: (?P<file>.*?) \((?P<line>\d+)\)\s*\n".
-"Extra Information: (?P<information>(?:-|[a-zA-Z0-9+/]+={0,2}))\s*\n".
-"Stack Trace: (?P<stack>\[[^\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 (file)
index 0000000..3cc6392
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+namespace wcf\util;
+use wcf\system\Regex;
+
+/**
+ * Contains header-related functions.
+ * 
+ * @author     Tim Duesterhus
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @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<date>[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<message>.*?)\s*\n".
+                       "PHP version: (?P<phpVersion>.*?)\s*\n".
+                       "WoltLab Suite version: (?P<wcfVersion>.*?)\s*\n".
+                       "Request URI: (?P<requestURI>.*?)\s*\n".
+                       "Referrer: (?P<referrer>.*?)\s*\n".
+                       "User Agent: (?P<userAgent>.*?)\s*\n".
+                       "Peak Memory Usage: (?<peakMemory>\d+)/(?<maxMemory>(?:\d+|-1))\s*\n".
+                       "(?<chain>======\n".
+                       ".*)", Regex::DOT_ALL);
+                       $chainRegex = new Regex("======\n".
+                       "Error Class: (?P<class>.*?)\s*\n".
+                       "Error Message: (?P<message>.*?)\s*\n".
+                       "Error Code: (?P<code>\d+)\s*\n".
+                       "File: (?P<file>.*?) \((?P<line>\d+)\)\s*\n".
+                       "Extra Information: (?P<information>(?:-|[a-zA-Z0-9+/]+={0,2}))\s*\n".
+                       "Stack Trace: (?P<stack>\[[^\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
+       }
+}