diff --git a/README.md b/README.md index 8419a1a..f636df6 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,13 @@ $logger->error('This is an error'); ``` ``` -INFO This is an info {"message":"This is an info","level":"INFO"} -WARNING This is a warning {"message":"This is a warning","level":"WARNING"} -ERROR This is an error {"message":"This is an error","level":"ERROR"} +8f507cfc-8b35-4e7e-9f26-f2a3a6e7e1a2 INFO This is an info {"message":"This is an info","level":"INFO"} +8f507cfc-8b35-4e7e-9f26-f2a3a6e7e1a2 WARNING This is a warning {"message":"This is a warning","level":"WARNING"} +8f507cfc-8b35-4e7e-9f26-f2a3a6e7e1a2 ERROR This is an error {"message":"This is an error","level":"ERROR"} ``` +This follows the standard format used by official AWS Lambda runtimes. For example the initial request ID is recognized by CloudWatch so that `filter @requestId = '8f507cfc-...'` shows all the logs of a single request/invocation. + Messages under `info` are not logged. ### Message placeholders diff --git a/src/StderrLogger.php b/src/StderrLogger.php index 8fcf25a..844b4e2 100644 --- a/src/StderrLogger.php +++ b/src/StderrLogger.php @@ -82,6 +82,13 @@ public function log($level, $message, array $context = []): void $formattedMessage = sprintf("%s\t%s\t%s\n", strtoupper($level), $displayMessage, $this->toJson($this->normalize($data))); + // Bref sets the ID of the current Lambda invocation. Lambda's own runtimes start their lines with it: + // CloudWatch Logs Insights reads it as `@requestId`, like in Lambda's START, END and REPORT lines. + $requestId = $_SERVER['LAMBDA_REQUEST_ID'] ?? null; + if (is_string($requestId) && $requestId !== '') { + $formattedMessage = "$requestId\t$formattedMessage"; + } + fwrite($this->stream, $formattedMessage); } diff --git a/tests/StderrLoggerTest.php b/tests/StderrLoggerTest.php index 7a74380..40df28a 100644 --- a/tests/StderrLoggerTest.php +++ b/tests/StderrLoggerTest.php @@ -136,6 +136,22 @@ public function test_with_exception() $this->assertStringContainsString('"message":"Test error"', $logs); } + public function test_lines_start_with_the_lambda_request_id() + { + $_SERVER['LAMBDA_REQUEST_ID'] = '8f507cfc-8b35-4e7e-9f26-f2a3a6e7e1a2'; + try { + $this->logger->info('Test message'); + } finally { + unset($_SERVER['LAMBDA_REQUEST_ID']); + } + + $this->assertLogsMatch(<<<'LOGS' +8f507cfc-8b35-4e7e-9f26-f2a3a6e7e1a2 INFO Test message {"message":"Test message","level":"INFO"} + +LOGS + ); + } + private function assertLogsMatch(string $expectedLog): void { rewind($this->stream);