Completed
Pull Request — master (#6)
by Walter
02:16
created

HumanReadableExceptionFormatter::indentLines()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 8
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 2
crap 2
1
<?php
2
3
namespace PolderKnowledge\LogModule\Formatter;
4
5
use Monolog\Formatter\FormatterInterface;
6
use Monolog\Formatter\LineFormatter;
7
use WShafer\PSR11MonoLog\FactoryInterface;
8
9
/**
10
 * Format an Exception in a similar way PHP does by default when an exception bubbles to the top
11
 */
12
class HumanReadableExceptionFormatter extends LineFormatter implements FactoryInterface
13
{
14
    public function __invoke(array $options)
15
    {
16
        if (array_key_exists('dateFormat', $options)) {
17
            return new self($options['dateFormat']);
18
        }
19
20
        return new self();
21
    }
22
23
    public function format(array $record): string
24
    {
25
        $exception = $record['context']['exception'] ?? null;
26
27
        if (!$exception) {
28
            return parent::format($record);
29
        }
30
31
        return $this->printFromThrowable($record, $exception);
32
    }
33
34
    protected function printFromThrowable(array $record, \Throwable $throwable)
35
    {
36
        $record = $this->normalize($record);
37
38
        $result = sprintf(
39
            "[%s] %s.%s: %s\n\n",
40
            $record['datetime'],
41
            $record['channel'],
42
            $record['level_name'],
43
            $record['message']
44
        );
45
46
        $exceptionCounter = 1;
47
48
        while ($throwable !== null) {
49
            $result .= sprintf("[Exception #%d]\n", $exceptionCounter++);
50
            $result .= sprintf("  Type: %s\n", get_class($throwable));
51
            $result .= sprintf("  Message: %s\n", $throwable->getMessage());
52
            $result .= sprintf("  Code: %d\n", $throwable->getCode());
53
            $result .= sprintf("  File: %s\n", $throwable->getFile());
54
            $result .= sprintf("  Line: %d\n\n", $throwable->getLine());
55
56
            $result .= "[Trace]\n";
57
            $result .= $this->indentLines($throwable->getTraceAsString());
58
            $result .= "\n\n";
59
60
            $throwable = $throwable->getPrevious();
61
        }
62
63
        foreach ($record['extra'] as $key => $params) {
64
            if (is_array($params) || is_object($params)) {
65
                $lines = json_encode($params, JSON_PRETTY_PRINT | JSON_FORCE_OBJECT);
66
            } else {
67
                $lines = $params;
68
            }
69
70
            $result .= "[Extra - " . $key . "]\n";
71
            $result .= $this->indentLines($lines) . "\n\n";
72
        }
73
74
        return $result;
75
    }
76
77
    private function indentLines(string $input, int $spaces = 2)
78
    {
79
        $lines = explode("\n", $input);
80
81
        $indented = array_map(function ($item) use ($spaces) {
82
            return str_repeat(' ', $spaces) . $item;
83
        }, $lines);
84
85
        return implode("\n", $indented);
86
    }
87
}
88