Passed
Pull Request — master (#8)
by
unknown
02:48
created

HttpTracingMiddleware   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 7
eloc 33
c 2
b 0
f 0
dl 0
loc 74
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A handle() 0 21 2
A traceIdHeader() 0 3 1
A addTraceIdToHeaderIfNeeded() 0 11 2
A terminate() 0 13 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Umbrellio\Jaravel\Middleware;
6
7
use Illuminate\Http\Request;
8
use Illuminate\Support\Facades\Config;
9
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
10
use OpenTelemetry\SDK\Trace\Span;
11
use Symfony\Component\HttpFoundation\Response;
12
use Umbrellio\Jaravel\Services\Caller;
13
use Umbrellio\Jaravel\Services\Http\TracingRequestGuard;
14
use Umbrellio\Jaravel\Services\Span\ActiveSpanTraceIdRetriever;
15
use Umbrellio\Jaravel\Services\Span\SpanCreator;
16
use Umbrellio\Jaravel\Services\Span\SpanAttributeHelper;
17
use Umbrellio\Jaravel\Services\TraceIdHeaderRetriever;
18
19
class HttpTracingMiddleware
20
{
21
    private SpanCreator $spanCreator;
22
    private TracingRequestGuard $requestGuard;
23
    private ActiveSpanTraceIdRetriever $activeTraceIdRetriever;
24
    private TraceIdHeaderRetriever $traceIdHeaderRetriever;
25
26
    public function __construct(
27
        SpanCreator $spanCreator,
28
        TracingRequestGuard $requestGuard,
29
        ActiveSpanTraceIdRetriever $activeTraceIdRetriever,
30
        TraceIdHeaderRetriever $traceIdHeaderRetriever
31
    ) {
32
        $this->spanCreator = $spanCreator;
33
        $this->requestGuard = $requestGuard;
34
        $this->activeTraceIdRetriever = $activeTraceIdRetriever;
35
        $this->traceIdHeaderRetriever = $traceIdHeaderRetriever;
36
    }
37
38
    /** @param Request $request */
39
    public function handle($request, callable $next)
40
    {
41
        if (!$this->requestGuard->allowRequest($request)) {
42
            return $next($request);
43
        }
44
45
        $headers = $request->server->all();
46
47
        $traceIdHeader = $this->traceIdHeaderRetriever->retrieve($headers, $this->traceIdHeader());
48
49
        $this->spanCreator->create(
50
            Caller::call(Config::get('jaravel.http.span_name'), [$request]),
51
            $traceIdHeader
52
        )->activate();
53
54
        /** @var Response $response */
55
        $response = $next($request);
56
57
        $this->addTraceIdToHeaderIfNeeded($response);
58
59
        return $response;
60
    }
61
62
    public function terminate($request, $response)
63
    {
64
        $span = Span::getCurrent();
65
        $scope = $span->activate();
66
67
        $callableConfig = Config::get('jaravel.http.attributes', fn () => [
68
            'type' => 'http',
69
        ]);
70
71
        SpanAttributeHelper::setAttributes($span, Caller::call($callableConfig, [$request, $response]));
72
73
        $span->end();
74
        $scope->detach();
75
    }
76
77
    private function addTraceIdToHeaderIfNeeded(Response $response): void
78
    {
79
        $headerName = $this->traceIdHeader();
80
81
        if (!$headerName) {
82
            return;
83
        }
84
85
        $traceId = $this->activeTraceIdRetriever->retrieve();
86
87
        $response->headers->set($headerName, $traceId);
88
    }
89
90
    private function traceIdHeader(): ?string
91
    {
92
        return 'HTTP_' . strtoupper(TraceContextPropagator::TRACEPARENT);
93
    }
94
}
95