From 5381dc36d65205738d15083dadf67449250d5d14 Mon Sep 17 00:00:00 2001 From: nervermore <18013272501@163.com> Date: Wed, 27 Dec 2023 00:13:04 +0800 Subject: [PATCH] add grpc request and response to entry (#507) * add grpc request and response to entry * Formatting code * add request and response when using middleware * Formatting code * rename response method to getResponsePayload * add grpc request and response to entry * Formatting code * add request and response when using middleware * Formatting code * rename response method to getResponsePayload * Formatting code * Optimize code * Optimize code * Optimize code * Optimize code * Optimize * Fix return statement in TelescopeMiddleware * Refactor TelescopeMiddleware to return payload instead of an empty string * Refactor TelescopeMiddleware to simplify getRequestPayload method * Refactor getRequestPayload method in RequestHandledListener * Refactor GrpcCoreMiddlewareAspect to handle request and response payloads --------- Co-authored-by: guandeng Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com> --- src/Aspect/GrpcCoreMiddlewareAspect.php | 85 +++++++++++++++++++++++++ src/ConfigProvider.php | 1 + src/Listener/RequestHandledListener.php | 59 +++++++++++------ src/Middleware/TelescopeMiddleware.php | 61 ++++++++++++------ src/TelescopeContext.php | 24 +++++++ 5 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 src/Aspect/GrpcCoreMiddlewareAspect.php diff --git a/src/Aspect/GrpcCoreMiddlewareAspect.php b/src/Aspect/GrpcCoreMiddlewareAspect.php new file mode 100644 index 0000000..fd184ce --- /dev/null +++ b/src/Aspect/GrpcCoreMiddlewareAspect.php @@ -0,0 +1,85 @@ +process(), function ($result) use ($proceedingJoinPoint) { + if (! $this->telescopeConfig->isEnable('grpc')) { + return; + } + + match ($proceedingJoinPoint->methodName) { + 'parseMethodParameters' => $this->setRequestPayload($result[0] ?? null), + 'handleResponse' => $this->setResponsePayload($proceedingJoinPoint->arguments['keys']['message'] ?? null), + default => null, + }; + }); + } + + /** + * @param Message|null $message + */ + protected function setRequestPayload($message) + { + if (! $message instanceof Message) { + return; + } + + try { + $payload = json_decode($message->serializeToJsonString(), true); + } catch (Throwable $e) { + return; + } + + TelescopeContext::setGrpcRequestPayload($payload); + } + + /** + * @param Message|null $message + */ + protected function setResponsePayload($message) + { + if (! $message instanceof Message) { + return; + } + + try { + $payload = json_decode($message->serializeToJsonString(), true); + } catch (Throwable $e) { + return; + } + + TelescopeContext::setGrpcResponsePayload($payload); + } +} diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index a02ef5e..501e6d5 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -40,6 +40,7 @@ public function __invoke(): array Aspect\RedisAspect::class, Aspect\RpcAspect::class, Aspect\RequestDispatcherAspect::class, + Aspect\GrpcCoreMiddlewareAspect::class, ], 'annotations' => [ 'scan' => [ diff --git a/src/Listener/RequestHandledListener.php b/src/Listener/RequestHandledListener.php index 40123c0..fec785c 100644 --- a/src/Listener/RequestHandledListener.php +++ b/src/Listener/RequestHandledListener.php @@ -94,8 +94,6 @@ public function requestHandled(RequestTerminated|RpcRequestTerminated $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', 'uri' => $psr7Request->getRequestTarget(), @@ -103,26 +101,15 @@ public function requestHandled(RequestTerminated|RpcRequestTerminated $event) 'controller_action' => $dispatched->handler ? $dispatched->handler->callback : '', 'middleware' => TelescopeContext::getMiddlewares(), 'headers' => $psr7Request->getHeaders(), - 'payload' => $psr7Request->getParsedBody(), + 'payload' => $this->getRequestPayload($psr7Request), 'session' => '', 'response_status' => $psr7Response->getStatusCode(), - 'response' => $this->response($psr7Response), + 'response' => $this->getResponsePayload($psr7Response), 'duration' => $startTime ? floor((microtime(true) - $startTime) * 1000) : null, 'memory' => round(memory_get_peak_usage(true) / 1024 / 1025, 1), ]); - $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 - && ( - is_a($handler, \Hyperf\RpcServer\Server::class, true) - || is_a($handler, \Hyperf\JsonRpc\HttpServer::class, true) - || is_a($handler, \Hyperf\GrpcServer\Server::class, true) - ) - ) { + if ($this->isRpcRequest($psr7Request)) { Telescope::recordService($entry); } else { Telescope::recordRequest($entry); @@ -139,7 +126,7 @@ protected function incomingRequest(ServerRequestInterface $psr7Request): bool return ! $this->telescopeConfig->isPathIgnored($psr7Request); } - protected function response(ResponseInterface $response): string|array + protected function getResponsePayload(ResponseInterface $response): array|string { $stream = $response->getBody(); @@ -165,8 +152,7 @@ protected function response(ResponseInterface $response): string|array return $this->contentWithinLimits($content) ? $content : 'Purged By Hyperf Telescope'; /* @phpstan-ignore-line */ } if (Str::contains($response->getHeaderLine('content-type'), 'application/grpc') !== false) { - // to do for grpc - return 'Purged By Hyperf Telescope'; + return TelescopeContext::getGrpcResponsePayload() ?: 'Purged By Hyperf Telescope'; } } @@ -210,4 +196,39 @@ protected function getRpcContext(): array return $this->container->get(RpcContext::class)->get('telescope.carrier', []); } + + protected function isRpcRequest(ServerRequestInterface $psr7Request): bool + { + $handler = $this->parseHandler($psr7Request); + if ( + $handler + && ( + is_a($handler, \Hyperf\RpcServer\Server::class, true) + || is_a($handler, \Hyperf\JsonRpc\HttpServer::class, true) + || is_a($handler, \Hyperf\GrpcServer\Server::class, true) + ) + ) { + return true; + } + + return false; + } + + protected function parseHandler(ServerRequestInterface $psr7Request): mixed + { + $dispatched = $psr7Request->getAttribute(Dispatched::class); + $serverName = $dispatched->serverName ?? 'http'; + $serverConfig = collect(config('server.servers'))->firstWhere('name', $serverName); + $handlerClass = $serverConfig['callbacks'][Event::ON_RECEIVE][0] ?? $serverConfig['callbacks'][Event::ON_REQUEST][0] ?? null; + return is_string($handlerClass) && $this->container->has($handlerClass) ? $this->container->get($handlerClass) : null; + } + + protected function getRequestPayload(ServerRequestInterface $psr7Request): array|string + { + $handler = $this->parseHandler($psr7Request); + if ($handler && is_a($handler, \Hyperf\GrpcServer\Server::class, true)) { + return TelescopeContext::getGrpcRequestPayload() ?: ''; + } + return $psr7Request->getParsedBody(); + } } diff --git a/src/Middleware/TelescopeMiddleware.php b/src/Middleware/TelescopeMiddleware.php index 209c055..bcaf60d 100644 --- a/src/Middleware/TelescopeMiddleware.php +++ b/src/Middleware/TelescopeMiddleware.php @@ -78,8 +78,6 @@ public function requestHandled($request, $response) 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'], 'uri' => $psr7Request->getRequestTarget(), @@ -87,26 +85,15 @@ public function requestHandled($request, $response) 'controller_action' => $dispatched->handler ? $dispatched->handler->callback : '', 'middleware' => TelescopeContext::getMiddlewares(), 'headers' => $psr7Request->getHeaders(), - 'payload' => $psr7Request->getParsedBody(), + 'payload' => $this->getRequestPayload($psr7Request), 'session' => '', 'response_status' => $psr7Response->getStatusCode(), - 'response' => $this->response($psr7Response), + 'response' => $this->getResponsePayload($psr7Response), 'duration' => $startTime ? floor((microtime(true) - $startTime) * 1000) : null, 'memory' => round(memory_get_peak_usage(true) / 1024 / 1025, 1), ]); - $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 - && ( - is_a($handler, \Hyperf\RpcServer\Server::class, true) - || is_a($handler, \Hyperf\JsonRpc\HttpServer::class, true) - || is_a($handler, \Hyperf\GrpcServer\Server::class, true) - ) - ) { + if ($this->isRpcRequest($psr7Request)) { Telescope::recordService($entry); } else { Telescope::recordRequest($entry); @@ -123,7 +110,7 @@ protected function incomingRequest(ServerRequestInterface $psr7Request): bool return ! $this->telescopeConfig->isPathIgnored($psr7Request); } - protected function response(ResponseInterface $response): string|array + protected function getResponsePayload(ResponseInterface $response): string|array { $stream = $response->getBody(); if ($stream->isSeekable()) { @@ -146,8 +133,7 @@ protected function response(ResponseInterface $response): string|array return $this->contentWithinLimits($content) ? $content : 'Purged By Hyperf Telescope'; /* @phpstan-ignore-line */ } if (Str::contains($response->getHeaderLine('content-type'), 'application/grpc') !== false) { - // to do for grpc - return 'Purged By Hyperf Telescope'; + return TelescopeContext::getGrpcResponsePayload() ?: 'Purged By Hyperf Telescope'; } } @@ -191,4 +177,41 @@ protected function getRpcContext(): array return $this->container->get(RpcContext::class)->get('telescope.carrier', []); } + + protected function isRpcRequest(ServerRequestInterface $psr7Request): bool + { + $handler = $this->parseHandler($psr7Request); + if ( + $handler + && ( + is_a($handler, \Hyperf\RpcServer\Server::class, true) + || is_a($handler, \Hyperf\JsonRpc\HttpServer::class, true) + || is_a($handler, \Hyperf\GrpcServer\Server::class, true) + ) + ) { + return true; + } + + return false; + } + + protected function parseHandler(ServerRequestInterface $psr7Request): mixed + { + $dispatched = $psr7Request->getAttribute(Dispatched::class); + $serverName = $dispatched->serverName ?? 'http'; + $serverConfig = collect(config('server.servers'))->firstWhere('name', $serverName); + $handlerClass = $serverConfig['callbacks'][Event::ON_RECEIVE][0] ?? $serverConfig['callbacks'][Event::ON_REQUEST][0] ?? null; + return is_string($handlerClass) && $this->container->has($handlerClass) ? $this->container->get($handlerClass) : null; + } + + protected function getRequestPayload(ServerRequestInterface $psr7Request): array|string + { + $handler = $this->parseHandler($psr7Request); + + if ($handler && is_a($handler, \Hyperf\GrpcServer\Server::class, true)) { + return TelescopeContext::getGrpcRequestPayload() ?: ''; + } + + return $psr7Request->getParsedBody(); + } } diff --git a/src/TelescopeContext.php b/src/TelescopeContext.php index bb5bf07..3fa7386 100644 --- a/src/TelescopeContext.php +++ b/src/TelescopeContext.php @@ -30,6 +30,10 @@ class TelescopeContext public const MIDDLEWARES = 'telescope.context.middlewares'; + public const GRPC_REQUEST_PAYLOAD = 'telescope.context.grpc.request.payload'; + + public const GRPC_RESPONSE_PAYLOAD = 'telescope.context.grpc.response.payload'; + public static function setBatchId(string $batchId): void { Context::set(self::BATCH_ID, $batchId); @@ -109,4 +113,24 @@ public static function addEntry(IncomingEntry $entry): void Context::set(self::ENTRIES, $entries); } + + public static function setGrpcRequestPayload(array $payload): void + { + Context::set(self::GRPC_REQUEST_PAYLOAD, $payload); + } + + public static function getGrpcRequestPayload(): ?array + { + return Context::get(self::GRPC_REQUEST_PAYLOAD) ?: null; + } + + public static function setGrpcResponsePayload(array $payload): void + { + Context::set(self::GRPC_RESPONSE_PAYLOAD, $payload); + } + + public static function getGrpcResponsePayload(): ?array + { + return Context::get(self::GRPC_RESPONSE_PAYLOAD) ?: null; + } }