diff --git a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php new file mode 100644 index 00000000..d37d1e0c --- /dev/null +++ b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\LogRecord; + +/** + * Encodes message information into JSON in a format compatible with Cloud logging. + * + * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry + * + * @author Luís Cobucci + */ +final class GoogleCloudLoggingFormatter extends JsonFormatter +{ + protected function normalizeRecord(LogRecord $record): array + { + $normalized = parent::normalizeRecord($record); + + // Re-key level for GCP logging + $normalized['severity'] = $normalized['level_name']; + $normalized['timestamp'] = $record->datetime->format(DateTimeInterface::RFC3339_EXTENDED); + + // Remove keys that are not used by GCP + unset($normalized['level'], $normalized['level_name'], $normalized['datetime']); + + return $normalized; + } +} diff --git a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php new file mode 100644 index 00000000..e46846ae --- /dev/null +++ b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\Test\TestCase; +use function json_decode; + +class GoogleCloudLoggingFormatterTest extends TestCase +{ + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::normalizeRecord + */ + public function formatProvidesRfc3339Timestamps(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("datetime", $formatted_decoded); + $this->assertArrayHasKey("timestamp", $formatted_decoded); + $this->assertSame($record->datetime->format(DateTimeInterface::RFC3339_EXTENDED), $formatted_decoded["timestamp"]); + } + + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::normalizeRecord + */ + public function formatIntroducesLogSeverity(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("level", $formatted_decoded); + $this->assertArrayNotHasKey("level_name", $formatted_decoded); + $this->assertArrayHasKey("severity", $formatted_decoded); + $this->assertSame($record->level->getName(), $formatted_decoded["severity"]); + } +}