Adds RequestTraceListener for hyperf/tracer (#6062)

This commit is contained in:
Deeka Wong 2023-09-05 18:19:28 +08:00 committed by GitHub
parent 1dd9b51881
commit 683e45e556
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 198 additions and 12 deletions

View File

@ -1,5 +1,9 @@
# v3.0.36 - TBD
# Added
- [#6062](https://github.com/hyperf/hyperf/pull/6057) Added `RequestTraceListener` for `hyperf/tracer`.
## Fixed
- [#6117](https://github.com/hyperf/hyperf/pull/6117) Fixed bug that grpc client cannot able to be reused.

View File

@ -194,9 +194,12 @@ return [
];
```
### Configure middleware
### Configure middleware or listener
After configuring the driver, you need to configure the middleware or request cycle event listener to collect information to enable the collection function.
- Add middleware
After configuring the driver, you need to configure the middleware to enable the collection function to collect information.
Open the `config/autoload/middlewares.php` file and enable the middleware on the `http` node.
```php
@ -205,9 +208,23 @@ Open the `config/autoload/middlewares.php` file and enable the middleware on the
declare(strict_types=1);
return [
'http' => [
\Hyperf\Tracer\Middleware\TraceMiddleware::class,
],
'http' => [
\Hyperf\Tracer\Middleware\TraceMiddleware::class,
],
];
```
- or add a listener
Open the `config/autoload/listeners.php` file and add the listener.
```php
<?php
declare(strict_types=1);
return [
\Hyperf\Tracer\Listener\RequestTraceListener::class,
];
```

View File

@ -194,9 +194,12 @@ return [
];
```
### 配置中间件
### 配置中间件或监听器
配置完驱动之后,采集信息还需要配置一下中间件或请求周期事件监听器才能启用采集功能。
- 添加中间件
配置完驱动之后,采集信息还需要配置一下中间件才能启用采集功能。
打开 `config/autoload/middlewares.php` 文件,在 `http` 节点启用中间件。
```php
@ -211,6 +214,20 @@ return [
];
```
- 或者添加监听器
打开 `config/autoload/listeners.php` 文件,添加监听器。
```php
<?php
declare(strict_types=1);
return [
\Hyperf\Tracer\Listener\RequestTraceListener::class,
];
```
### 配置 Span tag
对于一些 Hyperf 自动收集追踪信息的 Span Tag 名称,可以通过更改 Span Tag 配置来更改对应的名称,只需在配置文件 `config/autolaod/opentracing.php` 内增加 `tags` 配置即可,参考配置如下。如配置项存在,则以配置项的值为准,如配置项不存在,则以组件的默认值为准。

View File

@ -194,10 +194,13 @@ return [
];
```
### 配置中間件
### 配置中間件或監聽器
配置完驅動之後,採集信息還需要配置一下中間件才能啓用採集功能。
打開 `config/autoload/middlewares.php` 文件,在 `http` 節點啓用中間件。
配置完驅動之後,採集信息還需要配置一下中間件或請求週期事件監聽器才能啟用採集功能。
- 添加中間件
打開 `config/autoload/middlewares.php` 文件,在 `http` 節點啟用中間件。
```php
<?php
@ -211,6 +214,20 @@ return [
];
```
- 或者添加監聽器
打開 `config/autoload/listeners.php` 文件,添加監聽器。
```php
<?php
declare(strict_types=1);
return [
\Hyperf\Tracer\Listener\RequestTraceListener::class,
];
```
### 配置 Span tag
對於一些 Hyperf 自動收集追蹤信息的 Span Tag 名稱,可以通過更改 Span Tag 配置來更改對應的名稱,只需在配置文件 `config/autolaod/opentracing.php` 內增加 `tags` 配置即可,參考配置如下。如配置項存在,則以配置項的值為準,如配置項不存在,則以組件的默認值為準。

View File

@ -194,9 +194,12 @@ return [
];
```
### 配置中介軟體
### 配置中介軟體或監聽器
配置完驅動之後,採集資訊還需要配置一下中介軟體或請求週期事件監聽器才能啟用採集功能。
- 新增中介軟體
配置完驅動之後,採集資訊還需要配置一下中介軟體才能啟用採集功能。
開啟 `config/autoload/middlewares.php` 檔案,在 `http` 節點啟用中介軟體。
```php
@ -211,6 +214,20 @@ return [
];
```
- 或者新增監聽器
開啟 `config/autoload/listeners.php` 檔案,新增監聽器。
```php
<?php
declare(strict_types=1);
return [
\Hyperf\Tracer\Listener\RequestTraceListener::class,
];
```
### 配置 Span tag
對於一些 Hyperf 自動收集追蹤資訊的 Span Tag 名稱,可以透過更改 Span Tag 配置來更改對應的名稱,只需在配置檔案 `config/autolaod/opentracing.php` 內增加 `tags` 配置即可,參考配置如下。如配置項存在,則以配置項的值為準,如配置項不存在,則以元件的預設值為準。

View File

@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Tracer\Listener;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\HttpMessage\Exception\HttpException;
use Hyperf\HttpServer\Event\RequestHandled;
use Hyperf\HttpServer\Event\RequestReceived;
use Hyperf\HttpServer\Event\RequestTerminated;
use Hyperf\Tracer\SpanStarter;
use Hyperf\Tracer\SpanTagManager;
use Hyperf\Tracer\SwitchManager;
use Hyperf\Tracer\TracerContext;
use OpenTracing\Span;
use Psr\Http\Message\ServerRequestInterface;
use Swow\Psr7\Message\ResponsePlusInterface;
use Throwable;
class RequestTraceListener implements ListenerInterface
{
use SpanStarter;
public function __construct(private SwitchManager $switchManager, private SpanTagManager $spanTagManager)
{
}
public function listen(): array
{
return [
RequestReceived::class,
RequestHandled::class,
RequestTerminated::class,
];
}
public function process(object $event): void
{
match ($event::class) {
RequestReceived::class => $this->handleRequestReceived($event),
RequestHandled::class => $this->handleRequestHandled($event),
RequestTerminated::class => $this->handleRequestTerminated($event),
default => '', // fix phpstan error
};
}
protected function handleRequestReceived(RequestReceived $event): void
{
$this->buildSpan($event->request);
}
protected function handleRequestHandled(RequestHandled $event): void
{
if ($event->response instanceof ResponsePlusInterface && $traceId = TracerContext::getTraceId()) {
$event->response->addHeader('Trace-Id', $traceId);
}
}
protected function handleRequestTerminated(RequestTerminated $event): void
{
$response = $event->response;
if (! $response) {
return;
}
$tracer = TracerContext::getTracer();
$span = TracerContext::getRoot();
$span->setTag($this->spanTagManager->get('response', 'status_code'), $response->getStatusCode());
if ($event->exception && $this->switchManager->isEnable('exception')) {
$this->appendExceptionToSpan($span, $exception = $event->exception);
if ($exception instanceof HttpException) {
$span->setTag($this->spanTagManager->get('response', 'status_code'), $exception->getStatusCode());
}
}
$span->finish();
$tracer->flush();
}
protected function appendExceptionToSpan(Span $span, Throwable $exception): void
{
$span->setTag('error', true);
$span->setTag($this->spanTagManager->get('exception', 'class'), get_class($exception));
$span->setTag($this->spanTagManager->get('exception', 'code'), $exception->getCode());
$span->setTag($this->spanTagManager->get('exception', 'message'), $exception->getMessage());
$span->setTag($this->spanTagManager->get('exception', 'stack_trace'), (string) $exception);
}
protected function buildSpan(ServerRequestInterface $request): Span
{
$uri = $request->getUri();
$span = $this->startSpan(sprintf('request: %s %s', $request->getMethod(), $uri->getPath()));
$span->setTag($this->spanTagManager->get('coroutine', 'id'), (string) Coroutine::id());
$span->setTag($this->spanTagManager->get('request', 'path'), (string) $uri->getPath());
$span->setTag($this->spanTagManager->get('request', 'method'), $request->getMethod());
$span->setTag($this->spanTagManager->get('request', 'uri'), (string) $uri);
foreach ($request->getHeaders() as $key => $value) {
$span->setTag($this->spanTagManager->get('request', 'header') . '.' . $key, implode(', ', $value));
}
return $span;
}
}