AccessLogger   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 80
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 80
rs 10
c 0
b 0
f 0
wmc 8

4 Methods

Rating   Name   Duplication   Size   Complexity  
A outbound() 0 4 1
A inbound() 0 5 1
A requestFIN() 0 34 5
A exception() 0 4 1
1
<?php
2
/**
3
 * Access logger
4
 * User: moyo
5
 * Date: 2018/6/1
6
 * Time: 3:48 PM
7
 */
8
9
namespace Carno\Web\Handlers;
10
11
use Carno\Chain\Layered;
12
use Carno\Coroutine\Context;
13
use Carno\HTTP\Server\Connection;
14
use Carno\HTTP\Standard\Response;
15
use Carno\HTTP\Standard\ServerRequest;
16
use Carno\Net\Address;
17
use Throwable;
18
19
class AccessLogger implements Layered
20
{
21
    /**
22
     * ctx vars
23
     */
24
    private const REMOTE = 'log-r-remote';
25
    private const START = 'log-r-start-at';
26
27
    /**
28
     * @param Connection $ingress
29
     * @param Context $ctx
30
     * @return mixed
31
     */
32
    public function inbound($ingress, Context $ctx)
33
    {
34
        $ctx->set(self::REMOTE, $ingress->remote());
35
        $ctx->set(self::START, microtime(true));
36
        return $ingress;
37
    }
38
39
    /**
40
     * @param Response $response
41
     * @param Context $ctx
42
     * @return mixed
43
     */
44
    public function outbound($response, Context $ctx)
45
    {
46
        $this->requestFIN($ctx, null);
47
        return $response;
48
    }
49
50
    /**
51
     * @param Throwable $e
52
     * @param Context $ctx
53
     * @throws Throwable
54
     */
55
    public function exception(Throwable $e, Context $ctx)
56
    {
57
        $this->requestFIN($ctx, $e);
58
        throw $e;
59
    }
60
61
    /**
62
     * @param Context $ctx
63
     * @param Throwable $error
64
     */
65
    private function requestFIN(Context $ctx, Throwable $error = null) : void
66
    {
67
        /**
68
         * @var ServerRequest|null $request
69
         * @var Response|null $response
70
         * @var Address $remote
71
         * @var float $start
72
         */
73
74
        $request = $ctx->get(IngressWrapper::REQUESTING);
75
        $response = $ctx->get(IngressWrapper::RESPONDING);
76
        $remote = $ctx->get(self::REMOTE);
77
        $start = $ctx->get(self::START);
78
79
        if (!$request || !$response) {
80
            return;
81
        }
82
83
        $meta = [
84
            'method' => $request->getMethod(),
85
            'path' => $request->getUri()->getPath(),
86
            'status' => $response->getStatusCode(),
87
            'from' => (string) $remote,
88
            'cost' => $start ? intval((microtime(true) - $start) * 1000) : 0,
89
        ];
90
91
        if ($error) {
92
            $meta = array_merge($meta, [
93
                'error' => sprintf('%s::%s', get_class($error), $error->getMessage()),
94
                'file' => sprintf('%s:%d', $error->getFile(), $error->getLine()),
95
            ]);
96
            logger('web')->notice('Request failed', $meta);
97
        } else {
98
            logger('web')->debug('Request finished', $meta);
99
        }
100
    }
101
}
102