From 67699caa211245f717fa0f31aab6e012176c1b88 Mon Sep 17 00:00:00 2001 From: "andrii.serdiuk" Date: Tue, 7 Dec 2021 21:08:34 +0100 Subject: [PATCH 1/2] MessageFormatterHandler added. Removed deprecations from StringHandler. --- src/Handler/MessageFormatterHandler.php | 54 ++++++ src/Handler/StringHandler.php | 5 +- tests/Handler/MessageFormatterHandlerTest.php | 176 ++++++++++++++++++ 3 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 src/Handler/MessageFormatterHandler.php create mode 100644 tests/Handler/MessageFormatterHandlerTest.php diff --git a/src/Handler/MessageFormatterHandler.php b/src/Handler/MessageFormatterHandler.php new file mode 100644 index 0000000..829ef60 --- /dev/null +++ b/src/Handler/MessageFormatterHandler.php @@ -0,0 +1,54 @@ +messageFormatter = $messageFormatter; + $this->logLevelStrategy = $logLevelStrategy === null ? $this->getDefaultStrategy() : $logLevelStrategy; + } + + public function log(LoggerInterface $logger, RequestInterface $request, ?ResponseInterface $response = null, ?Throwable $exception = null, ?TransferStats $stats = null, array $options = []): void + { + if ( + $request->getBody()->isSeekable() === false + || $request->getBody()->isReadable() === false + || ( + $response !== null && ( + $response->getBody()->isSeekable() === false + || $response->getBody()->isReadable() === false + ) + ) + ) { + $logger->warning('StringHandler can not log request/response because the body is not seekable/readable.'); + return; + } + + $message = $this->messageFormatter->format($request, $response, $exception); + $reason = $exception ?? $response ?? $request; + $level = $this->logLevelStrategy->getLevel($reason, $options); + $logger->log($level, $message); + } +} diff --git a/src/Handler/StringHandler.php b/src/Handler/StringHandler.php index 09607a1..3542c55 100644 --- a/src/Handler/StringHandler.php +++ b/src/Handler/StringHandler.php @@ -4,6 +4,7 @@ namespace GuzzleLogMiddleware\Handler; +use GuzzleHttp\Psr7\Message; use GuzzleHttp\TransferStats; use GuzzleLogMiddleware\Handler\LogLevelStrategy\LogLevelStrategyInterface; use Psr\Http\Message\RequestInterface; @@ -53,7 +54,7 @@ private function logRequest(LoggerInterface $logger, RequestInterface $value, ar return; } - $str = \GuzzleHttp\Psr7\str($value); + $str = Message::toString($value); $level = $this->logLevelStrategy->getLevel($value, $options); $logger->log($level, 'Guzzle HTTP request:' . "\n" . $str); @@ -67,7 +68,7 @@ private function logResponse(LoggerInterface $logger, ResponseInterface $value, return; } - $str = \GuzzleHttp\Psr7\str($value); + $str = Message::toString($value); $level = $this->logLevelStrategy->getLevel($value, $options); $logger->log($level, 'Guzzle HTTP response:' . "\n" . $str); diff --git a/tests/Handler/MessageFormatterHandlerTest.php b/tests/Handler/MessageFormatterHandlerTest.php new file mode 100644 index 0000000..1cbce89 --- /dev/null +++ b/tests/Handler/MessageFormatterHandlerTest.php @@ -0,0 +1,176 @@ +createMock(MessageFormatterInterface::class); + $strategy = $this->createMock(LogLevelStrategyInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $loglevel = 'LOG_LEVEL'; + $formatter + ->expects($this->once()) + ->method('format') + ->with( + $this->equalTo($request), + $this->equalTo($response), + $this->equalTo($expectedException) + ) + ->willReturn($expectedLogMessage); + $strategy + ->expects($this->once()) + ->method('getLevel') + ->with( + $this->equalTo($expectedException ?? $response ?? $request) + ) + ->willReturn($loglevel); + $logger + ->expects($this->once()) + ->method('log') + ->with( + $this->equalTo($loglevel), + $this->equalTo($expectedLogMessage) + ); + + $handler = new MessageFormatterHandler($formatter, $strategy); + $handler->log($logger, $request, $response, $expectedException); + } + + public function successLogDataProvider(): \Generator + { + yield 'Response is not given.' => [ + // GIVEN request + $this->mockRequest(true, true), + // GIVEN response + null, + // GIVEN exception + null, + // EXPECTED logger message + 'Expected log message.' + ]; + + yield 'Response and Response are seekable.' => [ + // GIVEN request + $this->mockRequest(true, true), + // GIVEN response + $this->mockResponse(true, true), + // GIVEN exception + null, + // EXPECTED logger message + 'Expected log message.' + ]; + + yield 'Response and Response are seekable. Exception given.' => [ + // GIVEN request + $this->mockRequest(true, true), + // GIVEN response + $this->mockResponse(true, true), + // GIVEN exception + new TransferException(), + // EXPECTED logger message + 'Expected log message.' + ]; + } + + /** + * @covers \GuzzleLogMiddleware\Handler\MessageFormatterHandler::log() + * @dataProvider cannotLogDataProvider + */ + public function testCannotLog( + RequestInterface $request, + ?ResponseInterface $response + ): void { + $formatter = $this->createMock(MessageFormatterInterface::class); + $strategy = $this->createMock(LogLevelStrategyInterface::class); + $logger = $this->createMock(LoggerInterface::class); + + $formatter->expects($this->never())->method('format'); + $strategy->expects($this->never())->method('getLevel'); + $logger->expects($this->once()) + ->method('warning') + ->with( + $this->equalTo('StringHandler can not log request/response because the body is not seekable/readable.') + ); + + $handler = new MessageFormatterHandler($formatter, $strategy); + $handler->log($logger, $request, $response); + } + + public function cannotLogDataProvider(): \Generator + { + yield 'Request is not seekable.' => [ + $this->mockRequest(false, true), + $this->mockResponse(true, true), + ]; + + yield 'Request is not readable.' => [ + $this->mockRequest(true, false), + $this->mockResponse(true, true), + ]; + + yield 'Response is not seekable.' => [ + $this->mockRequest(true, true), + $this->mockResponse(false, true), + ]; + + yield 'Response is not readable.' => [ + $this->mockRequest(true, true), + $this->mockResponse(true, false), + ]; + } + + /** + * @return MockObject|RequestInterface + */ + private function mockRequest(bool $isSeekable, bool $isReadable) + { + $mock = $this->createMock(RequestInterface::class); + $mock->method('getBody')->willReturn($this->mockStream($isSeekable, $isReadable)); + return $mock; + } + + /** + * @return MockObject|ResponseInterface + */ + private function mockResponse(bool $isSeekable, bool $isReadable) + { + $mock = $this->createMock(ResponseInterface::class); + $mock->method('getBody')->willReturn($this->mockStream($isSeekable, $isReadable)); + return $mock; + } + + /** + * @return mixed|MockObject|StreamInterface + */ + private function mockStream(bool $isSeekable, bool $isReadable) + { + $mock = $this->createMock(StreamInterface::class); + $mock->method('isSeekable')->willReturn($isSeekable); + $mock->method('isReadable')->willReturn($isReadable); + return $mock; + } +} From 2896816870590c258e372b22f07151c48caac328 Mon Sep 17 00:00:00 2001 From: "andrii.serdiuk" Date: Tue, 7 Dec 2021 21:15:00 +0100 Subject: [PATCH 2/2] strict_types added --- tests/Handler/MessageFormatterHandlerTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Handler/MessageFormatterHandlerTest.php b/tests/Handler/MessageFormatterHandlerTest.php index 1cbce89..8bbe8e8 100644 --- a/tests/Handler/MessageFormatterHandlerTest.php +++ b/tests/Handler/MessageFormatterHandlerTest.php @@ -1,5 +1,7 @@