Adapt ExceptionLogViewPage
authorTim Düsterhus <duesterhus@woltlab.com>
Tue, 1 Dec 2015 22:28:55 +0000 (23:28 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Tue, 1 Dec 2015 22:38:21 +0000 (23:38 +0100)
wcfsetup/install/files/acp/templates/exceptionLogView.tpl
wcfsetup/install/files/lib/acp/page/ExceptionLogViewPage.class.php
wcfsetup/install/files/lib/core.functions.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 1626fdebe165b0ebb8007853445f9cda05925534..ae2d43ae80e022e504f68ef6e1df6b9862171aaa 100644 (file)
                                                <dd>{$exception[date]|strtotime|plainTime}</dd>
                                        </dl>
                                        
-                                       <dl>
-                                               <dt>{lang}wcf.acp.exceptionLog.exception.file{/lang}</dt>
-                                               <dd>{$exception[file]} ({$exception[line]})</dd>
-                                       </dl>
                                        <dl>
                                                <dt>{lang}wcf.acp.exceptionLog.exception.requestURI{/lang}</dt>
                                                <dd>{$exception[requestURI]}</dd>
                                                <dt>{lang}wcf.acp.exceptionLog.exception.userAgent{/lang}</dt>
                                                <dd>{$exception[userAgent]}</dd>
                                        </dl>
-                                       {if $exception[information]}
-                                               <dl>
-                                                       <dt>{lang}wcf.acp.exceptionLog.exception.information{/lang}</dt>
-                                                       <dd>{@$exception[information]}</dd>
-                                               </dl>
-                                       {/if}
+                                       <dl>
+                                               <dt>{lang}wcf.acp.exceptionLog.exception.memory{/lang}</dt>
+                                               <dd>{$exception[peakMemory]|filesizeBinary} / {$exception[maxMemory]|filesizeBinary}</dd>
+                                       </dl>
+                                       {foreach from=$exception[chain] item=chain}
+                                       <dl>
+                                               <dt>{lang}wcf.acp.exceptionLog.exception.message{/lang}</dt>
+                                               <dd>{$chain[message]}</dd>
+                                       </dl>
+                                       <dl>
+                                               <dt>{lang}wcf.acp.exceptionLog.exception.class{/lang}</dt>
+                                               <dd>{$chain[class]}</dd>
+                                       </dl>
+                                       <dl>
+                                               <dt>{lang}wcf.acp.exceptionLog.exception.file{/lang}</dt>
+                                               <dd>{$chain[file]} ({$chain[line]})</dd>
+                                       </dl>
                                        <dl>
                                                <dt>{lang}wcf.acp.exceptionLog.exception.stacktrace{/lang}</dt>
-                                               <dd class="monospace" style="word-wrap: wrap-all; word-break: break-all;">
-                                                       <ul>
-                                                               <li>{@"</li><li>"|implode:$exception[stacktrace]}</li>
+                                               <dd>
+                                                       <ol start="0" class="nativeList">
+                                                               {foreach from=$chain[stack] item=stack}
+                                                               <li>{$stack[file]} ({$stack[line]}): {$stack[class]}{$stack[type]}{$stack[function]}(&hellip;)</li>
+                                                               {/foreach}
                                                        </ul>
                                                </dd>
                                        </dl>
+                                       {/foreach}
                                        <dl>
                                                <dt><label for="copyException{$exceptionKey}">{lang}wcf.acp.exceptionLog.exception.copy{/lang}</label></dt>
                                                <dd><textarea id="copyException{$exceptionKey}" rows="5" cols="40" class="jsCopyException" readonly="readonly">{$exception[0]}</textarea></dd>
index 03f8e279128615d6f8f8261bc70664ca17b24309..e1edef30cf5341b2903505bbb015c451a9c59342 100644 (file)
@@ -135,17 +135,23 @@ class ExceptionLogViewPage extends MultipleLinkPage {
                
                $i = 0;
                // TODO: This needs to be adapted for WCF 2.2
-               $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})
-Message: (?P<message>.*?)
-File: (?P<file>.*?) \((?P<line>\d+)\)
-PHP version: (?P<phpVersion>.*?)
-WCF version: (?P<wcfVersion>.*?)
-Request URI: (?P<requestURI>.*?)
-Referrer: (?P<referrer>.*?)
-User-Agent: (?P<userAgent>.*?)
-Information: (?P<information>.*?)
-Stacktrace: 
-(?P<stacktrace>.*)', Regex::DOT_ALL);
+               $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*
+Message: (?P<message>.*?)\s*
+PHP version: (?P<phpVersion>.*?)\s*
+WCF version: (?P<wcfVersion>.*?)\s*
+Request URI: (?P<requestURI>.*?)\s*
+Referrer: (?P<referrer>.*?)\s*
+User Agent: (?P<userAgent>.*?)\s*
+Peak Memory Usage: (?<peakMemory>\d+)/(?<maxMemory>\d+)\s*
+(?<chain>======
+.*)', Regex::DOT_ALL);
+               $chainRegex = new Regex('======
+Error Class: (?P<class>.*?)\s*
+Error Message: (?P<message>.*?)\s*
+Error Code: (?P<code>\d+)\s*
+File: (?P<file>.*?) \((?P<line>\d+)\)\s*
+Extra Information: (?P<information>(?:-|[a-zA-Z0-9+/]+={0,2}))\s*
+Stack Trace: (?P<stack>[a-zA-Z0-9+/]+={0,2})', Regex::DOT_ALL);
                $stackTraceFormatter = new Regex('^\s+(#\d+)', Regex::MULTILINE);
                foreach ($this->exceptions as $key => $val) {
                        $i++;
@@ -158,10 +164,20 @@ Stacktrace:
                                unset($this->exceptions[$key]);
                                continue;
                        }
+                       $matches = $exceptionRegex->getMatches();
+                       $chainRegex->match($matches['chain'], true, Regex::ORDER_MATCH_BY_SET);
                        
-                       $this->exceptions[$key] = $exceptionRegex->getMatches();
-                       $this->exceptions[$key]['stacktrace'] = explode("\n", $stackTraceFormatter->replace(StringUtil::encodeHTML($this->exceptions[$key]['stacktrace']), '<strong>\\1</strong>'));
-                       $this->exceptions[$key]['information'] = JSON::decode($this->exceptions[$key]['information']);
+                       $chainMatches = array_map(function ($item) {
+                               if ($item['information'] === '-') $item['information'] = null;
+                               else $item['information'] = @unserialize(base64_decode($item['information']));
+                               
+                               $item['stack'] = @unserialize(base64_decode($item['stack']));
+                               
+                               return $item;
+                       }, $chainRegex->getMatches());
+                       
+                       $matches['chain'] = $chainMatches;
+                       $this->exceptions[$key] = $matches;
                }
        }
        
