From e2c9d07c18da58298a3b287c818cebaeb722a144 Mon Sep 17 00:00:00 2001 From: Seth Westphal Date: Mon, 31 Jul 2023 14:36:14 -0500 Subject: [PATCH] feat(ErrorReporting): Generate HttpRequestContext for log context. (#5656) --- ErrorReporting/src/Bootstrap.php | 49 ++++++++++++++++++++- ErrorReporting/tests/Unit/BootstrapTest.php | 44 ++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/ErrorReporting/src/Bootstrap.php b/ErrorReporting/src/Bootstrap.php index 29c9ad133ad6..8f69bc13a5c3 100644 --- a/ErrorReporting/src/Bootstrap.php +++ b/ErrorReporting/src/Bootstrap.php @@ -129,7 +129,7 @@ public static function exceptionHandler($ex) if (self::$psrLogger) { $service = self::$psrLogger->getMetadataProvider()->serviceId(); $version = self::$psrLogger->getMetadataProvider()->versionId(); - self::$psrLogger->error($message, [ + $context = [ 'context' => [ 'reportLocation' => [ 'filePath' => $ex->getFile(), @@ -142,7 +142,12 @@ public static function exceptionHandler($ex) 'service' => $service, 'version' => $version, ] - ]); + ]; + $httpRequest = self::getHttpRequest(); + if (!empty($httpRequest)) { + $context['context']['httpRequest'] = self::getHttpRequest(); + } + self::$psrLogger->error($message, $context); } else { $stderr = defined('STDERR') ? STDERR : fopen('php://stderr', 'w'); fwrite($stderr, $message . PHP_EOL); @@ -186,6 +191,10 @@ public static function errorHandler($level, $message, $file, $line) 'version' => $version ] ]; + $httpRequest = self::getHttpRequest(); + if (!empty($httpRequest)) { + $context['context']['httpRequest'] = self::getHttpRequest(); + } self::$psrLogger->log( self::getErrorLevelString($level), $message, @@ -232,6 +241,10 @@ public static function shutdownHandler() 'version' => $version ] ]; + $httpRequest = self::getHttpRequest(); + if (!empty($httpRequest)) { + $context['context']['httpRequest'] = self::getHttpRequest(); + } if (self::$psrLogger) { self::$psrLogger->log( self::getErrorLevelString($err['type']), @@ -268,4 +281,36 @@ private static function getFunctionNameForReport(array $trace = null) } return implode('', array_reverse($functionName)); } + + /** + * Builds an HttpRequestContext from available server information. + * + * @return array An HttpRequestContext. + */ + private static function getHttpRequest() + { + $httpRequest = []; + if (isset($_SERVER)) { + if (isset($_SERVER['REQUEST_METHOD'])) { + $httpRequest['method'] = $_SERVER['REQUEST_METHOD']; + } + if (isset($_SERVER['HTTP_USER_AGENT'])) { + $httpRequest['userAgent'] = $_SERVER['HTTP_USER_AGENT']; + } + if (isset($_SERVER['HTTP_REFERER'])) { + $httpRequest['referrer'] = $_SERVER['HTTP_REFERER']; + } + if (isset($_SERVER['REMOTE_ADDR'])) { + $httpRequest['remoteIp'] = $_SERVER['REMOTE_ADDR']; + } + if (isset($_SERVER['HTTP_HOST']) && isset($_SERVER['REQUEST_URI'])) { + $httpRequest['url'] = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') + . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + } + if (http_response_code() !== false) { + $httpRequest['responseStatusCode'] = http_response_code(); + } + } + return $httpRequest; + } } diff --git a/ErrorReporting/tests/Unit/BootstrapTest.php b/ErrorReporting/tests/Unit/BootstrapTest.php index 4e598c95af51..4cd3b05d7239 100644 --- a/ErrorReporting/tests/Unit/BootstrapTest.php +++ b/ErrorReporting/tests/Unit/BootstrapTest.php @@ -140,6 +140,50 @@ public function testExceptionHandler($exception) Bootstrap::exceptionHandler($exception); } + /** + * @dataProvider exceptionProvider + * @runInSeparateProcess + */ + public function testExceptionHandlerWithHttpContext($exception) + { + $_SERVER = [ + 'REQUEST_METHOD' => 'GET', + 'HTTP_REFERER' => 'ref', + 'HTTP_HOST' => 'google.com', + 'REQUEST_URI' => '/index.php', + 'REMOTE_ADDR' => '1.2.3.4', + 'HTTP_USER_AGENT' => 'UA', + ]; + $expectedMessage = sprintf('PHP Notice: %s', (string)$exception); + $expectedContext = [ + 'context' => [ + 'reportLocation' => [ + 'filePath' => $exception->getFile(), + 'lineNumber' => $exception->getLine(), + 'functionName' => 'Google\Cloud\ErrorReporting\Tests\Unit\BootstrapTest->exceptionProvider', + ], + 'httpRequest' => [ + 'method' => 'GET', + 'url' => 'http://google.com/index.php', + 'referrer' => 'ref', + 'remoteIp' => '1.2.3.4', + 'userAgent' => 'UA', + ] + ], + 'serviceContext' => [ + 'service' => '', + 'version' => '' + ] + ]; + $this->psrBatchLogger->error($expectedMessage, $expectedContext) + ->shouldBeCalledTimes(1); + $this->psrBatchLogger->getMetadataProvider() + ->willReturn(new SimpleMetadataProvider()) + ->shouldBeCalledTimes(2); + Bootstrap::$psrLogger = $this->psrBatchLogger->reveal(); + Bootstrap::exceptionHandler($exception); + } + /** * @dataProvider exceptionProvider */