Reporter   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 59
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 4
dl 0
loc 59
ccs 17
cts 17
cp 1
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
B process() 0 20 5
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Caridea
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
 * use this file except in compliance with the License. You may obtain a copy of
8
 * the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 * License for the specific language governing permissions and limitations under
16
 * the License.
17
 *
18
 * @copyright 2017-2018 LibreWorks contributors
19
 * @license   Apache-2.0
20
 */
21
namespace Caridea\Dispatch\Middleware;
22
23
use Psr\Http\Message\ServerRequestInterface;
24
use Psr\Http\Message\ResponseInterface;
25
use Psr\Http\Server\MiddlewareInterface;
26
use Psr\Http\Server\RequestHandlerInterface;
27
use Psr\Log\LogLevel;
28
use Psr\Log\LoggerInterface;
29
use Psr\Log\LoggerAwareTrait;
30
use Psr\Log\LoggerAwareInterface;
31
32
/**
33
 * Catches exceptions, logs them, and re-throws.
34
 *
35
 * Requires the PSR-3 library.
36
 *
37
 * If the logger itself throws an Exception, it's silently discarded.
38
 *
39
 * @copyright 2017-2018 LibreWorks contributors
40
 * @license   Apache-2.0
41
 */
42
class Reporter implements MiddlewareInterface, LoggerAwareInterface
43
{
44
    use LoggerAwareTrait;
45
46
    /**
47
     * @var array<string,string> Stores the Exception class name to log level
48
     */
49
    private $levels;
50
51
    /**
52
     * Creates a new Reporter middleware.
53
     *
54
     * If an exception isn't found in the `$levels` map, this class assumes a
55
     * level of `LogLevel::ERROR`.
56
     *
57
     * ```php
58
     * $elog = new ErrorLogger(
59
     *     $logger,
60
     *     ["MyException" => LogLevel::DEBUG, "RuntimeException" => LogLevel::WARN]
61
     * );
62
     * ```
63
     *
64
     * @param \Psr\Log\LoggerInterface|null $logger  The logger; will use `Psr\Log\NullLogger` by default
65
     * @param array|null $levels  Map of Exception names to log levels. Order matters!
66
     */
67 3
    public function __construct(LoggerInterface $logger = null, array $levels = null)
68
    {
69 3
        $this->logger = $logger ?? new \Psr\Log\NullLogger();
70 3
        $this->levels = $levels === null ? [] : array_map(function ($a) {
71 2
            return (string) $a;
72 3
        }, $levels);
73 3
    }
74
75
    /**
76
     * {@inheritDoc}
77
     *
78
     * If the logger throws an exception, it's silently discarded.
79
     */
80 3
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
81
    {
82
        try {
83 3
            return $handler->handle($request);
84 3
        } catch (\Throwable $e) {
85 3
            $out = LogLevel::ERROR;
86 3
            foreach ($this->levels as $class => $level) {
87 2
                if ($e instanceof $class) {
88 2
                    $out = $level;
89 2
                    break;
90
                }
91
            }
92
            try {
93 3
                $this->logger->log($out, $e->getMessage(), ['exception' => $e]);
94 1
            } catch (\Throwable $_) {
95
                // Don't worry about errors the logger throws
96
            }
97 3
            throw $e;
98
        }
99
    }
100
}
101