index f9b45b1083aff63fcd5d67c4de0497e10a1f20dc..62092c8aecb323c5958a2dc1e7ae6d53d972b0d8 100644 (file)
@@ -8,7 +8,7 @@
  */
 namespace {
        use wcf\system\WCF;
-       
+
        // set exception handler
        set_exception_handler([ WCF::class, 'handleException' ]);
        // set php error handler
@@ -17,12 +17,12 @@ namespace {
        register_shutdown_function([ WCF::class, 'destruct' ]);
        // set autoload function
        spl_autoload_register([ WCF::class, 'autoload' ]);
-       
+
        // define escape string shortcut
        function escapeString($string) {
                return WCF::getDB()->escapeString($string);
        }
-       
+
        // define DOCUMENT_ROOT on IIS if not set
        if (PHP_EOL == "\r\n") {
                if (!isset($_SERVER['DOCUMENT_ROOT']) && isset($_SERVER['SCRIPT_FILENAME'])) {
@@ -31,7 +31,7 @@ namespace {
                if (!isset($_SERVER['DOCUMENT_ROOT']) && isset($_SERVER['PATH_TRANSLATED'])) {
                        $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0 - strlen($_SERVER['PHP_SELF'])));
                }
-               
+
                if (!isset($_SERVER['REQUEST_URI'])) {
                        $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'], 1);
                        if (isset($_SERVER['QUERY_STRING'])) {
@@ -47,11 +47,11 @@ namespace wcf\functions\exception {
        use wcf\system\WCF;
        use wcf\util\FileUtil;
        use wcf\util\StringUtil;
-       
+
        function logThrowable($e) {
                $logFile = WCF_DIR . 'log/' . gmdate('Y-m-d', TIME_NOW) . '.txt';
                touch($logFile);
-               
+
                // don't forget to update ExceptionLogViewPage, when changing the log file format
                $message = gmdate('r', TIME_NOW)."\n".
                        'Message: '.str_replace("\n", ' ', $e->getMessage())."\n".
@@ -81,20 +81,20 @@ namespace wcf\functions\exception {
                                                        return $item;
                                        }
                                }, $item['args']);
-                               
+
                                return $item;
                        }, sanitizeStacktrace($e, true))))."\n";
                }
                while ($e = $e->getPrevious());
