Skip to content

Commit 8e7abb6

Browse files
committed
Merge branch 'master' into 3.1-merge
2 parents d9f7bb8 + 6baa065 commit 8e7abb6

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Tracer\Listener;
13+
14+
use Hyperf\Coroutine\Coroutine;
15+
use Hyperf\Event\Contract\ListenerInterface;
16+
use Hyperf\HttpMessage\Exception\HttpException;
17+
use Hyperf\HttpServer\Event\RequestHandled;
18+
use Hyperf\HttpServer\Event\RequestReceived;
19+
use Hyperf\HttpServer\Event\RequestTerminated;
20+
use Hyperf\Tracer\SpanStarter;
21+
use Hyperf\Tracer\SpanTagManager;
22+
use Hyperf\Tracer\SwitchManager;
23+
use Hyperf\Tracer\TracerContext;
24+
use OpenTracing\Span;
25+
use Psr\Http\Message\ServerRequestInterface;
26+
use Swow\Psr7\Message\ResponsePlusInterface;
27+
use Throwable;
28+
29+
class RequestTraceListener implements ListenerInterface
30+
{
31+
use SpanStarter;
32+
33+
public function __construct(private SwitchManager $switchManager, private SpanTagManager $spanTagManager)
34+
{
35+
}
36+
37+
public function listen(): array
38+
{
39+
return [
40+
RequestReceived::class,
41+
RequestHandled::class,
42+
RequestTerminated::class,
43+
];
44+
}
45+
46+
public function process(object $event): void
47+
{
48+
match ($event::class) {
49+
RequestReceived::class => $this->handleRequestReceived($event),
50+
RequestHandled::class => $this->handleRequestHandled($event),
51+
RequestTerminated::class => $this->handleRequestTerminated($event),
52+
default => '', // fix phpstan error
53+
};
54+
}
55+
56+
protected function handleRequestReceived(RequestReceived $event): void
57+
{
58+
$this->buildSpan($event->request);
59+
}
60+
61+
protected function handleRequestHandled(RequestHandled $event): void
62+
{
63+
if ($event->response instanceof ResponsePlusInterface && $traceId = TracerContext::getTraceId()) {
64+
$event->response->addHeader('Trace-Id', $traceId);
65+
}
66+
}
67+
68+
protected function handleRequestTerminated(RequestTerminated $event): void
69+
{
70+
$response = $event->response;
71+
72+
if (! $response) {
73+
return;
74+
}
75+
76+
$tracer = TracerContext::getTracer();
77+
$span = TracerContext::getRoot();
78+
$span->setTag($this->spanTagManager->get('response', 'status_code'), $response->getStatusCode());
79+
80+
if ($event->exception && $this->switchManager->isEnable('exception')) {
81+
$this->appendExceptionToSpan($span, $exception = $event->exception);
82+
83+
if ($exception instanceof HttpException) {
84+
$span->setTag($this->spanTagManager->get('response', 'status_code'), $exception->getStatusCode());
85+
}
86+
}
87+
88+
$span->finish();
89+
$tracer->flush();
90+
}
91+
92+
protected function appendExceptionToSpan(Span $span, Throwable $exception): void
93+
{
94+
$span->setTag('error', true);
95+
$span->setTag($this->spanTagManager->get('exception', 'class'), get_class($exception));
96+
$span->setTag($this->spanTagManager->get('exception', 'code'), $exception->getCode());
97+
$span->setTag($this->spanTagManager->get('exception', 'message'), $exception->getMessage());
98+
$span->setTag($this->spanTagManager->get('exception', 'stack_trace'), (string) $exception);
99+
}
100+
101+
protected function buildSpan(ServerRequestInterface $request): Span
102+
{
103+
$uri = $request->getUri();
104+
$span = $this->startSpan(sprintf('request: %s %s', $request->getMethod(), $uri->getPath()));
105+
$span->setTag($this->spanTagManager->get('coroutine', 'id'), (string) Coroutine::id());
106+
$span->setTag($this->spanTagManager->get('request', 'path'), (string) $uri->getPath());
107+
$span->setTag($this->spanTagManager->get('request', 'method'), $request->getMethod());
108+
$span->setTag($this->spanTagManager->get('request', 'uri'), (string) $uri);
109+
foreach ($request->getHeaders() as $key => $value) {
110+
$span->setTag($this->spanTagManager->get('request', 'header') . '.' . $key, implode(', ', $value));
111+
}
112+
return $span;
113+
}
114+
}

0 commit comments

Comments
 (0)