Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15511324
D13007.id31366.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
3 KB
Referenced Files
None
Subscribers
None
D13007.id31366.diff
View Options
diff --git a/src/error/PhutilErrorHandler.php b/src/error/PhutilErrorHandler.php
--- a/src/error/PhutilErrorHandler.php
+++ b/src/error/PhutilErrorHandler.php
@@ -251,7 +251,7 @@
array(
'file' => $ex->getFile(),
'line' => $ex->getLine(),
- 'trace' => self::getRootException($ex)->getTrace(),
+ 'trace' => self::getExceptionTrace($ex),
'catch_trace' => debug_backtrace(),
));
@@ -302,6 +302,11 @@
foreach ($trace as $key => $entry) {
$line = ' #'.$key.' ';
+ if (!empty($entry['xid'])) {
+ if ($entry['xid'] != 1) {
+ $line .= '<#'.$entry['xid'].'> ';
+ }
+ }
if (isset($entry['class'])) {
$line .= $entry['class'].'::';
}
@@ -383,7 +388,7 @@
$metadata['default_message'] = $default_message;
error_log($default_message);
- self::outputStacktrace(self::getRootException($value)->getTrace());
+ self::outputStacktrace($metadata['trace']);
break;
case self::PHLOG:
$default_message = sprintf(
@@ -517,4 +522,75 @@
return $libinfo;
}
+ /**
+ * Get a full trace across all proxied and aggregated exceptions.
+ *
+ * This attempts to build a set of stack frames which completely represent
+ * all of the places an exception came from, even if it came from multiple
+ * origins and has been aggregated or proxied.
+ *
+ * @param Exception Exception to retrieve a trace for.
+ * @return list<wild> List of stack frames.
+ */
+ public static function getExceptionTrace(Exception $ex) {
+ $id = 1;
+
+ // Keep track of discovered exceptions which we need to build traces for.
+ $stack = array(
+ array($id, $ex),
+ );
+
+ $frames = array();
+ while ($info = array_shift($stack)) {
+ list($xid, $ex) = $info;
+
+ // We're going from top-level exception down in bredth-first order, but
+ // want to build a trace in approximately standard order (deepest part of
+ // the call stack to most shallow) so we need to reverse each list of
+ // frames and then reverse everything at the end.
+
+ $ex_frames = array_reverse($ex->getTrace());
+ $ex_frames = array_values($ex_frames);
+ $last_key = (count($ex_frames) - 1);
+ foreach ($ex_frames as $frame_key => $frame) {
+ $frame['xid'] = $xid;
+
+ // If this is a child/previous exception and we're on the deepest frame
+ // and missing file/line data, fill it in from the exception itself.
+ if ($xid > 1 && ($frame_key == $last_key)) {
+ if (empty($frame['file'])) {
+ $frame['file'] = $ex->getFile();
+ $frame['line'] = $ex->getLine();
+ }
+ }
+
+ // Since the exceptions are likely to share the most shallow frames,
+ // try to add those to the trace only once.
+ if (isset($frame['file']) && isset($frame['line'])) {
+ $signature = $frame['file'].':'.$frame['line'];
+ if (empty($frames[$signature])) {
+ $frames[$signature] = $frame;
+ }
+ } else {
+ $frames[] = $frame;
+ }
+ }
+
+ // If this is a proxy exception, add the proxied exception.
+ $prev = self::getPreviousException($ex);
+ if ($prev) {
+ $stack[] = array(++$id, $prev);
+ }
+
+ // If this is an aggregate exception, add the child exceptions.
+ if ($ex instanceof PhutilAggregateException) {
+ foreach ($ex->getExceptions() as $child) {
+ $stack[] = array(++$id, $child);
+ }
+ }
+ }
+
+ return array_values(array_reverse($frames));
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 18, 1:25 AM (1 w, 6 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7706506
Default Alt Text
D13007.id31366.diff (3 KB)
Attached To
Mode
D13007: Automatically compile aggregate stack traces for complex exceptions
Attached
Detach File
Event Timeline
Log In to Comment