-               
+
                // calculate Exception-ID
                $exceptionID = sha1($message);
-               $entry = "<<<<<<<<".$exceptionID."<<<<\n".$message."<<<<\n";
-               
+               $entry = "<<<<<<<<".$exceptionID."<<<<\n".$message."<<<<\n\n";
+
                file_put_contents($logFile, $entry, FILE_APPEND);
                return $exceptionID;
        }
-       
+
        function printThrowable($e) {
                $exceptionID = logThrowable($e); // TODO
        ?><!DOCTYPE html>
@@ -201,10 +201,10 @@ namespace wcf\functions\exception {
                                                $message = str_replace('{$exceptionID}', $exceptionID, WCF::getLanguage()->get('wcf.global.error.exception', true));
                                        }
                                        catch (\Exception $e) {
-                                               
+
                                        }
                                        catch (\Throwable $e) {
-                                               
+
                                        }
                                        echo $message;
                                        ?>
@@ -241,7 +241,7 @@ namespace wcf\functions\exception {
                                                                ob_start();
                                                                $e->show();
                                                                ob_end_clean();
-                                                               
+
                                                                $reflection = new \ReflectionClass($e);
                                                                $property = $reflection->getProperty('information');
                                                                $property->setAccessible(true);
@@ -257,14 +257,7 @@ namespace wcf\functions\exception {
                                                        ?>
                                                        <dt>Stack Trace</dt>
                                                        <dd class="pre"><?php
-                                                               $trace = array_map(function ($item) {
-                                                                       if (!isset($item['file'])) $item['file'] = '[internal function]';
-                                                                       if (!isset($item['line'])) $item['line'] = '?';
-                                                                       if (!isset($item['class'])) $item['class'] = '';
-                                                                       if (!isset($item['type'])) $item['type'] = '';
-                                                                       
-                                                                       return $item;
-                                                               }, sanitizeStacktrace($e));
+                                                               $trace = sanitizeStacktrace($e);
                                                                $pathLength = array_reduce($trace, function ($carry, $item) {
                                                                        return max($carry, mb_strlen($item['file'].$item['line']));
                                                                }, 0) + 3;
@@ -310,33 +303,36 @@ namespace wcf\functions\exception {
 
        function sanitizeStacktrace($e, $ignorePaths = false) {
                $trace = $e->getTrace();
-               
+
                return array_map(function ($item) use ($ignorePaths) {
+                       if (!isset($item['file'])) $item['file'] = '[internal function]';
+                       if (!isset($item['line'])) $item['line'] = '?';
+                       if (!isset($item['class'])) $item['class'] = '';
+                       if (!isset($item['type'])) $item['type'] = '';
+                       
                        // strip database credentials
-                       if (isset($item['class'])) {
-                               if (preg_match('~\\\\?wcf\\\\system\\\\database\\\\[a-zA-Z]*Database~', $item['class']) || $item['class'] === 'PDO') {
-                                       if ($item['function'] === '__construct') {
-                                               $item['args'] = array_map(function () {
-                                                       return '[redacted]';
-                                               }, $item['args']);
-                                       }
+                       if (preg_match('~\\\\?wcf\\\\system\\\\database\\\\[a-zA-Z]*Database~', $item['class']) || $item['class'] === 'PDO') {
+                               if ($item['function'] === '__construct') {
+                                       $item['args'] = array_map(function () {
+                                               return '[redacted]';
+                                       }, $item['args']);
                                }
                        }
-                       
+
                        if (!$ignorePaths) {
                                $item['args'] = array_map(function ($item) {
                                        if (!is_string($item)) return $item;
-                                       
+
                                        if (preg_match('~^'.preg_quote($_SERVER['DOCUMENT_ROOT'], '~').'~', $item)) {
                                                $item = sanitizePath($item);
                                        }
-                                       
+
                                        return preg_replace('~^'.preg_quote(WCF_DIR, '~').'~', '*/', $item);
                                }, $item['args']);
-                               
-                               if (isset($item['file'])) $item['file'] = sanitizePath($item['file']);
+
+                               $item['file'] = sanitizePath($item['file']);
                        }
-                       
+
                        return $item;
                }, $trace);
        }
@@ -345,7 +341,7 @@ namespace wcf\functions\exception {
                if (WCF::debugModeIsEnabled() && defined('EXCEPTION_PRIVACY') && EXCEPTION_PRIVACY === 'public') {
                        return $path;
                }
-               
+
                return '*/'.FileUtil::removeTrailingSlash(FileUtil::getRelativePath(WCF_DIR, $path));
        }
 }
index 5dfa0906a6f59a59da5e839564f71ef38ff279d6..003e3d85ad88220b1a4604c4d6c0e3e4f7b6e8b1 100644 (file)
        
        <category name="wcf.acp.exceptionLog">
                <item name="wcf.acp.exceptionLog"><![CDATA[Protokollierte Fehler]]></item>
+               <item name="wcf.acp.exceptionLog.exception.message"><![CDATA[Fehlermeldung]]></item>
+               <item name="wcf.acp.exceptionLog.exception.class"><![CDATA[Art]]></item>
                <item name="wcf.acp.exceptionLog.exception.file"><![CDATA[Datei (Zeile)]]></item>
                <item name="wcf.acp.exceptionLog.exception.requestURI"><![CDATA[Aufgerufene URL]]></item>
                <item name="wcf.acp.exceptionLog.exception.referrer"><![CDATA[Referrer]]></item>
-               <item name="wcf.acp.exceptionLog.exception.information"><![CDATA[Zusatzinformationen]]></item>
                <item name="wcf.acp.exceptionLog.exception.stacktrace"><![CDATA[Stacktrace]]></item>
                <item name="wcf.acp.exceptionLog.exception.copy"><![CDATA[Fehlermeldung kopieren]]></item>
                <item name="wcf.acp.exceptionLog.exceptionNotFound"><![CDATA[Es wurde kein Fehler mit der ID „{$exceptionID}“ gefunden.]]></item>
index 8069a6de824b29146b6b98761141dc820c83a342..00801e80a344eafa2f556220ab44e1afad6fd86d 100644 (file)
@@ -248,10 +248,11 @@ Examples for medium ID detection:
        
        <category name="wcf.acp.exceptionLog">
                <item name="wcf.acp.exceptionLog"><![CDATA[Logged errors]]></item>
+               <item name="wcf.acp.exceptionLog.exception.message"><![CDATA[Error Message]]></item>
+               <item name="wcf.acp.exceptionLog.exception.class"><![CDATA[Type]]></item>
                <item name="wcf.acp.exceptionLog.exception.file"><![CDATA[File (Line)]]></item>
                <item name="wcf.acp.exceptionLog.exception.requestURI"><![CDATA[Requested URL]]></item>
                <item name="wcf.acp.exceptionLog.exception.referrer"><![CDATA[Referrer]]></item>
-               <item name="wcf.acp.exceptionLog.exception.information"><![CDATA[Additional information]]></item>
                <item name="wcf.acp.exceptionLog.exception.stacktrace"><![CDATA[Stacktrace]]></item>
                <item name="wcf.acp.exceptionLog.exception.copy"><![CDATA[Copy error message]]></item>
                <item name="wcf.acp.exceptionLog.exceptionNotFound"><![CDATA[No error with the ID “{$exceptionID}” was found.]]></item>