Skip to content

Commit 364ac02

Browse files
committed
Refactor exception logging
1 parent d76e2a2 commit 364ac02

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

system/Debug/Exceptions.php

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,11 @@ public function exceptionHandler(Throwable $exception)
102102
[$statusCode, $exitCode] = $this->determineCodes($exception);
103103

104104
if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) {
105-
log_message('critical', $exception->getMessage() . "\n{trace}", [
106-
'trace' => $exception->getTraceAsString(),
105+
log_message('critical', "{message}\nin {exFile} on line {exLine}.\n{trace}", [
106+
'message' => $exception->getMessage(),
107+
'exFile' => clean_path($exception->getFile()), // {file} refers to THIS file
108+
'exLine' => $exception->getLine(), // {line} refers to THIS line
109+
'trace' => self::renderBacktrace($exception->getTrace()),
107110
]);
108111
}
109112

@@ -430,4 +433,52 @@ public static function highlightFile(string $file, int $lineNumber, int $lines =
430433

431434
return '<pre><code>' . $out . '</code></pre>';
432435
}
436+
437+
private static function renderBacktrace(array $backtrace): string
438+
{
439+
$backtraces = [];
440+
441+
foreach ($backtrace as $index => $trace) {
442+
$frame = $trace + ['file' => '[internal function]', 'line' => '', 'class' => '', 'type' => '', 'args' => []];
443+
444+
if ($frame['file'] !== '[internal function]') {
445+
$frame['file'] = sprintf('%s(%s)', $frame['file'], $frame['line']);
446+
}
447+
448+
unset($frame['line']);
449+
$idx = $index;
450+
$idx = str_pad((string) ++$index, 2, ' ', STR_PAD_LEFT);
451+
452+
$args = implode(', ', array_map(static function ($value): string {
453+
switch (true) {
454+
case is_object($value):
455+
return sprintf('Object(%s)', get_class($value));
456+
457+
case is_array($value):
458+
return $value !== [] ? '[...]' : '[]';
459+
460+
case $value === null:
461+
return 'null';
462+
463+
case is_resource($value):
464+
return sprintf('resource (%s)', get_resource_type($value));
465+
466+
default:
467+
return var_export($value, true);
468+
}
469+
}, $frame['args']));
470+
471+
$backtraces[] = sprintf(
472+
'%s %s: %s%s%s(%s)',
473+
$idx,
474+
clean_path($frame['file']),
475+
$frame['class'],
476+
$frame['type'],
477+
$frame['function'],
478+
$args
479+
);
480+
}
481+
482+
return implode("\n", $backtraces);
483+
}
433484
}

tests/system/Debug/ExceptionsTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,22 @@ public function testDetermineCodes(): void
6262
$this->assertSame([404, 1], $determineCodes(new RuntimeException('There.', 404)));
6363
}
6464

65+
public function testRenderBacktrace(): void
66+
{
67+
$renderer = self::getPrivateMethodInvoker(Exceptions::class, 'renderBacktrace');
68+
$exception = new RuntimeException('This.');
69+
70+
$renderedBacktrace = $renderer($exception->getTrace());
71+
$renderedBacktrace = explode("\n", $renderedBacktrace);
72+
73+
foreach ($renderedBacktrace as $trace) {
74+
$this->assertMatchesRegularExpression(
75+
'/^\s*\d* .+(?:\(\d+\))?: \S+(?:(?:\->|::)\S+)?\(.*\)$/',
76+
$trace
77+
);
78+
}
79+
}
80+
6581
/**
6682
* @dataProvider dirtyPathsProvider
6783
*/

0 commit comments

Comments
 (0)