1
0
mirror of https://github.com/danog/parallel.git synced 2024-11-30 04:39:01 +01:00

Serialize exception trace arguments in child processes and threads

This commit is contained in:
Aaron Piotrowski 2020-02-10 12:33:55 -06:00
parent 4ed05f6aac
commit 0597620f56
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
5 changed files with 118 additions and 7 deletions

View File

@ -38,6 +38,8 @@
"Amp\\Parallel\\": "lib"
},
"files": [
"lib/Context/functions.php",
"lib/Sync/functions.php",
"lib/Worker/functions.php"
]
},

33
lib/Context/functions.php Normal file
View File

@ -0,0 +1,33 @@
<?php
namespace Amp\Parallel\Context;
use Amp\Promise;
/**
* @param string|string[] $script
*
* @return Context
*/
function create($script): Context
{
if (Parallel::isSupported()) {
return new Parallel($script);
}
return new Process($script);
}
/**
* @param string|string[] $script
*
* @return Promise<Context>
*/
function run($script): Promise
{
if (Parallel::isSupported()) {
return Parallel::run($script);
}
return Process::run($script);
}

View File

@ -13,7 +13,7 @@ final class ExitFailure implements ExitResult
/** @var int|string */
private $code;
/** @var array */
/** @var string[] */
private $trace;
/** @var self|null */
@ -24,7 +24,7 @@ final class ExitFailure implements ExitResult
$this->type = \get_class($exception);
$this->message = $exception->getMessage();
$this->code = $exception->getCode();
$this->trace = $exception->getTraceAsString();
$this->trace = flattenThrowableBacktrace($exception);
if ($previous = $exception->getPrevious()) {
$this->previous = new self($previous);
@ -53,7 +53,7 @@ final class ExitFailure implements ExitResult
$this->code,
PanicError::class
),
$this->trace,
\implode("\n", $this->trace),
$previous
);
}

75
lib/Sync/functions.php Normal file
View File

@ -0,0 +1,75 @@
<?php
namespace Amp\Parallel\Sync;
/**
* @param \Throwable $exception
*
* @return string[] Serializable array of strings representing the exception backtrace including function arguments.
*/
function flattenThrowableBacktrace(\Throwable $exception): array
{
$output = [];
$counter = 0;
$trace = $exception->getTrace();
foreach ($trace as $call) {
if (isset($call['class'])) {
$name = $call['class'] . $call['type'] . $call['function'];
} else {
$name = $call['function'];
}
$args = \implode(', ', \array_map(__NAMESPACE__ . '\\flattenArgument', $call['args']));
$output[] = \sprintf(
'#%d %s(%d): %s(%s)',
$counter++,
$call['file'] ?? '[internal function]',
$call['line'] ?? 0,
$name,
$args
);
}
return $output;
}
/**
* @param mixed $value
*
* @return string Serializable string representation of $value for backtraces.
*/
function flattenArgument($value): string
{
if ($value instanceof \Closure) {
$closureReflection = new \ReflectionFunction($value);
return \sprintf(
'Closure(%s:%s)',
$closureReflection->getFileName(),
$closureReflection->getStartLine()
);
}
if (\is_object($value)) {
return \sprintf('Object(%s)', \get_class($value));
}
if (\is_array($value)) {
return 'Array([' . \implode(', ', \array_map(__FUNCTION__, $value)) . '])';
}
if (\is_resource($value)) {
return \sprintf('Resource(%s)', \get_resource_type($value));
}
if (\is_string($value)) {
return '"' . $value . '"';
}
if (\is_null($value)) {
return 'null';
}
return (string) $value;
}

View File

@ -3,6 +3,7 @@
namespace Amp\Parallel\Worker\Internal;
use Amp\Failure;
use Amp\Parallel\Sync;
use Amp\Parallel\Worker\TaskError;
use Amp\Parallel\Worker\TaskException;
use Amp\Promise;
@ -25,7 +26,7 @@ final class TaskFailure extends TaskResult
/** @var int|string */
private $code;
/** @var array */
/** @var string[] */
private $trace;
/** @var self|null */
@ -38,7 +39,7 @@ final class TaskFailure extends TaskResult
$this->parent = $exception instanceof \Error ? self::PARENT_ERROR : self::PARENT_EXCEPTION;
$this->message = $exception->getMessage();
$this->code = $exception->getCode();
$this->trace = $exception->getTraceAsString();
$this->trace = Sync\flattenThrowableBacktrace($exception);
if ($previous = $exception->getPrevious()) {
$this->previous = new self($id, $previous);
@ -61,7 +62,7 @@ final class TaskFailure extends TaskResult
return new TaskError(
$this->type,
\sprintf($format, $this->type, $this->message, $this->code, TaskError::class),
$this->trace,
\implode("\n", $this->trace),
$previous
);
}
@ -69,7 +70,7 @@ final class TaskFailure extends TaskResult
return new TaskException(
$this->type,
\sprintf($format, $this->type, $this->message, $this->code, TaskException::class),
$this->trace,
\implode("\n", $this->trace),
$previous
);
}