Skip to content

Commit

Permalink
Add record rpc server (#442)
Browse files Browse the repository at this point in the history
* Add record rpc server

* Improve telescope middleware

* optimize code

* Fix TelescopeMiddleware to record service or
request based on server type

* Update telescope README.md to include rpc
server/client

* Update README.md

* Add record rpc server

* Improve telescope middleware

* optimize code

* Fix TelescopeMiddleware to record service or
request based on server type

* Update telescope README.md to include rpc
server/client

* Update README.md

* Fix RequestHandledListener to record service or

---------

Co-authored-by: Deeka Wong <[email protected]>
  • Loading branch information
guandeng and huangdijia authored Nov 20, 2023
1 parent 8defbaa commit 3475a13
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 45 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"hyperf/framework": "~3.0.0",
"hyperf/grpc-client": "~3.0.0",
"hyperf/grpc-server": "~3.0.0",
"hyperf/json-rpc": "~3.0.0",
"hyperf/guzzle": "~3.0.0",
"hyperf/http-server": "~3.0.20",
"hyperf/http2-client": "~3.0.0",
Expand Down
6 changes: 4 additions & 2 deletions src/telescope/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ An elegant debug assistant for the hyperf framework.
- [x] request
- [x] exception
- [x] sql
- [x] grpc client
- [x] grpc server/client
- [x] redis
- [x] log
- [x] command
- [x] event
- [x] http client
- [x] guzzle
- [x] cache
- [x] rpc server/client

## Installation

Expand Down Expand Up @@ -80,6 +81,7 @@ TELESCOPE_ENABLE_JOB=true
TELESCOPE_ENABLE_DB=true
TELESCOPE_ENABLE_GUZZLE=true
TELESCOPE_ENABLE_CACHE=true
TELESCOPE_ENABLE_RPC=true
TELESCOPE_SERVER_ENABLE=true
```
Expand Down
1 change: 1 addition & 0 deletions src/telescope/publish/telescope.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'db' => env('TELESCOPE_ENABLE_DB', false),
'guzzle' => env('TELESCOPE_ENABLE_GUZZLE', false),
'cache' => env('TELESCOPE_ENABLE_CACHE', false),
'rpc' => env('TELESCOPE_ENABLE_RPC', false),
],
'timezone' => env('TELESCOPE_TIMEZONE', 'Asia/Shanghai'),
'database' => [
Expand Down
71 changes: 45 additions & 26 deletions src/telescope/src/Aspect/HttpClientAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
use GuzzleHttp\Client;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Psr\Http\Message\ResponseInterface;

use function Hyperf\Tappable\tap;

/**
* @property array $config
*/
class HttpClientAspect extends AbstractAspect
{
public array $classes = [
Expand All @@ -33,29 +35,46 @@ public function __construct(protected SwitchManager $switcherManager)

public function process(ProceedingJoinPoint $proceedingJoinPoint)
{
return tap($proceedingJoinPoint->process(), function ($result) use ($proceedingJoinPoint) {
if (! $this->switcherManager->isEnable('guzzle')) {
return;
}
$options = $proceedingJoinPoint->arguments['keys']['options'];
if (isset($options['no_aspect']) && $options['no_aspect'] === true) {
return;
}
$arguments = $proceedingJoinPoint->arguments;
$method = $arguments['keys']['method'] ?? 'Null';
$uri = $arguments['keys']['uri'] ?? 'Null';
$headers = $options['headers'] ?? [];

Telescope::recordClientRequest(IncomingEntry::make([
'method' => $method,
'uri' => $uri,
'headers' => $headers,
'payload' => '',
'response_status' => 0,
'response_headers' => '',
'response' => '',
'duration' => 0,
]));
});
if (! $this->switcherManager->isEnable('guzzle')) {
return $proceedingJoinPoint->process();
}
$startTime = microtime(true);
$instance = $proceedingJoinPoint->getInstance();
$arguments = $proceedingJoinPoint->arguments;
$options = $arguments['keys']['options'] ?? [];
$guzzleConfig = (fn () => $this->config ?? [])->call($instance);

if (($options['no_telescope_aspect'] ?? null) === true || ($guzzleConfig['no_telescope_aspect'] ?? null) === true) {
return $proceedingJoinPoint->process();
}

// Disable the aspect for the requestAsync method.
if ($proceedingJoinPoint->methodName == 'request') {
$proceedingJoinPoint->arguments['keys']['options']['no_telescope_aspect'] = true;
}

$arguments = $proceedingJoinPoint->arguments;
$method = $arguments['keys']['method'] ?? 'GET';
$uri = $arguments['keys']['uri'] ?? '';
$headers = $options['headers'] ?? [];

$result = $proceedingJoinPoint->process();

$response = [];
if ($result instanceof ResponseInterface) {
$response['status'] = $result->getStatusCode();
$response['reason'] = $result->getReasonPhrase();
$response['headers'] = $result->getHeaders();
}
Telescope::recordClientRequest(IncomingEntry::make([
'method' => $method,
'uri' => $uri,
'headers' => $headers,
'response_status' => $response['status'] ?? 0,
'response_headers' => $response['headers'] ?? '',
'response' => $response,
'duration' => floor((microtime(true) - $startTime) * 1000),
]));
return $result;
}
}
45 changes: 45 additions & 0 deletions src/telescope/src/Aspect/RpcAspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);
/**
* This file is part of friendsofhyperf/components.
*
* @link https://github.com/friendsofhyperf/components
* @document https://github.com/friendsofhyperf/components/blob/main/README.md
* @contact [email protected]
*/

namespace FriendsOfHyperf\Telescope\Aspect;

use FriendsOfHyperf\Telescope\SwitchManager;
use FriendsOfHyperf\Telescope\TelescopeContext;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\Rpc\Context;
use Hyperf\RpcClient\AbstractServiceClient;

use function Hyperf\Tappable\tap;

class RpcAspect extends AbstractAspect
{
public array $classes = [
AbstractServiceClient::class . '::__generateRpcPath',
];

public function __construct(protected SwitchManager $switcherManager, protected Context $context)
{
}

public function process(ProceedingJoinPoint $proceedingJoinPoint)
{
return tap($proceedingJoinPoint->process(), function () {
if (static::class == self::class && $this->switcherManager->isEnable('rpc') === false) {
return;
}

$carrier = [];
$carrier['batch-id'] = TelescopeContext::getBatchId();
$this->context->set('telescope.carrier', $carrier);
});
}
}
1 change: 1 addition & 0 deletions src/telescope/src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function __invoke(): array
Aspect\HttpClientAspect::class,
Aspect\LogAspect::class,
Aspect\RedisAspect::class,
Aspect\RpcAspect::class,
],
'annotations' => [
'scan' => [
Expand Down
45 changes: 40 additions & 5 deletions src/telescope/src/Listener/RequestHandledListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,30 @@
use FriendsOfHyperf\Telescope\Telescope;
use FriendsOfHyperf\Telescope\TelescopeContext;
use Hyperf\Collection\Arr;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\HttpServer\Event\RequestReceived;
use Hyperf\HttpServer\Event\RequestTerminated;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Rpc;
use Hyperf\Server\Event;
use Hyperf\Stringable\Str;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Swow\Psr7\Message\ResponsePlusInterface;

use function Hyperf\Collection\collect;
use function Hyperf\Config\config;

class RequestHandledListener implements ListenerInterface
{
public function __construct(protected SwitchManager $switchManager, protected ConfigInterface $config)
{
public function __construct(
protected ContainerInterface $container,
protected ConfigInterface $config,
protected SwitchManager $switchManager
) {
}

public function listen(): array
Expand Down Expand Up @@ -57,10 +67,14 @@ public function requestReceived(RequestReceived $event)
$request = $event->request;

if (! $batchId = $request->getHeaderLine('batch-id')) {
$batchId = Str::orderedUuid()->toString();
} else {
$batchId = $this->getRpcBatchId();
}

if ($batchId) {
$subBatchId = Str::orderedUuid()->toString();
TelescopeContext::setSubBatchId($subBatchId);
} else {
$batchId = Str::orderedUuid()->toString();
}

TelescopeContext::setBatchId($batchId);
Expand All @@ -83,6 +97,7 @@ public function requestHandled(RequestTerminated $event)
if ($this->incomingRequest($psr7Request)) {
/** @var Dispatched $dispatched */
$dispatched = $psr7Request->getAttribute(Dispatched::class);
$serverName = $dispatched->serverName ?? 'http';

$entry = IncomingEntry::make([
'ip_address' => $psr7Request->getServerParams()['remote_addr'] ?? 'unknown',
Expand All @@ -99,7 +114,11 @@ public function requestHandled(RequestTerminated $event)
'memory' => round(memory_get_peak_usage(true) / 1024 / 1025, 1),
]);

if (Str::contains($psr7Request->getHeaderLine('content-type'), 'application/grpc')) {
$serverConfig = collect(config('server.servers'))->firstWhere('name', $serverName);
$handlerClass = $serverConfig['callbacks'][Event::ON_RECEIVE][0] ?? $serverConfig['callbacks'][Event::ON_REQUEST][0] ?? null;
$handler = is_string($handlerClass) && $this->container->has($handlerClass) ? $this->container->get($handlerClass) : null;

if ($handler && ($handler instanceof \Hyperf\RpcServer\Server || $handler instanceof \Hyperf\GrpcServer\Server || $handler instanceof \Hyperf\JsonRpc\HttpServer)) {
Telescope::recordService($entry);
} else {
Telescope::recordRequest($entry);
Expand Down Expand Up @@ -179,4 +198,20 @@ protected function hideParameters(array $data, array $hidden): array

return $data;
}

protected function getRpcBatchId(): string
{
$carrier = $this->getRpcContext();
return $carrier['batch-id'] ?? '';
}

protected function getRpcContext(): array
{
$container = ApplicationContext::getContainer();
if (! $container->has(Rpc\Context::class)) {
return [];
}
$rpcContext = $container->get(Rpc\Context::class);
return (array) $rpcContext->get('telescope.carrier');
}
}
53 changes: 41 additions & 12 deletions src/telescope/src/Middleware/TelescopeMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,26 @@
use FriendsOfHyperf\Telescope\Telescope;
use FriendsOfHyperf\Telescope\TelescopeContext;
use Hyperf\Collection\Arr;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\ConfigInterface;
use Hyperf\HttpServer\Router\Dispatched;
use Hyperf\Rpc;
use Hyperf\Server\Event;
use Hyperf\Stringable\Str;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

use function Hyperf\Collection\collect;
use function Hyperf\Config\config;
use function Hyperf\Coroutine\defer;

class TelescopeMiddleware implements MiddlewareInterface
{
public function __construct(
protected ContainerInterface $container,
protected ConfigInterface $config,
protected SwitchManager $switchManager
) {
Expand All @@ -40,20 +47,21 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
return $handler->handle($request);
}

$batchId = $request->getHeaderLine('batch-id');
if (! $batchId) {
$batchId = Str::orderedUuid()->toString();
} else {
if (! $batchId = $request->getHeaderLine('batch-id')) {
$batchId = $this->getRpcBatchId();
}

if ($batchId) {
$subBatchId = Str::orderedUuid()->toString();
TelescopeContext::setSubBatchId($subBatchId);
} else {
$batchId = Str::orderedUuid()->toString();
}

TelescopeContext::setBatchId($batchId);

$response = $handler->handle($request);

if ($batchId) {
$response = $response->withHeader('batch-id', $batchId);
}
$response = $response->withHeader('batch-id', $batchId);

defer(fn () => $this->requestHandled($request, $response));

Expand All @@ -73,7 +81,8 @@ public function requestHandled($request, $response)
if ($this->incomingRequest($psr7Request)) {
/** @var Dispatched $dispatched */
$dispatched = $psr7Request->getAttribute(Dispatched::class);
$middlewares = $this->config->get('middlewares.' . ($dispatched->serverName ?? 'http'), []);
$serverName = $dispatched->serverName ?? 'http';
$middlewares = $this->config->get('middlewares.' . $serverName, []);

$entry = IncomingEntry::make([
'ip_address' => $psr7Request->getServerParams()['remote_addr'],
Expand All @@ -90,7 +99,11 @@ public function requestHandled($request, $response)
'memory' => round(memory_get_peak_usage(true) / 1024 / 1025, 1),
]);

if (Str::contains($psr7Request->getHeaderLine('content-type'), 'application/grpc')) {
$serverConfig = collect(config('server.servers'))->firstWhere('name', $serverName);
$handlerClass = $serverConfig['callbacks'][Event::ON_RECEIVE][0] ?? $serverConfig['callbacks'][Event::ON_REQUEST][0] ?? null;
$handler = is_string($handlerClass) && $this->container->has($handlerClass) ? $this->container->get($handlerClass) : null;

if ($handler && ($handler instanceof \Hyperf\RpcServer\Server || $handler instanceof \Hyperf\GrpcServer\Server || $handler instanceof \Hyperf\JsonRpc\HttpServer)) {
Telescope::recordService($entry);
} else {
Telescope::recordRequest($entry);
Expand All @@ -112,7 +125,7 @@ protected function incomingRequest(ServerRequestInterface $psr7Request): bool
return true;
}

protected function response(ResponseInterface $response): string
protected function response(ResponseInterface $response): string|array
{
$stream = $response->getBody();
if ($stream->isSeekable()) {
Expand All @@ -129,7 +142,7 @@ protected function response(ResponseInterface $response): string
) {
return $this->contentWithinLimits($content)
? $this->hideParameters(json_decode($content, true), Telescope::$hiddenResponseParameters)
: 'Purged By Telescope';
: 'Purged By Hyperf Telescope';
}
if (Str::startsWith(strtolower($response->getHeaderLine('content-type') ?? ''), 'text/plain')) {
return $this->contentWithinLimits($content) ? $content : 'Purged By Hyperf Telescope';
Expand Down Expand Up @@ -166,4 +179,20 @@ protected function hideParameters(array $data, array $hidden): array

return $data;
}

protected function getRpcBatchId(): string
{
$carrier = $this->getRpcContext();
return $carrier['batch-id'] ?? '';
}

protected function getRpcContext(): array
{
$container = ApplicationContext::getContainer();
if (! $container->has(Rpc\Context::class)) {
return [];
}
$rpcContext = $container->get(Rpc\Context::class);
return (array) $rpcContext->get('telescope.carrier');
}
}

0 comments on commit 3475a13

Please sign in to comment.