From 197f534d42591eb32ebfee60e9c92b5192be39a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Fri, 22 Jul 2022 13:04:51 +0200 Subject: [PATCH 01/21] Add basic support to Google Cloud Logging format (#1719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Google Cloud Logging doesn't show the correct level log when using JsonFormatter, making observability a bit trickier. This applies minor tweaks to the default format, allowing log entries to be properly represented. There are alternative packages to this but they add fields that aren't strictly required - also performing `debug_backtrace()` calls that are usually not desired when in production mode. This is a backport of https://github.com/Seldaek/monolog/pull/1690 Signed-off-by: Luís Cobucci --- .../Formatter/GoogleCloudLoggingFormatter.php | 39 ++++++++++++++ .../GoogleCloudLoggingFormatterTest.php | 54 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/Monolog/Formatter/GoogleCloudLoggingFormatter.php create mode 100644 tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php diff --git a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php new file mode 100644 index 00000000..0cd287f5 --- /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 +{ + /** {@inheritdoc} **/ + public function format(array $record): string + { + // Re-key level for GCP logging + $record['severity'] = $record['level_name']; + $record['timestamp'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED); + + // Remove keys that are not used by GCP + unset($record['level'], $record['level_name'], $record['datetime']); + + return parent::format($record); + } +} + diff --git a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php new file mode 100644 index 00000000..27aea2ca --- /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::format + */ + 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::format + */ + 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_name'], $formatted_decoded["severity"]); + } +} From 3734f190f8f643aaed3bae99a722bae5212ccb2a Mon Sep 17 00:00:00 2001 From: Mikhail Popov Date: Fri, 22 Jul 2022 14:08:34 +0300 Subject: [PATCH 02/21] Add the ability to set or redefine attributes for messages in Rabbit. (#1724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of content_type, content_encoding, message_id, user_id, app_id, delivery_mode, priority, timestamp, expiration, type or reply_to, headers. Co-authored-by: Попов Михаил --- src/Monolog/Handler/AmqpHandler.php | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index e30d784d..c0b4504e 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -27,6 +27,29 @@ class AmqpHandler extends AbstractProcessingHandler * @var AMQPExchange|AMQPChannel $exchange */ protected $exchange; + /** @var array */ + private $extraAttributes = []; + + /** + * @return array + */ + public function getExtraAttributes(): array + { + return $this->extraAttributes; + } + + /** + * @param array $extraAttributes One of content_type, content_encoding, + * message_id, user_id, app_id, delivery_mode, + * priority, timestamp, expiration, type + * or reply_to, headers. + * @return AmqpHandler + */ + public function setExtraAttributes(array $extraAttributes): self + { + $this->extraAttributes = $extraAttributes; + return $this; + } /** * @var string @@ -60,14 +83,18 @@ class AmqpHandler extends AbstractProcessingHandler $routingKey = $this->getRoutingKey($record); if ($this->exchange instanceof AMQPExchange) { + $attributes = [ + 'delivery_mode' => 2, + 'content_type' => 'application/json', + ]; + if ($this->extraAttributes) { + $attributes = array_merge($attributes, $this->extraAttributes); + } $this->exchange->publish( $data, $routingKey, 0, - [ - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ] + $attributes ); } else { $this->exchange->basic_publish( From 11be0a4b30ab3a84c1687e2c1fd4eedf9e800c55 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:15:11 +0200 Subject: [PATCH 03/21] Fix phpstan errors --- src/Monolog/Handler/AmqpHandler.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index c0b4504e..c4997482 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -27,11 +27,11 @@ class AmqpHandler extends AbstractProcessingHandler * @var AMQPExchange|AMQPChannel $exchange */ protected $exchange; - /** @var array */ + /** @var array */ private $extraAttributes = []; /** - * @return array + * @return array */ public function getExtraAttributes(): array { @@ -39,10 +39,12 @@ class AmqpHandler extends AbstractProcessingHandler } /** - * @param array $extraAttributes One of content_type, content_encoding, - * message_id, user_id, app_id, delivery_mode, - * priority, timestamp, expiration, type - * or reply_to, headers. + * Configure extra attributes to pass to the AMQPExchange (if you are using the amqp extension) + * + * @param array $extraAttributes One of content_type, content_encoding, + * message_id, user_id, app_id, delivery_mode, + * priority, timestamp, expiration, type + * or reply_to, headers. * @return AmqpHandler */ public function setExtraAttributes(array $extraAttributes): self From f958fdac0f3ec78af4c5c1cdebd2e5e219a563ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 9 Jul 2022 11:29:07 +0200 Subject: [PATCH 04/21] allow Predis 2.0, closes #1732 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 52cb35f6..d01b8e18 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5.14", - "predis/predis": "^1.1", + "predis/predis": "^1.1 || ^2.0", "rollbar/rollbar": "^1.3 || ^2 || ^3", "ruflin/elastica": "^7", "swiftmailer/swiftmailer": "^5.3|^6.0", From af8efac0d58e524aead247ce64445a66e6d7c553 Mon Sep 17 00:00:00 2001 From: Max Ageev Date: Thu, 9 Jun 2022 14:23:32 +0300 Subject: [PATCH 05/21] Check if errorMessage contain error "File exists" Fixes #1678, closes #1685 When we try to create directory we got error and find out that error is to the fact that directory already was created for us. If that the case we should not throw exception as it's fine now... If file was deleted after that it's not problem of this funtion. --- src/Monolog/Handler/StreamHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index e6c79569..3550c8c1 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -212,7 +212,7 @@ class StreamHandler extends AbstractProcessingHandler set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status && !is_dir($dir)) { + if (false === $status && !is_dir($dir) && strpos($this->errorMessage, 'File exists') !== false) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } From 6cc788bdec2550f596736c58742de4c447cc64d1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:25:12 +0200 Subject: [PATCH 06/21] Fix build error with lowest deps on php7.4 --- .github/workflows/continuous-integration.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ff2cc1a6..ace0a642 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -152,6 +152,10 @@ jobs: - name: "Change dependencies" run: "composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^${{ matrix.es-version }}" + - name: "Allow composer plugin to run" + if: "matrix.php-version == '7.4' && matrix.dependencies == 'lowest'" + run: "composer config allow-plugins.ocramius/package-versions true" + - name: "Update dependencies with composer" uses: "ramsey/composer-install@v1" with: @@ -229,6 +233,10 @@ jobs: composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^8 + - name: "Allow composer plugin to run" + if: "matrix.php-version == '7.4' && matrix.dependencies == 'lowest'" + run: "composer config allow-plugins.ocramius/package-versions true" + - name: "Update dependencies with composer" uses: "ramsey/composer-install@v1" with: From 475bc874091fc1e5ab579d895c27efcd1ddc20a4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:33:21 +0200 Subject: [PATCH 07/21] Fix issues --- src/Monolog/Handler/RedisHandler.php | 4 ++-- src/Monolog/Handler/RedisPubSubHandler.php | 4 ++-- src/Monolog/Handler/StreamHandler.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 938eee6b..91d16eaf 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -30,7 +30,7 @@ use Monolog\Logger; */ class RedisHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $redisKey; @@ -38,7 +38,7 @@ class RedisHandler extends AbstractProcessingHandler protected $capSize; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The key name to push records to * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index f9fede8e..7789309c 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -28,13 +28,13 @@ use Monolog\Logger; */ class RedisPubSubHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $channelKey; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 3550c8c1..65183512 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -212,7 +212,7 @@ class StreamHandler extends AbstractProcessingHandler set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status && !is_dir($dir) && strpos($this->errorMessage, 'File exists') !== false) { + if (false === $status && !is_dir($dir) && strpos((string) $this->errorMessage, 'File exists') === false) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } From ffc2bc2e23f174a7356b74f51e5e57aff713202e Mon Sep 17 00:00:00 2001 From: systemsolutionweb <88460896+systemsolutionweb@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:54:02 -0500 Subject: [PATCH 08/21] Update .gitattributes, closes #1688 --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 52e9cb43..6da920e3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ /doc export-ignore /tests export-ignore /.* export-ignore -/phpstan.neon.dist export-ignore +/phpstan* export-ignore /phpunit.xml.dist export-ignore /_config.yml export-ignore /UPGRADE.md From 83db4b3f8124f0d1ff0d45872728359022c4c4b6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:18:01 +0200 Subject: [PATCH 09/21] Handle depth to avoid cases where an exception has many too many previous exceptions, fixes #1726 --- src/Monolog/Formatter/LineFormatter.php | 6 ++++++ src/Monolog/Formatter/NormalizerFormatter.php | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index d0b4de94..69dfee5c 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -153,6 +153,12 @@ class LineFormatter extends NormalizerFormatter if ($previous = $e->getPrevious()) { do { + $depth++; + if ($depth > $this->maxNormalizeDepth) { + $str .= '\n[previous exception] Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; + break; + } + $str .= "\n[previous exception] " . $this->formatException($previous); } while ($previous = $previous->getPrevious()); } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 0c622715..5441bc0a 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -198,6 +198,10 @@ class NormalizerFormatter implements FormatterInterface */ protected function normalizeException(Throwable $e, int $depth = 0) { + if ($depth > $this->maxNormalizeDepth) { + return ['Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization']; + } + if ($e instanceof \JsonSerializable) { return (array) $e->jsonSerialize(); } From 27dc1b2ef734cf4077321886dcbb6d9efbf6b81b Mon Sep 17 00:00:00 2001 From: erikn69 Date: Fri, 22 Jul 2022 07:23:53 -0500 Subject: [PATCH 10/21] Fix utf8_encode deprecation (#1722) --- src/Monolog/Handler/ChromePHPHandler.php | 6 +++--- src/Monolog/Utils.php | 2 +- tests/Monolog/Handler/ChromePHPHandlerTest.php | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index d1a98b8f..234ecf61 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -149,7 +149,7 @@ class ChromePHPHandler extends AbstractProcessingHandler } $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); - $data = base64_encode(utf8_encode($json)); + $data = base64_encode($json); if (strlen($data) > 3 * 1024) { self::$overflowed = true; @@ -163,8 +163,8 @@ class ChromePHPHandler extends AbstractProcessingHandler 'extra' => [], ]; self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); - $json = Utils::jsonEncode(self::$json, null, true); - $data = base64_encode(utf8_encode($json)); + $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); + $data = base64_encode($json); } if (trim($data) !== '') { diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 726c9819..360c4219 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -211,7 +211,7 @@ final class Utils $data = preg_replace_callback( '/[\x80-\xFF]+/', function ($m) { - return utf8_encode($m[0]); + return function_exists('mb_convert_encoding') ? mb_convert_encoding($m[0], 'UTF-8', 'ISO-8859-1') : utf8_encode($m[0]); }, $data ); diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 1ee58195..cf13dd89 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -38,7 +38,7 @@ class ChromePHPHandlerTest extends TestCase $handler->handle($this->getRecord(Logger::WARNING)); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -46,7 +46,7 @@ class ChromePHPHandlerTest extends TestCase 'test', ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler->getHeaders()); @@ -72,7 +72,7 @@ class ChromePHPHandlerTest extends TestCase $handler->handle($this->getRecord(Logger::WARNING, str_repeat('b', 2 * 1024))); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -96,7 +96,7 @@ class ChromePHPHandlerTest extends TestCase ], ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler->getHeaders()); @@ -115,7 +115,7 @@ class ChromePHPHandlerTest extends TestCase $handler2->handle($this->getRecord(Logger::WARNING)); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -125,7 +125,7 @@ class ChromePHPHandlerTest extends TestCase 'test', ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler2->getHeaders()); From c1c73b07debd6d2f72fe225d9cf9642a88e93dfe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:25:43 +0200 Subject: [PATCH 11/21] Update issue templates --- .github/ISSUE_TEMPLATE/Bug_Report.md | 2 +- .github/ISSUE_TEMPLATE/Question.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md index 71ce0c2b..df38260f 100644 --- a/.github/ISSUE_TEMPLATE/Bug_Report.md +++ b/.github/ISSUE_TEMPLATE/Bug_Report.md @@ -4,6 +4,6 @@ about: Create a bug report labels: Bug --- -Monolog version 1|2 +Monolog version 1|2|3? Write your bug report here. diff --git a/.github/ISSUE_TEMPLATE/Question.md b/.github/ISSUE_TEMPLATE/Question.md index b2810fa3..f62632c4 100644 --- a/.github/ISSUE_TEMPLATE/Question.md +++ b/.github/ISSUE_TEMPLATE/Question.md @@ -4,6 +4,6 @@ about: Ask a question regarding software usage labels: Support --- -Monolog version 1|2 +Monolog version 1|2|3? Write your question here. From ad09e76f97d165a9067af8daf8fd6f4d07d0c133 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:26:06 +0200 Subject: [PATCH 12/21] Add php 8.2 build --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ace0a642..e50e004d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,6 +20,7 @@ jobs: - "7.4" - "8.0" - "8.1" + - "8.2" dependencies: [highest] From b3ac20ef322e9bc8aa1d13c9943eca8f278ee9f6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:46:07 +0200 Subject: [PATCH 13/21] Matrix update --- .github/workflows/continuous-integration.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index e50e004d..6a139279 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -6,7 +6,7 @@ on: jobs: tests: - name: "CI" + name: "CI (PHP ${{ matrix.php-version }}, ${{ matrix.dependencies }} deps)" runs-on: "${{ matrix.operating-system }}" @@ -24,6 +24,8 @@ jobs: dependencies: [highest] + composer-options: "" + operating-system: - "ubuntu-latest" @@ -34,6 +36,10 @@ jobs: - php-version: "8.1" dependencies: lowest operating-system: ubuntu-latest + - php-version: "8.2" + dependencies: highest + operating-system: ubuntu-latest + composer-options: "--ignore-platform-req=php+" steps: - name: "Checkout" @@ -69,9 +75,10 @@ jobs: composer config --no-plugins allow-plugins.ocramius/package-versions true - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" + composer-options: "${{ matrix.composer-options }}" - name: "Run tests" run: "composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose" @@ -158,7 +165,7 @@ jobs: run: "composer config allow-plugins.ocramius/package-versions true" - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" @@ -239,7 +246,7 @@ jobs: run: "composer config allow-plugins.ocramius/package-versions true" - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" From 3a1ea88ee0c90dd809d75dd7dcef1d0f59a92216 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:47:49 +0200 Subject: [PATCH 14/21] Fix matrix --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 6a139279..5fb4c9e0 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -24,7 +24,7 @@ jobs: dependencies: [highest] - composer-options: "" + composer-options: [""] operating-system: - "ubuntu-latest" From 611ff01fa6f9d36c41fb6d0f4c8b0de820a3c2eb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:48:24 +0200 Subject: [PATCH 15/21] Skip php8.2 default build --- .github/workflows/continuous-integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5fb4c9e0..129d36d8 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,7 +20,6 @@ jobs: - "7.4" - "8.0" - "8.1" - - "8.2" dependencies: [highest] From 9c1fb56f6aa983b959517e57955516bdba771d5d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:00:00 +0200 Subject: [PATCH 16/21] Deprecate CubeHandler and PHPConsoleHandler which are targetting abandoned projects, fixes #1734 --- composer.json | 2 -- src/Monolog/Handler/CubeHandler.php | 3 ++- src/Monolog/Handler/PHPConsoleHandler.php | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index d01b8e18..ab775ad6 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,6 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5.14", @@ -48,7 +47,6 @@ "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "php-console/php-console": "Allow sending log messages to Google Chrome", "ext-mbstring": "Allow to work properly with unicode symbols", "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index fc8f58f1..3535a4fc 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -17,8 +17,9 @@ use Monolog\Utils; /** * Logs to Cube. * - * @link http://square.github.com/cube/ + * @link https://github.com/square/cube/wiki * @author Wan Chen + * @deprecated Since 2.8.0 and 3.2.0, Cube appears abandoned and thus we will drop this handler in Monolog 4 */ class CubeHandler extends AbstractProcessingHandler { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 6e209b19..23a1d117 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -25,7 +25,7 @@ use PhpConsole\Helper; * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely * * Usage: - * 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef + * 1. Install Google Chrome extension [now dead and removed from the chrome store] * 2. See overview https://github.com/barbushin/php-console#overview * 3. Install PHP Console library https://github.com/barbushin/php-console#installation * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png) @@ -39,6 +39,7 @@ use PhpConsole\Helper; * @author Sergey Barbushin https://www.linkedin.com/in/barbushin * * @phpstan-import-type Record from \Monolog\Logger + * @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4 */ class PHPConsoleHandler extends AbstractProcessingHandler { From 6fdeea463cc61a112c0fa969ceec6f576d181b07 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:07:44 +0200 Subject: [PATCH 17/21] Fix build --- phpstan.neon.dist | 3 +++ tests/Monolog/Formatter/NormalizerFormatterTest.php | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4a368cd2..d368b288 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,9 @@ parameters: - src/ # - tests/ + excludePaths: + - 'src/Monolog/Handler/PHPConsoleHandler.php' + ignoreErrors: - '#zend_monitor_|ZEND_MONITOR_#' - '#MongoDB\\(Client|Collection)#' diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 00cc1fb9..181065ed 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -369,8 +369,9 @@ class NormalizerFormatterTest extends TestCase $record = ['context' => ['exception' => $e]]; $result = $formatter->format($record); + $offset = PHP_VERSION_ID >= 80200 ? 12 : 10; $this->assertSame( - __FILE__.':'.(__LINE__-9), + __FILE__.':'.(__LINE__ - $offset), $result['context']['exception']['trace'][0] ); } From 34635fdcf5c1ef6da113c84aee5401d01aa0a13f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:08:12 +0200 Subject: [PATCH 18/21] Add docs --- tests/Monolog/Formatter/NormalizerFormatterTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 181065ed..162f34b3 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -369,7 +369,8 @@ class NormalizerFormatterTest extends TestCase $record = ['context' => ['exception' => $e]]; $result = $formatter->format($record); - $offset = PHP_VERSION_ID >= 80200 ? 12 : 10; + // See https://github.com/php/php-src/issues/8810 fixed in PHP 8.2 + $offset = PHP_VERSION_ID >= 80200 ? 13 : 11; $this->assertSame( __FILE__.':'.(__LINE__ - $offset), $result['context']['exception']['trace'][0] From 1e6a4e106c0aa8c52cfb219017834d48f3f012a0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:10:54 +0200 Subject: [PATCH 19/21] Remove deprecated handlers from docs --- doc/02-handlers-formatters-processors.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 72c5da01..d16e674a 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -51,7 +51,6 @@ [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. - [_GelfHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/GelfHandler.php): Logs records to a [Graylog2](http://www.graylog2.org) server. Requires package [graylog2/gelf-php](https://github.com/bzikarsky/gelf-php). -- [_CubeHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/CubeHandler.php): Logs records to a [Cube](http://square.github.com/cube/) server. - [_ZendMonitorHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ZendMonitorHandler.php): Logs records to the Zend Monitor present in Zend Server. - [_NewRelicHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NewRelicHandler.php): Logs records to a [NewRelic](http://newrelic.com/) application. - [_LogglyHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogglyHandler.php): Logs records to a [Loggly](http://www.loggly.com/) account. @@ -72,8 +71,6 @@ inline `console` messages within Chrome. - [_BrowserConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/BrowserConsoleHandler.php): Handler to send logs to browser's Javascript `console` with no browser extension required. Most browsers supporting `console` API are supported. -- [_PHPConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PHPConsoleHandler.php): Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing - inline `console` and notification popup messages within Chrome. ### Log to databases From 284482a726da916e2562425ac5223826db924dd0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:12:01 +0200 Subject: [PATCH 20/21] More test fixes --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 129d36d8..cf50545a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -87,7 +87,7 @@ jobs: run: | composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar composer require --no-update psr/log:^3 - composer update -W + composer update ${{ matrix.composer-options }} composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose tests-es-7: From cf0f4b38148bc5ee19e83585b5dea135cbbfe3ca Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:27:46 +0200 Subject: [PATCH 21/21] Handle __toString to serialize objects which are not json-serializable in JsonFormatter, fixes #1733 --- src/Monolog/Formatter/JsonFormatter.php | 23 ++++++-- tests/Monolog/Formatter/JsonFormatterTest.php | 56 +++++++++++++++++++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 42735a6b..b737d82e 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -178,12 +178,25 @@ class JsonFormatter extends NormalizerFormatter return $normalized; } - if ($data instanceof \DateTimeInterface) { - return $this->formatDate($data); - } + if (is_object($data)) { + if ($data instanceof \DateTimeInterface) { + return $this->formatDate($data); + } - if ($data instanceof Throwable) { - return $this->normalizeException($data, $depth); + if ($data instanceof Throwable) { + return $this->normalizeException($data, $depth); + } + + // if the object has specific json serializability we want to make sure we skip the __toString treatment below + if ($data instanceof \JsonSerializable) { + return $data; + } + + if (method_exists($data, '__toString')) { + return $data->__toString(); + } + + return $data; } if (is_resource($data)) { diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 17a3ba82..14702102 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use JsonSerializable; use Monolog\Logger; use Monolog\Test\TestCase; @@ -314,4 +315,59 @@ class JsonFormatterTest extends TestCase $record ); } + + public function testFormatObjects() + { + $formatter = new JsonFormatter(); + + $record = $formatter->format(array( + 'level' => 100, + 'level_name' => 'DEBUG', + 'channel' => 'test', + 'message' => 'Testing', + 'context' => array( + 'public' => new TestJsonNormPublic, + 'private' => new TestJsonNormPrivate, + 'withToStringAndJson' => new TestJsonNormWithToStringAndJson, + 'withToString' => new TestJsonNormWithToString, + ), + 'extra' => array(), + )); + + $this->assertSame( + '{"level":100,"level_name":"DEBUG","channel":"test","message":"Testing","context":{"public":{"foo":"fooValue"},"private":{},"withToStringAndJson":["json serialized"],"withToString":"stringified"},"extra":{}}'."\n", + $record + ); + } +} + +class TestJsonNormPublic +{ + public $foo = 'fooValue'; +} + +class TestJsonNormPrivate +{ + private $foo = 'fooValue'; +} + +class TestJsonNormWithToStringAndJson implements JsonSerializable +{ + public function jsonSerialize() + { + return ['json serialized']; + } + + public function __toString() + { + return 'SHOULD NOT SHOW UP'; + } +} + +class TestJsonNormWithToString +{ + public function __toString() + { + return 'stringified'; + } }