Skip to content

Commit 5fdd73a

Browse files
authored
Merge pull request #15 from VadymHrechukha/HP-2823_check_rcp_logs_for_kafka_message_processing_errors_after_release
HP-2823: modified Has Context Exception class to returns formatter message with context
2 parents e8ed3d0 + 6e3a5e8 commit 5fdd73a

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace hidev\Infrastructure\Exception;
6+
7+
use hidev\exception\HasContextInterface;
8+
9+
final class ExceptionDebugFormatter
10+
{
11+
public function format(\Throwable $e, bool $skipContext = false): array
12+
{
13+
$debugInfo = [
14+
'class' => \get_class($e),
15+
'message' => $e->getMessage(),
16+
'thrownAt' => $e->getFile() . ':' . $e->getLine(),
17+
];
18+
19+
if (!$skipContext && $e instanceof HasContextInterface) {
20+
$debugInfo = array_merge($debugInfo, [
21+
'context' => $e->getContext(),
22+
]);
23+
}
24+
25+
if ($root = $e->getPrevious()) {
26+
$debugInfo['parentException'] = $this->format($root, $skipContext);
27+
}
28+
return $debugInfo;
29+
}
30+
}

src/exception/HasContext.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace hidev\exception;
66

7+
use hidev\Infrastructure\Exception\ExceptionDebugFormatter;
78
use Throwable;
89
use yii\helpers\ArrayHelper;
910

@@ -37,4 +38,37 @@ public function getContextValue(string $fieldName)
3738
{
3839
return ArrayHelper::getValue($this->context, $fieldName, '');
3940
}
41+
42+
public function getFormattedContext(): string
43+
{
44+
$text = '';
45+
$context = $this->getContext();
46+
if ($previous = $this->getPrevious()) {
47+
$context['previousException'] = $this->getExceptionDebugInfo($previous);
48+
}
49+
50+
if ($context) {
51+
$text .= PHP_EOL . PHP_EOL . 'Context:';
52+
53+
foreach ($context as $key => $value) {
54+
$stringValue = is_array($value) || is_object($value)
55+
? $this->jsonEncode($value)
56+
: trim((string)$value);
57+
58+
$text .= PHP_EOL . '' . $key . ': ' . $stringValue;
59+
}
60+
}
61+
62+
return $text;
63+
}
64+
65+
private function getExceptionDebugInfo(?Throwable $throwable): array
66+
{
67+
return (new ExceptionDebugFormatter())->format($throwable);
68+
}
69+
70+
private function jsonEncode($value): string
71+
{
72+
return \json_encode($value, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT);
73+
}
4074
}

src/exception/HasContextInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ interface HasContextInterface extends \Throwable
77
public function addContext(array $data): self;
88

99
public function getContext(): array;
10+
11+
public function getFormattedContext(): string;
1012
}

tests/unit/exception/HasContextTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,59 @@ public function testGetContextValueReturnsDefaultWhenMissing(): void
5959

6060
$this->assertSame('', $e->getContextValue('missing.key'));
6161
}
62+
63+
// -----------------------------------------------------
64+
// getFormattedContext() Tests
65+
// -----------------------------------------------------
66+
67+
public function testGetFormattedContextReturnsEmptyStringWhenNoContext(): void
68+
{
69+
$e = new TestException('Error');
70+
71+
$this->assertSame('', $e->getFormattedContext());
72+
}
73+
74+
public function testGetFormattedContextFormatsSimpleContext(): void
75+
{
76+
$e = new TestException('Error');
77+
$e->addContext([
78+
'key' => 'value',
79+
'number' => 123,
80+
]);
81+
82+
$output = $e->getFormattedContext();
83+
84+
$this->assertStringContainsString('Context:', $output);
85+
$this->assertStringContainsString('key: value', $output);
86+
$this->assertStringContainsString('number: 123', $output);
87+
}
88+
89+
public function testGetFormattedContextFormatsArrayValuesAsJson(): void
90+
{
91+
$e = new TestException('Error');
92+
$e->addContext([
93+
'data' => ['a' => 1, 'b' => 2],
94+
]);
95+
96+
$output = $e->getFormattedContext();
97+
98+
// Pretty-printed JSON
99+
$this->assertStringContainsString('"a": 1', $output);
100+
$this->assertStringContainsString('"b": 2', $output);
101+
}
102+
103+
public function testGetFormattedContextIncludesPreviousException(): void
104+
{
105+
$previous = new TestException('Previous error');
106+
$previous->addContext(['prevKey' => 'prevValue']);
107+
108+
$e = new TestException('Main error', 0, $previous);
109+
$e->addContext(['key' => 'value']);
110+
111+
$output = $e->getFormattedContext();
112+
113+
$this->assertStringContainsString('previousException', $output);
114+
$this->assertStringContainsString('prevKey', $output);
115+
$this->assertStringContainsString('prevValue', $output);
116+
}
62117
}

0 commit comments

Comments
 (0)