]> git.mxchange.org Git - friendica-addons.git/commitdiff
Fix Monolog
authorPhilipp <admin@philipp.info>
Sun, 2 Jul 2023 21:57:24 +0000 (23:57 +0200)
committerHypolite Petovan <hypolite@mrpetovan.com>
Sun, 23 Jul 2023 11:00:31 +0000 (13:00 +0200)
- Use new hook-loading

141 files changed:
monolog/composer.json
monolog/composer.lock
monolog/monolog.php
monolog/src/DevelopHandler.php [deleted file]
monolog/src/Factory/Monolog.php [new file with mode: 0644]
monolog/src/IntrospectionProcessor.php [deleted file]
monolog/src/Monolog/DevelopHandler.php [new file with mode: 0644]
monolog/src/Monolog/IntrospectionProcessor.php [new file with mode: 0644]
monolog/static/dependencies.config.php [new file with mode: 0644]
monolog/static/hooks.config.php [new file with mode: 0644]
monolog/vendor/composer/autoload_classmap.php
monolog/vendor/composer/autoload_psr4.php
monolog/vendor/composer/autoload_static.php
monolog/vendor/composer/installed.json
monolog/vendor/monolog/monolog/CHANGELOG.md
monolog/vendor/monolog/monolog/README.md
monolog/vendor/monolog/monolog/composer.json
monolog/vendor/monolog/monolog/src/Monolog/Attribute/AsMonologProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/DateTimeImmutable.php
monolog/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/LogmaticFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Formatter/SyslogFormatter.php [deleted file]
monolog/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ElasticaHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ElasticsearchHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FallbackGroupHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/Handler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/LogmaticHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/NoopHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/OverflowHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ProcessHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/RedisPubSubHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SendGridHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SqsHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/TelegramBotHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/WebRequestRecognizerTrait.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Level.php [deleted file]
monolog/vendor/monolog/monolog/src/Monolog/LogRecord.php
monolog/vendor/monolog/monolog/src/Monolog/Logger.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/HostnameProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
monolog/vendor/monolog/monolog/src/Monolog/Registry.php
monolog/vendor/monolog/monolog/src/Monolog/ResettableInterface.php
monolog/vendor/monolog/monolog/src/Monolog/SignalHandler.php
monolog/vendor/monolog/monolog/src/Monolog/Test/TestCase.php
monolog/vendor/monolog/monolog/src/Monolog/Utils.php
monolog/vendor/psr/log/composer.json
monolog/vendor/psr/log/src/AbstractLogger.php [deleted file]
monolog/vendor/psr/log/src/InvalidArgumentException.php [deleted file]
monolog/vendor/psr/log/src/LogLevel.php [deleted file]
monolog/vendor/psr/log/src/LoggerAwareInterface.php [deleted file]
monolog/vendor/psr/log/src/LoggerAwareTrait.php [deleted file]
monolog/vendor/psr/log/src/LoggerInterface.php [deleted file]
monolog/vendor/psr/log/src/LoggerTrait.php [deleted file]
monolog/vendor/psr/log/src/NullLogger.php [deleted file]

index 9c7f32c3e39255f5ee93ec82948c39979df15e7d..7bcb4995df2251896cdec5b1f417c83cc26b8475 100644 (file)
@@ -11,8 +11,8 @@
        }
   ],
   "require": {
-    "php": ">=7.0",
-    "monolog/monolog": "^3.2"
+    "php": ">=7.3",
+    "monolog/monolog": "^2.9"
   },
   "license": "3-clause BSD license",
   "config": {
index 0566f7212f4e3f47a2b4ecb91d080af230aee08a..f73b2ef033479a395d88cc79fdf3afbfb6ae4408 100644 (file)
@@ -4,45 +4,46 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "e812bcd051a73d1c9b19c91ec88a6a21",
+    "content-hash": "6fd294bd163b37ac6cc400e0f8785222",
     "packages": [
         {
             "name": "monolog/monolog",
-            "version": "3.2.0",
+            "version": "2.9.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81"
+                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/305444bc6fb6c89e490f4b34fa6e979584d7fa81",
-                "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
-                "psr/log": "^2.0 || ^3.0"
+                "php": ">=7.2",
+                "psr/log": "^1.0.1 || ^2.0 || ^3.0"
             },
             "provide": {
-                "psr/log-implementation": "3.0.0"
+                "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
             },
             "require-dev": {
-                "aws/aws-sdk-php": "^3.0",
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
                 "doctrine/couchdb": "~1.0@dev",
                 "elasticsearch/elasticsearch": "^7 || ^8",
                 "ext-json": "*",
-                "graylog2/gelf-php": "^1.4.2",
+                "graylog2/gelf-php": "^1.4.2 || ^2@dev",
                 "guzzlehttp/guzzle": "^7.4",
                 "guzzlehttp/psr7": "^2.2",
                 "mongodb/mongodb": "^1.8",
                 "php-amqplib/php-amqplib": "~2.4 || ^3",
-                "phpstan/phpstan": "^1.4",
-                "phpstan/phpstan-deprecation-rules": "^1.0",
-                "phpstan/phpstan-strict-rules": "^1.1",
-                "phpunit/phpunit": "^9.5.16",
-                "predis/predis": "^1.1",
+                "phpspec/prophecy": "^1.15",
+                "phpstan/phpstan": "^0.12.91",
+                "phpunit/phpunit": "^8.5.14",
+                "predis/predis": "^1.1 || ^2.0",
+                "rollbar/rollbar": "^1.3 || ^2 || ^3",
                 "ruflin/elastica": "^7",
+                "swiftmailer/swiftmailer": "^5.3|^6.0",
                 "symfony/mailer": "^5.4 || ^6",
                 "symfony/mime": "^5.4 || ^6"
             },
@@ -65,7 +66,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "3.x-dev"
+                    "dev-main": "2.x-dev"
                 }
             },
             "autoload": {
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-07-24T12:00:55+00:00"
+            "time": "2023-02-06T13:44:46+00:00"
         },
         {
             "name": "psr/log",
-            "version": "3.0.0",
+            "version": "1.1.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.0.0"
+                "php": ">=5.3.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.x-dev"
+                    "dev-master": "1.1.x-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Psr\\Log\\": "src"
+                    "Psr\\Log\\": "Psr/Log/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 "psr",
                 "psr-3"
             ],
-            "time": "2021-07-14T16:46:02+00:00"
+            "time": "2021-05-03T11:20:27+00:00"
         }
     ],
     "packages-dev": [],
     "prefer-stable": false,
     "prefer-lowest": false,
     "platform": {
-        "php": ">=7.0"
+        "php": ">=7.3"
     },
     "platform-dev": [],
     "plugin-api-version": "1.1.0"
index efdcb3feba4bf49de37c45aa06ffe1423ee2d61f..b13efff94e27d6ced854d4c522fe3464fb05462e 100644 (file)
@@ -5,62 +5,3 @@
  * Version: 1.0
  * Author: Philipp Holzer
  */
-
-use Friendica\App;
-use Friendica\Core\Hook;
-use Friendica\Addon\monolog\src\IntrospectionProcessor;
-use Friendica\DI;
-use Psr\Log\LogLevel;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-function monolog_install()
-{
-       Hook::register('logger_instance' , __FILE__, 'monolog_instance');
-}
-
-function monolog_uninstall()
-{
-       Hook::unregister('logger_instance', __FILE__, 'monolog_instance');
-}
-
-function monolog_instance(array &$data)
-{
-       if ($data['name'] !== 'monolog') {
-               return;
-       }
-
-       $loggerTimeZone = new \DateTimeZone('UTC');
-
-       $logger = new Monolog\Logger($data['channel']);
-       $logger->setTimezone($loggerTimeZone);
-       $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
-       $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
-       $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-       $logger->pushProcessor(new IntrospectionProcessor($data['introspection'], LogLevel::DEBUG));
-
-       $stream = DI::config()->get('system', 'logfile');
-
-       // just add a stream in case it's either writable or not file
-       if (!is_file($stream) || is_writable($stream)) {
-               try {
-                       $loglevel = Monolog\Logger::toMonologLevel($data['loglevel']);
-
-                       // fallback to notice if an invalid loglevel is set
-                       if (!is_int($loglevel)) {
-                               $loglevel = LogLevel::NOTICE;
-                       }
-
-                       $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
-
-                       $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
-                       $fileHandler->setFormatter($formatter);
-
-                       $logger->pushHandler($fileHandler);
-               } catch (\Throwable $e) {
-                       return;
-               }
-       }
-
-       $data['storage'] = $logger;
-}
diff --git a/monolog/src/DevelopHandler.php b/monolog/src/DevelopHandler.php
deleted file mode 100644 (file)
index e3d31e6..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Addon\monolog\src;
-
-use Friendica\App\Request;
-use Monolog\Handler;
-use Monolog\Logger;
-
-/**
- * Simple handler for Friendica developers to use for deeper logging
- *
- * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
- * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
- */
-class DevelopHandler extends Handler\AbstractHandler
-{
-       /**
-        * @var string The IP of the developer who wants to debug
-        */
-       private $developerIp;
-
-       /**
-        * @var string The IP of the current request
-        */
-       private $remoteAddress;
-
-       /**
-        * @param Request $request     The current http request
-        * @param string  $developerIp The IP of the developer who wants to debug
-        * @param int     $level       The minimum logging level at which this handler will be triggered
-        * @param bool    $bubble      Whether the messages that are handled can bubble up the stack or not
-        */
-       public function __construct(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true)
-       {
-               parent::__construct($level, $bubble);
-
-               $this->developerIp   = $developerIp;
-               $this->remoteAddress = $request->getRemoteAddress();
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function handle(array $record): bool
-       {
-               if (!$this->isHandling($record)) {
-                       return false;
-               }
-
-               /// Just in case the remote IP is the same as the developer IP log the output
-               if (!is_null($this->developerIp) && $this->remoteAddress != $this->developerIp) {
-                       return false;
-               }
-
-               return false === $this->bubble;
-       }
-}
diff --git a/monolog/src/Factory/Monolog.php b/monolog/src/Factory/Monolog.php
new file mode 100644 (file)
index 0000000..c5c6982
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+
+namespace Friendica\Addon\monolog\src\Factory;
+
+use Friendica\Addon\monolog\src\Monolog\IntrospectionProcessor;
+use Friendica\Core\Config\Capability\IManageConfigValues;
+use Friendica\Core\Logger\Factory\AbstractLoggerTypeFactory;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Handler\StreamHandler;
+use Monolog\Logger;
+use Monolog\Processor\ProcessIdProcessor;
+use Monolog\Processor\PsrLogMessageProcessor;
+use Monolog\Processor\UidProcessor;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+require_once __DIR__ . '/../../vendor/autoload.php';
+
+class Monolog extends AbstractLoggerTypeFactory
+{
+       public function create(IManageConfigValues $config, string $loglevel = null): LoggerInterface
+       {
+               $loggerTimeZone = new \DateTimeZone('UTC');
+
+               $logger = new Logger($this->channel);
+               $logger->setTimezone($loggerTimeZone);
+               $logger->pushProcessor(new PsrLogMessageProcessor());
+               $logger->pushProcessor(new ProcessIdProcessor());
+               $logger->pushProcessor(new UidProcessor());
+               $logger->pushProcessor(new IntrospectionProcessor($this->introspection, LogLevel::DEBUG));
+
+               $logfile = $config->get('system', 'logfile');
+
+               // just add a stream in case it's either writable or not file
+               if (is_writable($logfile)) {
+                       $loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($config->get('system', 'loglevel'));
+                       $loglevel = Logger::toMonologLevel($loglevel);
+
+                       // fallback to notice if an invalid loglevel is set
+                       if (!is_int($loglevel)) {
+                               $loglevel = LogLevel::NOTICE;
+                       }
+
+                       $fileHandler = new StreamHandler($logfile, $loglevel);
+
+                       $formatter = new LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
+                       $fileHandler->setFormatter($formatter);
+
+                       $logger->pushHandler($fileHandler);
+               }
+
+               return $logger;
+       }
+}
diff --git a/monolog/src/IntrospectionProcessor.php b/monolog/src/IntrospectionProcessor.php
deleted file mode 100644 (file)
index 8ba6023..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2023, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Addon\monolog\src;
-
-use Friendica\Core\Logger\Util\Introspection;
-use Monolog\Logger;
-use Monolog\LogRecord;
-use Monolog\Processor\ProcessorInterface;
-
-/**
- * Injects line/file//function where the log message came from
- */
-class IntrospectionProcessor implements ProcessorInterface
-{
-       private $level;
-
-       private $introspection;
-
-       /**
-        * @param Introspection $introspection Holds the Introspection of the current call
-        * @param string|int    $level         The minimum logging level at which this Processor will be triggered
-        */
-       public function __construct(Introspection $introspection, $level = Logger::DEBUG)
-       {
-               $this->level = Logger::toMonologLevel($level);
-               $introspection->addClasses(['Monolog\\']);
-               $this->introspection = $introspection;
-       }
-
-       public function __invoke(LogRecord $record): LogRecord
-       {
-               // return if the level is not high enough
-               if ($record->level < $this->level) {
-                       return $record;
-               }
-               // we should have the call source now
-               $record->extra = array_merge(
-                       $record->extra,
-                       $this->introspection->getRecord()
-               );
-
-               return $record;
-       }
-}
diff --git a/monolog/src/Monolog/DevelopHandler.php b/monolog/src/Monolog/DevelopHandler.php
new file mode 100644 (file)
index 0000000..735ebac
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Addon\monolog\src\Monolog;
+
+use Friendica\App\Request;
+use Monolog\Handler;
+use Monolog\Logger;
+
+/**
+ * Simple handler for Friendica developers to use for deeper logging
+ *
+ * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
+ * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
+ */
+class DevelopHandler extends Handler\AbstractHandler
+{
+       /**
+        * @var string The IP of the developer who wants to debug
+        */
+       private $developerIp;
+
+       /**
+        * @var string The IP of the current request
+        */
+       private $remoteAddress;
+
+       /**
+        * @param Request $request     The current http request
+        * @param string  $developerIp The IP of the developer who wants to debug
+        * @param int     $level       The minimum logging level at which this handler will be triggered
+        * @param bool    $bubble      Whether the messages that are handled can bubble up the stack or not
+        */
+       public function __construct(Request $request, $developerIp, int $level = Logger::DEBUG, bool $bubble = true)
+       {
+               parent::__construct($level, $bubble);
+
+               $this->developerIp   = $developerIp;
+               $this->remoteAddress = $request->getRemoteAddress();
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function handle(array $record): bool
+       {
+               if (!$this->isHandling($record)) {
+                       return false;
+               }
+
+               /// Just in case the remote IP is the same as the developer IP log the output
+               if (!is_null($this->developerIp) && $this->remoteAddress != $this->developerIp) {
+                       return false;
+               }
+
+               return false === $this->bubble;
+       }
+}
diff --git a/monolog/src/Monolog/IntrospectionProcessor.php b/monolog/src/Monolog/IntrospectionProcessor.php
new file mode 100644 (file)
index 0000000..2df0e21
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Addon\monolog\src\Monolog;
+
+use Friendica\Core\Logger\Util\Introspection;
+use Monolog\Logger;
+use Monolog\Processor\ProcessorInterface;
+
+/**
+ * Injects line/file//function where the log message came from
+ */
+class IntrospectionProcessor implements ProcessorInterface
+{
+       private $level;
+
+       private $introspection;
+
+       /**
+        * @param Introspection $introspection Holds the Introspection of the current call
+        * @param string|int    $level         The minimum logging level at which this Processor will be triggered
+        */
+       public function __construct(Introspection $introspection, $level = Logger::DEBUG)
+       {
+               $this->level = Logger::toMonologLevel($level);
+               $introspection->addClasses(['Monolog\\', static::class]);
+               $this->introspection = $introspection;
+       }
+
+       public function __invoke(array $record): array
+       {
+               // return if the level is not high enough
+               if ($record['level'] < $this->level) {
+                       return $record;
+               }
+               // we should have the call source now
+               $record['extra'] = array_merge(
+                       $record['extra'],
+                       $this->introspection->getRecord()
+               );
+
+               return $record;
+       }
+}
diff --git a/monolog/static/dependencies.config.php b/monolog/static/dependencies.config.php
new file mode 100644 (file)
index 0000000..365f382
--- /dev/null
@@ -0,0 +1,30 @@
+
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+return [
+       \Monolog\Logger::class => [
+               'instanceOf' => \Friendica\Addon\monolog\src\Factory\Monolog::class,
+               'call' => [
+                       ['create', [], \Dice\Dice::CHAIN_CALL],
+               ],
+       ],
+];
diff --git a/monolog/static/hooks.config.php b/monolog/static/hooks.config.php
new file mode 100644 (file)
index 0000000..cb3c7ef
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2023, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+use Friendica\Core\Hooks\Capabilities\HookType as H;
+
+return [
+       H::STRATEGY => [
+               \Psr\Log\LoggerInterface::class => [
+                       \Monolog\Logger::class => ['monolog'],
+               ],
+       ],
+];
index 706092031f63c55d984b3f1d339dce6525ae75bb..3c89f22cb76e927ecd7750bbd153df8ef9348693 100644 (file)
@@ -26,7 +26,6 @@ return array(
     'Monolog\\Formatter\\MongoDBFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php',
     'Monolog\\Formatter\\NormalizerFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
     'Monolog\\Formatter\\ScalarFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php',
-    'Monolog\\Formatter\\SyslogFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/SyslogFormatter.php',
     'Monolog\\Formatter\\WildfireFormatter' => $vendorDir . '/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php',
     'Monolog\\Handler\\AbstractHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
     'Monolog\\Handler\\AbstractProcessingHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
@@ -92,6 +91,7 @@ return array(
     'Monolog\\Handler\\SocketHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SocketHandler.php',
     'Monolog\\Handler\\SqsHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SqsHandler.php',
     'Monolog\\Handler\\StreamHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
+    'Monolog\\Handler\\SwiftMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php',
     'Monolog\\Handler\\SymfonyMailerHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php',
     'Monolog\\Handler\\SyslogHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogHandler.php',
     'Monolog\\Handler\\SyslogUdpHandler' => $vendorDir . '/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php',
@@ -121,12 +121,15 @@ return array(
     'Monolog\\SignalHandler' => $vendorDir . '/monolog/monolog/src/Monolog/SignalHandler.php',
     'Monolog\\Test\\TestCase' => $vendorDir . '/monolog/monolog/src/Monolog/Test/TestCase.php',
     'Monolog\\Utils' => $vendorDir . '/monolog/monolog/src/Monolog/Utils.php',
-    'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/src/AbstractLogger.php',
-    'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/src/InvalidArgumentException.php',
-    'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/src/LogLevel.php',
-    'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/src/LoggerAwareInterface.php',
-    'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/src/LoggerAwareTrait.php',
-    'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/src/LoggerInterface.php',
-    'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/src/LoggerTrait.php',
-    'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/src/NullLogger.php',
+    'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php',
+    'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php',
+    'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php',
+    'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php',
+    'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php',
+    'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php',
+    'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php',
+    'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php',
+    'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php',
+    'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
+    'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php',
 );
index afcfb31e10bb30e8116dbde09edf3e2794da87e8..9cb5b63dfb4926293a8ed3155c8c392bfe5c3f2c 100644 (file)
@@ -6,6 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
-    'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
+    'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
     'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
 );
index 85bd86fdeb4c7528b4f75cf1bff16edb87e3dcdb..95ed9e754a5571850ea21a604826cce83ed6ee0e 100644 (file)
@@ -20,7 +20,7 @@ class ComposerStaticInitMonologAddon
     public static $prefixDirsPsr4 = array (
         'Psr\\Log\\' => 
         array (
-            0 => __DIR__ . '/..' . '/psr/log/src',
+            0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
         ),
         'Monolog\\' => 
         array (
@@ -49,7 +49,6 @@ class ComposerStaticInitMonologAddon
         'Monolog\\Formatter\\MongoDBFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php',
         'Monolog\\Formatter\\NormalizerFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php',
         'Monolog\\Formatter\\ScalarFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php',
-        'Monolog\\Formatter\\SyslogFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/SyslogFormatter.php',
         'Monolog\\Formatter\\WildfireFormatter' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php',
         'Monolog\\Handler\\AbstractHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AbstractHandler.php',
         'Monolog\\Handler\\AbstractProcessingHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php',
@@ -115,6 +114,7 @@ class ComposerStaticInitMonologAddon
         'Monolog\\Handler\\SocketHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SocketHandler.php',
         'Monolog\\Handler\\SqsHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SqsHandler.php',
         'Monolog\\Handler\\StreamHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/StreamHandler.php',
+        'Monolog\\Handler\\SwiftMailerHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php',
         'Monolog\\Handler\\SymfonyMailerHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php',
         'Monolog\\Handler\\SyslogHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SyslogHandler.php',
         'Monolog\\Handler\\SyslogUdpHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php',
@@ -144,14 +144,17 @@ class ComposerStaticInitMonologAddon
         'Monolog\\SignalHandler' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/SignalHandler.php',
         'Monolog\\Test\\TestCase' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Test/TestCase.php',
         'Monolog\\Utils' => __DIR__ . '/..' . '/monolog/monolog/src/Monolog/Utils.php',
-        'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/src/AbstractLogger.php',
-        'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/src/InvalidArgumentException.php',
-        'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/src/LogLevel.php',
-        'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareInterface.php',
-        'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerAwareTrait.php',
-        'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/src/LoggerInterface.php',
-        'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/src/LoggerTrait.php',
-        'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/src/NullLogger.php',
+        'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php',
+        'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php',
+        'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php',
+        'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php',
+        'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php',
+        'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php',
+        'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php',
+        'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php',
+        'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php',
+        'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
+        'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php',
     );
 
     public static function getInitializer(ClassLoader $loader)
index c01706ed1d81591351be1dfc76ae57de25f4d8f5..ea2bb1784a885ea2fdb8c9be3a0d844fa502ba6c 100644 (file)
@@ -1,42 +1,43 @@
 [
     {
         "name": "monolog/monolog",
-        "version": "3.2.0",
-        "version_normalized": "3.2.0.0",
+        "version": "2.9.1",
+        "version_normalized": "2.9.1.0",
         "source": {
             "type": "git",
             "url": "https://github.com/Seldaek/monolog.git",
-            "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81"
+            "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/Seldaek/monolog/zipball/305444bc6fb6c89e490f4b34fa6e979584d7fa81",
-            "reference": "305444bc6fb6c89e490f4b34fa6e979584d7fa81",
+            "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+            "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
             "shasum": ""
         },
         "require": {
-            "php": ">=8.1",
-            "psr/log": "^2.0 || ^3.0"
+            "php": ">=7.2",
+            "psr/log": "^1.0.1 || ^2.0 || ^3.0"
         },
         "provide": {
-            "psr/log-implementation": "3.0.0"
+            "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
         },
         "require-dev": {
-            "aws/aws-sdk-php": "^3.0",
+            "aws/aws-sdk-php": "^2.4.9 || ^3.0",
             "doctrine/couchdb": "~1.0@dev",
             "elasticsearch/elasticsearch": "^7 || ^8",
             "ext-json": "*",
-            "graylog2/gelf-php": "^1.4.2",
+            "graylog2/gelf-php": "^1.4.2 || ^2@dev",
             "guzzlehttp/guzzle": "^7.4",
             "guzzlehttp/psr7": "^2.2",
             "mongodb/mongodb": "^1.8",
             "php-amqplib/php-amqplib": "~2.4 || ^3",
-            "phpstan/phpstan": "^1.4",
-            "phpstan/phpstan-deprecation-rules": "^1.0",
-            "phpstan/phpstan-strict-rules": "^1.1",
-            "phpunit/phpunit": "^9.5.16",
-            "predis/predis": "^1.1",
+            "phpspec/prophecy": "^1.15",
+            "phpstan/phpstan": "^0.12.91",
+            "phpunit/phpunit": "^8.5.14",
+            "predis/predis": "^1.1 || ^2.0",
+            "rollbar/rollbar": "^1.3 || ^2 || ^3",
             "ruflin/elastica": "^7",
+            "swiftmailer/swiftmailer": "^5.3|^6.0",
             "symfony/mailer": "^5.4 || ^6",
             "symfony/mime": "^5.4 || ^6"
         },
             "rollbar/rollbar": "Allow sending log messages to Rollbar",
             "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
         },
-        "time": "2022-07-24T12:00:55+00:00",
+        "time": "2023-02-06T13:44:46+00:00",
         "type": "library",
         "extra": {
             "branch-alias": {
-                "dev-main": "3.x-dev"
+                "dev-main": "2.x-dev"
             }
         },
         "installation-source": "dist",
     },
     {
         "name": "psr/log",
-        "version": "3.0.0",
-        "version_normalized": "3.0.0.0",
+        "version": "1.1.4",
+        "version_normalized": "1.1.4.0",
         "source": {
             "type": "git",
             "url": "https://github.com/php-fig/log.git",
-            "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+            "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
         },
         "dist": {
             "type": "zip",
-            "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
-            "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+            "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+            "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
             "shasum": ""
         },
         "require": {
-            "php": ">=8.0.0"
+            "php": ">=5.3.0"
         },
-        "time": "2021-07-14T16:46:02+00:00",
+        "time": "2021-05-03T11:20:27+00:00",
         "type": "library",
         "extra": {
             "branch-alias": {
-                "dev-master": "3.x-dev"
+                "dev-master": "1.1.x-dev"
             }
         },
         "installation-source": "dist",
         "autoload": {
             "psr-4": {
-                "Psr\\Log\\": "src"
+                "Psr\\Log\\": "Psr/Log/"
             }
         },
         "notification-url": "https://packagist.org/downloads/",
index fa0acea36ec3dd63ddc693b6094aa3df0f31b771..8a8c651244642eefe7908bbd7af811236834886a 100644 (file)
@@ -1,70 +1,17 @@
-### 3.2.0 (2022-07-24)
+### 2.9.1 (2023-02-06)
 
-  * Deprecated `CubeHandler` and `PHPConsoleHandler` as both projects are abandoned and those should not be used anymore (#1734)
-  * Marked `Logger` `@final` as it should not be extended, prefer composition or talk to us if you are missing something
-  * Added RFC 5424 level (`7` to `0`) support to `Logger::log` and `Logger::addRecord` to increase interoperability (#1723)
-  * Added `SyslogFormatter` to output syslog-like files which can be consumed by tools like [lnav](https://lnav.org/) (#1689)
-  * Added support for `__toString` for objects which are not json serializable in `JsonFormatter` (#1733)
-  * Added `GoogleCloudLoggingFormatter` (#1719)
-  * Added support for Predis 2.x (#1732)
-  * Added `AmqpHandler->setExtraAttributes` to allow configuring attributes when using an AMQPExchange (#1724)
-  * Fixed serialization/unserialization of handlers to make sure private properties are included (#1727)
-  * Fixed allowInlineLineBreaks in LineFormatter causing issues with windows paths containing `\n` or `\r` sequences (#1720)
-  * Fixed max normalization depth not being taken into account when formatting exceptions with a deep chain of previous exceptions (#1726)
-  * Fixed PHP 8.2 deprecation warnings (#1722)
-  * Fixed rare race condition or filesystem issue where StreamHandler is unable to create the directory the log should go into yet it exists already (#1678)
-
-### 3.1.0 (2022-06-09)
-
-  * Added `$datetime` parameter to `Logger::addRecord` as low level API to allow logging into the past or future (#1682)
-  * Added `Logger::useLoggingLoopDetection` to allow disabling cyclic logging detection in concurrent frameworks (#1681)
-  * Fixed handling of fatal errors if callPrevious is disabled in ErrorHandler (#1670)
-  * Fixed interop issue by removing the need for a return type in ProcessorInterface (#1680)
-  * Marked the reusable `Monolog\Test\TestCase` class as `@internal` to make sure PHPStorm does not show it above PHPUnit, you may still use it to test your own handlers/etc though (#1677)
-  * Fixed RotatingFileHandler issue when the date format contained slashes (#1671)
-
-### 3.0.0 (2022-05-10)
-
-Changes from RC1
-
-- The `Monolog\LevelName` enum does not exist anymore, use `Monolog\Level->getName()` instead.
-
-### 3.0.0-RC1 (2022-05-08)
-
-This is mostly a cleanup release offering stronger type guarantees for integrators with the
-array->object/enum changes, but there is no big new feature for end users.
-
-See [UPGRADE notes](UPGRADE.md#300) for details on all breaking changes especially if you are extending/implementing Monolog classes/interfaces.
-
-Noteworthy BC Breaks:
-
-- The minimum supported PHP version is now `8.1.0`.
-- Log records have been converted from an array to a [`Monolog\LogRecord` object](src/Monolog/LogRecord.php)
-  with public (and mostly readonly) properties. e.g. instead of doing
-  `$record['context']` use `$record->context`.
-  In formatters or handlers if you rather need an array to work with you can use `$record->toArray()`
-  to get back a Monolog 1/2 style record array. This will contain the enum values instead of enum cases
-  in the `level` and `level_name` keys to be more backwards compatible and use simpler data types.
-- `FormatterInterface`, `HandlerInterface`, `ProcessorInterface`, etc. changed to contain `LogRecord $record`
-  instead of `array $record` parameter types. If you want to support multiple Monolog versions this should
-  be possible by type-hinting nothing, or `array|LogRecord` if you support PHP 8.0+. You can then code
-  against the $record using Monolog 2 style as LogRecord implements ArrayAccess for BC.
-  The interfaces do not require a `LogRecord` return type even where it would be applicable, but if you only
-  support Monolog 3 in integration code I would recommend you use `LogRecord` return types wherever fitting
-  to ensure forward compatibility as it may be added in Monolog 4.
-- Log levels are now enums [`Monolog\Level`](src/Monolog/Level.php) and [`Monolog\LevelName`](src/Monolog/LevelName.php)
-- Removed deprecated SwiftMailerHandler, migrate to SymfonyMailerHandler instead.
-- `ResettableInterface::reset()` now requires a void return type.
-- All properties have had types added, which may require you to do so as well if you extended
-  a Monolog class and declared the same property.
+  * Fixed Logger not being serializable anymore (#1792)
 
-New deprecations:
+### 2.9.0 (2023-02-05)
 
-- `Logger::DEBUG`, `Logger::ERROR`, etc. are now deprecated in favor of the `Monolog\Level` enum.
-  e.g. instead of `Logger::WARNING` use `Level::Warning` if you need to pass the enum case
-  to Monolog or one of its handlers, or `Level::Warning->value` if you need the integer
-  value equal to what `Logger::WARNING` was giving you.
-- `Logger::getLevelName()` is now deprecated.
+  * Deprecated FlowdockHandler & Formatter as the flowdock service was shutdown (#1748)
+  * Added support for enum context values in PsrLogMessageProcessor (#1773)
+  * Added graylog2/gelf-php 2.x support (#1747)
+  * Improved `BrowserConsoleHandler` logging to use more appropriate methods than just console.log in the browser (#1739)
+  * Fixed `WhatFailureGroupHandler` not catching errors happening inside `close()` (#1791)
+  * Fixed datetime field in `GoogleCloudLoggingFormatter` (#1758)
+  * Fixed infinite loop detection within Fibers (#1753)
+  * Fixed `AmqpHandler->setExtraAttributes` not working with buffering handler wrappers (#1781)
 
 ### 2.8.0 (2022-07-24)
 
index 87c7f664daab826ef3172c72145cb680a2e54548..bfcae0c003d163d48c9dab7c56dd6b1b2a5509f2 100644 (file)
@@ -3,8 +3,6 @@
 [![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
 [![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
 
-> âš  This is the **documentation for Monolog 3.x**, if you are using older releases
-> see the documentation for [Monolog 2.x](https://github.com/Seldaek/monolog/blob/2.x/README.md) or [Monolog 1.x](https://github.com/Seldaek/monolog/blob/1.x/README.md) âš 
 
 Monolog sends your logs to files, sockets, inboxes, databases and various
 web services. See the complete list of handlers below. Special handlers
@@ -30,13 +28,12 @@ $ composer require monolog/monolog
 ```php
 <?php
 
-use Monolog\Level;
 use Monolog\Logger;
 use Monolog\Handler\StreamHandler;
 
 // create a log channel
 $log = new Logger('name');
-$log->pushHandler(new StreamHandler('path/to/your.log', Level::Warning));
+$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
 
 // add records to the log
 $log->warning('Foo');
@@ -53,7 +50,7 @@ $log->error('Bar');
 
 ## Support Monolog Financially
 
-Get supported Monolog and help fund the project with the [Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-monolog-monolog?utm_source=packagist-monolog-monolog&utm_medium=referral&utm_campaign=enterprise) or via [GitHub sponsorship](https://github.com/sponsors/Seldaek).
+Get supported Monolog and help fund the project with the [Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-monolog-monolog?utm_source=packagist-monolog-monolog&utm_medium=referral&utm_campaign=enterprise) or via [GitHub sponsorship](https://github.com/sponsors/Seldaek). 
 
 Tidelift delivers commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
 
@@ -67,13 +64,11 @@ can also add your own there if you publish one.
 
 ### Requirements
 
-- Monolog `^3.0` works with PHP 8.1 or above.
-- Monolog `^2.5` works with PHP 7.2 or above.
-- Monolog `^1.25` works with PHP 5.3 up to 8.1, but is not very maintained anymore and will not receive PHP support fixes anymore.
+- Monolog `^2.0` works with PHP 7.2 or above, use Monolog `^1.25` for PHP 5.3+ support.
 
 ### Support
 
-Monolog 1.x support is somewhat limited at this point and only important fixes will be done. You should migrate to Monolog 2 or 3 where possible to benefit from all the latest features and fixes.
+Monolog 1.x support is somewhat limited at this point and only important fixes will be done. You should migrate to Monolog 2 where possible to benefit from all the latest features and fixes.
 
 ### Submitting bugs and feature requests
 
index 3a48e6db4d04f514d10dffc0ac7cfe8612524ff5..b9437d6d5269cb7a62a6c221421a46f4d95b68ad 100644 (file)
         }
     ],
     "require": {
-        "php": ">=8.1",
-        "psr/log": "^2.0 || ^3.0"
+        "php": ">=7.2",
+        "psr/log": "^1.0.1 || ^2.0 || ^3.0"
     },
     "require-dev": {
         "ext-json": "*",
-        "aws/aws-sdk-php": "^3.0",
+        "aws/aws-sdk-php": "^2.4.9 || ^3.0",
         "doctrine/couchdb": "~1.0@dev",
         "elasticsearch/elasticsearch": "^7 || ^8",
-        "graylog2/gelf-php": "^1.4.2",
+        "graylog2/gelf-php": "^1.4.2 || ^2@dev",
         "guzzlehttp/guzzle": "^7.4",
         "guzzlehttp/psr7": "^2.2",
         "mongodb/mongodb": "^1.8",
         "php-amqplib/php-amqplib": "~2.4 || ^3",
-        "phpstan/phpstan": "^1.4",
-        "phpstan/phpstan-deprecation-rules": "^1.0",
-        "phpstan/phpstan-strict-rules": "^1.1",
-        "phpunit/phpunit": "^9.5.16",
-        "predis/predis": "^1.1",
+        "phpspec/prophecy": "^1.15",
+        "phpstan/phpstan": "^0.12.91",
+        "phpunit/phpunit": "^8.5.14",
+        "predis/predis": "^1.1 || ^2.0",
+        "rollbar/rollbar": "^1.3 || ^2 || ^3",
         "ruflin/elastica": "^7",
+        "swiftmailer/swiftmailer": "^5.3|^6.0",
         "symfony/mailer": "^5.4 || ^6",
         "symfony/mime": "^5.4 || ^6"
     },
         "psr-4": {"Monolog\\": "tests/Monolog"}
     },
     "provide": {
-        "psr/log-implementation": "3.0.0"
+        "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
     },
     "extra": {
         "branch-alias": {
-            "dev-main": "3.x-dev"
+            "dev-main": "2.x-dev"
         }
     },
     "scripts": {
@@ -72,6 +73,9 @@
     "config": {
         "lock": false,
         "sort-packages": true,
-        "platform-check": false
+        "platform-check": false,
+        "allow-plugins": {
+            "composer/package-versions-deprecated": true
+        }
     }
 }
index f8b2502170df87032450bf8c8e5eb358e770443c..188bbb0d86e9e121c2061f3886b05927f1bbe584 100644 (file)
@@ -13,24 +13,34 @@ namespace Monolog\Attribute;
 
 /**
  * A reusable attribute to help configure a class or a method as a processor.
- *
+ * 
  * Using it offers no guarantee: it needs to be leveraged by a Monolog third-party consumer.
- *
+ * 
  * Using it with the Monolog library only has no effect at all: processors should still be turned into a callable if
  * needed and manually pushed to the loggers and to the processable handlers.
  */
 #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
 class AsMonologProcessor
 {
+    /** @var string|null */
+    public $channel = null;
+    /** @var string|null */
+    public $handler = null;
+    /** @var string|null */
+    public $method = null;
+    
     /**
-     * @param string|null $channel The logging channel the processor should be pushed to.
-     * @param string|null $handler The handler the processor should be pushed to.
-     * @param string|null $method  The method that processes the records (if the attribute is used at the class level).
+     * @param string|null $channel  The logging channel the processor should be pushed to.
+     * @param string|null $handler  The handler the processor should be pushed to.
+     * @param string|null $method   The method that processes the records (if the attribute is used at the class level).
      */
     public function __construct(
-        public readonly ?string $channel = null,
-        public readonly ?string $handler = null,
-        public readonly ?string $method = null
+        ?string $channel = null,
+        ?string $handler = null,
+        ?string $method = null
     ) {
+        $this->channel = $channel;
+        $this->handler = $handler;
+        $this->method = $method;
     }
-}
+} 
index 274b73ea1df04ad740846cd22ecf9158677954a0..6a1ba9b25a30cfe9191c99436a5260b6481d0c59 100644 (file)
@@ -21,7 +21,10 @@ use DateTimeZone;
  */
 class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable
 {
-    private bool $useMicroseconds;
+    /**
+     * @var bool
+     */
+    private $useMicroseconds;
 
     public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null)
     {
index 2ed4603572e952465ed11fcc86742958b0115e13..576f1713f04c2034a7ab5ced65692b52e5675c1b 100644 (file)
@@ -11,7 +11,6 @@
 
 namespace Monolog;
 
-use Closure;
 use Psr\Log\LoggerInterface;
 use Psr\Log\LogLevel;
 
@@ -26,33 +25,35 @@ use Psr\Log\LogLevel;
  */
 class ErrorHandler
 {
-    private Closure|null $previousExceptionHandler = null;
+    /** @var LoggerInterface */
+    private $logger;
 
+    /** @var ?callable */
+    private $previousExceptionHandler = null;
     /** @var array<class-string, LogLevel::*> an array of class name to LogLevel::* constant mapping */
-    private array $uncaughtExceptionLevelMap = [];
-
-    /** @var Closure|true|null */
-    private Closure|bool|null $previousErrorHandler = null;
+    private $uncaughtExceptionLevelMap = [];
 
+    /** @var callable|true|null */
+    private $previousErrorHandler = null;
     /** @var array<int, LogLevel::*> an array of E_* constant to LogLevel::* constant mapping */
-    private array $errorLevelMap = [];
-
-    private bool $handleOnlyReportedErrors = true;
-
-    private bool $hasFatalErrorHandler = false;
-
-    private string $fatalLevel = LogLevel::ALERT;
-
-    private string|null $reservedMemory = null;
-
+    private $errorLevelMap = [];
+    /** @var bool */
+    private $handleOnlyReportedErrors = true;
+
+    /** @var bool */
+    private $hasFatalErrorHandler = false;
+    /** @var LogLevel::* */
+    private $fatalLevel = LogLevel::ALERT;
+    /** @var ?string */
+    private $reservedMemory = null;
     /** @var ?array{type: int, message: string, file: string, line: int, trace: mixed} */
-    private array|null $lastFatalData = null;
-
-    private const FATAL_ERRORS = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
+    private $lastFatalData = null;
+    /** @var int[] */
+    private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
 
-    public function __construct(
-        private LoggerInterface $logger
-    ) {
+    public function __construct(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
     }
 
     /**
@@ -60,6 +61,7 @@ class ErrorHandler
      *
      * By default it will handle errors, exceptions and fatal errors
      *
+     * @param  LoggerInterface                        $logger
      * @param  array<int, LogLevel::*>|false          $errorLevelMap     an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
      * @param  array<class-string, LogLevel::*>|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling
      * @param  LogLevel::*|null|false                 $fatalLevel        a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling
@@ -97,8 +99,8 @@ class ErrorHandler
                 $this->uncaughtExceptionLevelMap[$class] = $level;
             }
         }
-        if ($callPrevious && null !== $prev) {
-            $this->previousExceptionHandler = $prev(...);
+        if ($callPrevious && $prev) {
+            $this->previousExceptionHandler = $prev;
         }
 
         return $this;
@@ -110,10 +112,10 @@ class ErrorHandler
      */
     public function registerErrorHandler(array $levelMap = [], bool $callPrevious = true, int $errorTypes = -1, bool $handleOnlyReportedErrors = true): self
     {
-        $prev = set_error_handler($this->handleError(...), $errorTypes);
+        $prev = set_error_handler([$this, 'handleError'], $errorTypes);
         $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
         if ($callPrevious) {
-            $this->previousErrorHandler = $prev !== null ? $prev(...) : true;
+            $this->previousErrorHandler = $prev ?: true;
         } else {
             $this->previousErrorHandler = null;
         }
@@ -129,7 +131,7 @@ class ErrorHandler
      */
     public function registerFatalHandler($level = null, int $reservedMemorySize = 20): self
     {
-        register_shutdown_function($this->handleFatalError(...));
+        register_shutdown_function([$this, 'handleFatalError']);
 
         $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
         $this->fatalLevel = null === $level ? LogLevel::ALERT : $level;
@@ -173,7 +175,10 @@ class ErrorHandler
         ];
     }
 
-    private function handleException(\Throwable $e): never
+    /**
+     * @phpstan-return never
+     */
+    private function handleException(\Throwable $e): void
     {
         $level = LogLevel::ERROR;
         foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) {
@@ -189,25 +194,30 @@ class ErrorHandler
             ['exception' => $e]
         );
 
-        if (null !== $this->previousExceptionHandler) {
+        if ($this->previousExceptionHandler) {
             ($this->previousExceptionHandler)($e);
         }
 
-        if (!headers_sent() && !(bool) ini_get('display_errors')) {
+        if (!headers_sent() && !ini_get('display_errors')) {
             http_response_code(500);
         }
 
         exit(255);
     }
 
-    private function handleError(int $code, string $message, string $file = '', int $line = 0): bool
+    /**
+     * @private
+     *
+     * @param mixed[] $context
+     */
+    public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []): bool
     {
-        if ($this->handleOnlyReportedErrors && 0 === (error_reporting() & $code)) {
+        if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) {
             return false;
         }
 
         // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
-        if (!$this->hasFatalErrorHandler || !in_array($code, self::FATAL_ERRORS, true)) {
+        if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
             $level = $this->errorLevelMap[$code] ?? LogLevel::CRITICAL;
             $this->logger->log($level, self::codeToString($code).': '.$message, ['code' => $code, 'message' => $message, 'file' => $file, 'line' => $line]);
         } else {
@@ -218,9 +228,8 @@ class ErrorHandler
 
         if ($this->previousErrorHandler === true) {
             return false;
-        }
-        if ($this->previousErrorHandler instanceof Closure) {
-            return (bool) ($this->previousErrorHandler)($code, $message, $file, $line);
+        } elseif ($this->previousErrorHandler) {
+            return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context);
         }
 
         return true;
@@ -238,7 +247,8 @@ class ErrorHandler
         } else {
             $lastError = error_get_last();
         }
-        if (is_array($lastError) && in_array($lastError['type'], self::FATAL_ERRORS, true)) {
+
+        if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
             $trace = $lastError['trace'] ?? null;
             $this->logger->log(
                 $this->fatalLevel,
@@ -254,25 +264,44 @@ class ErrorHandler
         }
     }
 
-    private static function codeToString(int $code): string
+    /**
+     * @param int $code
+     */
+    private static function codeToString($code): string
     {
-        return match ($code) {
-            E_ERROR => 'E_ERROR',
-            E_WARNING => 'E_WARNING',
-            E_PARSE => 'E_PARSE',
-            E_NOTICE => 'E_NOTICE',
-            E_CORE_ERROR => 'E_CORE_ERROR',
-            E_CORE_WARNING => 'E_CORE_WARNING',
-            E_COMPILE_ERROR => 'E_COMPILE_ERROR',
-            E_COMPILE_WARNING => 'E_COMPILE_WARNING',
-            E_USER_ERROR => 'E_USER_ERROR',
-            E_USER_WARNING => 'E_USER_WARNING',
-            E_USER_NOTICE => 'E_USER_NOTICE',
-            E_STRICT => 'E_STRICT',
-            E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
-            E_DEPRECATED => 'E_DEPRECATED',
-            E_USER_DEPRECATED => 'E_USER_DEPRECATED',
-            default => 'Unknown PHP error',
-        };
+        switch ($code) {
+            case E_ERROR:
+                return 'E_ERROR';
+            case E_WARNING:
+                return 'E_WARNING';
+            case E_PARSE:
+                return 'E_PARSE';
+            case E_NOTICE:
+                return 'E_NOTICE';
+            case E_CORE_ERROR:
+                return 'E_CORE_ERROR';
+            case E_CORE_WARNING:
+                return 'E_CORE_WARNING';
+            case E_COMPILE_ERROR:
+                return 'E_COMPILE_ERROR';
+            case E_COMPILE_WARNING:
+                return 'E_COMPILE_WARNING';
+            case E_USER_ERROR:
+                return 'E_USER_ERROR';
+            case E_USER_WARNING:
+                return 'E_USER_WARNING';
+            case E_USER_NOTICE:
+                return 'E_USER_NOTICE';
+            case E_STRICT:
+                return 'E_STRICT';
+            case E_RECOVERABLE_ERROR:
+                return 'E_RECOVERABLE_ERROR';
+            case E_DEPRECATED:
+                return 'E_DEPRECATED';
+            case E_USER_DEPRECATED:
+                return 'E_USER_DEPRECATED';
+        }
+
+        return 'Unknown PHP error';
     }
 }
index 3f1d4582975f1c7f196588ca200695f5cf831a5d..aa1884b9c7aa293195df9d19245199b498d81831 100644 (file)
@@ -11,8 +11,7 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Formats a log message according to the ChromePHP array format
@@ -24,55 +23,52 @@ class ChromePHPFormatter implements FormatterInterface
     /**
      * Translates Monolog log levels to Wildfire levels.
      *
-     * @return 'log'|'info'|'warn'|'error'
+     * @var array<int, 'log'|'info'|'warn'|'error'>
      */
-    private function toWildfireLevel(Level $level): string
-    {
-        return match ($level) {
-            Level::Debug     => 'log',
-            Level::Info      => 'info',
-            Level::Notice    => 'info',
-            Level::Warning   => 'warn',
-            Level::Error     => 'error',
-            Level::Critical  => 'error',
-            Level::Alert     => 'error',
-            Level::Emergency => 'error',
-        };
-    }
+    private $logLevels = [
+        Logger::DEBUG     => 'log',
+        Logger::INFO      => 'info',
+        Logger::NOTICE    => 'info',
+        Logger::WARNING   => 'warn',
+        Logger::ERROR     => 'error',
+        Logger::CRITICAL  => 'error',
+        Logger::ALERT     => 'error',
+        Logger::EMERGENCY => 'error',
+    ];
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record)
+    public function format(array $record)
     {
         // Retrieve the line and file if set and remove them from the formatted extra
         $backtrace = 'unknown';
-        if (isset($record->extra['file'], $record->extra['line'])) {
-            $backtrace = $record->extra['file'].' : '.$record->extra['line'];
-            unset($record->extra['file'], $record->extra['line']);
+        if (isset($record['extra']['file'], $record['extra']['line'])) {
+            $backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
+            unset($record['extra']['file'], $record['extra']['line']);
         }
 
-        $message = ['message' => $record->message];
-        if (\count($record->context) > 0) {
-            $message['context'] = $record->context;
+        $message = ['message' => $record['message']];
+        if ($record['context']) {
+            $message['context'] = $record['context'];
         }
-        if (\count($record->extra) > 0) {
-            $message['extra'] = $record->extra;
+        if ($record['extra']) {
+            $message['extra'] = $record['extra'];
         }
         if (count($message) === 1) {
             $message = reset($message);
         }
 
         return [
-            $record->channel,
+            $record['channel'],
             $message,
             $backtrace,
-            $this->toWildfireLevel($record->level),
+            $this->logLevels[$record['level']],
         ];
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function formatBatch(array $records)
     {
index 160510ad852f3834dc87cd0daa3d5ff3f6d9960f..6c8a9ab5eaa514caf59610c3b070f726d6bd6f5c 100644 (file)
 namespace Monolog\Formatter;
 
 use Elastica\Document;
-use Monolog\LogRecord;
 
 /**
  * Format a log message into an Elastica Document
  *
  * @author Jelle Vink <jelle.vink@gmail.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class ElasticaFormatter extends NormalizerFormatter
 {
     /**
      * @var string Elastic search index name
      */
-    protected string $index;
+    protected $index;
 
     /**
-     * @var string|null Elastic search document type
+     * @var ?string Elastic search document type
      */
-    protected string|null $type;
+    protected $type;
 
     /**
      * @param string  $index Elastic Search index name
@@ -45,9 +46,9 @@ class ElasticaFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record)
+    public function format(array $record)
     {
         $record = parent::format($record);
 
@@ -71,13 +72,14 @@ class ElasticaFormatter extends NormalizerFormatter
     /**
      * Convert a log message into an Elastica Document
      *
-     * @param mixed[] $record
+     * @phpstan-param Record $record
      */
     protected function getDocument(array $record): Document
     {
         $document = new Document();
         $document->setData($record);
         if (method_exists($document, 'setType')) {
+            /** @phpstan-ignore-next-line */
             $document->setType($this->type);
         }
         $document->setIndex($this->index);
index 6c3eb9b2a70c6a8042e2130017b839a37d06e4a1..b792b819c2cf484e1b34b27dd2c770b7373e3d91 100644 (file)
@@ -12,7 +12,6 @@
 namespace Monolog\Formatter;
 
 use DateTimeInterface;
-use Monolog\LogRecord;
 
 /**
  * Format a log message into an Elasticsearch record
@@ -24,12 +23,12 @@ class ElasticsearchFormatter extends NormalizerFormatter
     /**
      * @var string Elasticsearch index name
      */
-    protected string $index;
+    protected $index;
 
     /**
      * @var string Elasticsearch record type
      */
-    protected string $type;
+    protected $type;
 
     /**
      * @param string $index Elasticsearch index name
@@ -45,9 +44,9 @@ class ElasticsearchFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record)
+    public function format(array $record)
     {
         $record = parent::format($record);
 
@@ -56,6 +55,8 @@ class ElasticsearchFormatter extends NormalizerFormatter
 
     /**
      * Getter index
+     *
+     * @return string
      */
     public function getIndex(): string
     {
@@ -64,6 +65,8 @@ class ElasticsearchFormatter extends NormalizerFormatter
 
     /**
      * Getter type
+     *
+     * @return string
      */
     public function getType(): string
     {
index b8f7be522d75855ad03aa19592177cac2240671f..867ae586bfdfcffa25453a4f2e5e66aeee094910 100644 (file)
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
  * formats the record to be used in the FlowdockHandler
  *
  * @author Dominik Liebler <liebler.dominik@gmail.com>
+ * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4
  */
 class FlowdockFormatter implements FormatterInterface
 {
-    private string $source;
+    /**
+     * @var string
+     */
+    private $source;
 
-    private string $sourceEmail;
+    /**
+     * @var string
+     */
+    private $sourceEmail;
 
     public function __construct(string $source, string $sourceEmail)
     {
@@ -31,41 +36,43 @@ class FlowdockFormatter implements FormatterInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @return mixed[]
      */
-    public function format(LogRecord $record): array
+    public function format(array $record): array
     {
         $tags = [
             '#logs',
-            '#' . $record->level->toPsrLogLevel(),
-            '#' . $record->channel,
+            '#' . strtolower($record['level_name']),
+            '#' . $record['channel'],
         ];
 
-        foreach ($record->extra as $value) {
+        foreach ($record['extra'] as $value) {
             $tags[] = '#' . $value;
         }
 
         $subject = sprintf(
             'in %s: %s - %s',
             $this->source,
-            $record->level->getName(),
-            $this->getShortMessage($record->message)
+            $record['level_name'],
+            $this->getShortMessage($record['message'])
         );
 
-        return [
+        $record['flowdock'] = [
             'source' => $this->source,
             'from_address' => $this->sourceEmail,
             'subject' => $subject,
-            'content' => $record->message,
+            'content' => $record['message'],
             'tags' => $tags,
             'project' => $this->source,
         ];
+
+        return $record;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @return mixed[][]
      */
index 9bd2c1604ad7afcf59f6fe53711c9f58b2dac285..29b14d30d9fede6daa35f0ad4091b67a631454b0 100644 (file)
@@ -12,7 +12,6 @@
 namespace Monolog\Formatter;
 
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Class FluentdFormatter
@@ -40,7 +39,7 @@ class FluentdFormatter implements FormatterInterface
     /**
      * @var bool $levelTag should message level be a part of the fluentd tag
      */
-    protected bool $levelTag = false;
+    protected $levelTag = false;
 
     public function __construct(bool $levelTag = false)
     {
@@ -56,25 +55,25 @@ class FluentdFormatter implements FormatterInterface
         return $this->levelTag;
     }
 
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
-        $tag = $record->channel;
+        $tag = $record['channel'];
         if ($this->levelTag) {
-            $tag .= '.' . $record->level->toPsrLogLevel();
+            $tag .= '.' . strtolower($record['level_name']);
         }
 
         $message = [
-            'message' => $record->message,
-            'context' => $record->context,
-            'extra' => $record->extra,
+            'message' => $record['message'],
+            'context' => $record['context'],
+            'extra' => $record['extra'],
         ];
 
         if (!$this->levelTag) {
-            $message['level'] = $record->level->value;
-            $message['level_name'] = $record->level->getName();
+            $message['level'] = $record['level'];
+            $message['level_name'] = $record['level_name'];
         }
 
-        return Utils::jsonEncode([$tag, $record->datetime->getTimestamp(), $message]);
+        return Utils::jsonEncode([$tag, $record['datetime']->getTimestamp(), $message]);
     }
 
     public function formatBatch(array $records): string
index 3413a4b05a0b5c7dcce0d669114ffbe5d0213fa0..19617ec5f4d95ed84fc3c2b1b7ff19b08b1dc73d 100644 (file)
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
  * Interface for formatters
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 interface FormatterInterface
 {
     /**
      * Formats a log record.
      *
-     * @param  LogRecord $record A record to format
-     * @return mixed     The formatted record
+     * @param  array $record A record to format
+     * @return mixed The formatted record
+     *
+     * @phpstan-param Record $record
      */
-    public function format(LogRecord $record);
+    public function format(array $record);
 
     /**
      * Formats a set of log records.
      *
-     * @param  array<LogRecord> $records A set of records to format
-     * @return mixed            The formatted set of records
+     * @param  array $records A set of records to format
+     * @return mixed The formatted set of records
+     *
+     * @phpstan-param Record[] $records
      */
     public function formatBatch(array $records);
 }
index 33116a261534ff191f54aedd14f6a9961ecfd182..3b3e1e7f6db7cdc81b317f40cba83b756ffa8544 100644 (file)
 
 namespace Monolog\Formatter;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Gelf\Message;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Serializes a log message to GELF
  * @see http://docs.graylog.org/en/latest/pages/gelf.html
  *
  * @author Matt Lehner <mlehner@gmail.com>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 class GelfMessageFormatter extends NormalizerFormatter
 {
@@ -29,39 +30,45 @@ class GelfMessageFormatter extends NormalizerFormatter
     /**
      * @var string the name of the system for the Gelf log message
      */
-    protected string $systemName;
+    protected $systemName;
 
     /**
      * @var string a prefix for 'extra' fields from the Monolog record (optional)
      */
-    protected string $extraPrefix;
+    protected $extraPrefix;
 
     /**
      * @var string a prefix for 'context' fields from the Monolog record (optional)
      */
-    protected string $contextPrefix;
+    protected $contextPrefix;
 
     /**
      * @var int max length per field
      */
-    protected int $maxLength;
+    protected $maxLength;
+
+    /**
+     * @var int
+     */
+    private $gelfVersion = 2;
 
     /**
      * Translates Monolog log levels to Graylog2 log priorities.
+     *
+     * @var array<int, int>
+     *
+     * @phpstan-var array<Level, int>
      */
-    private function getGraylog2Priority(Level $level): int
-    {
-        return match ($level) {
-            Level::Debug     => 7,
-            Level::Info      => 6,
-            Level::Notice    => 5,
-            Level::Warning   => 4,
-            Level::Error     => 3,
-            Level::Critical  => 2,
-            Level::Alert     => 1,
-            Level::Emergency => 0,
-        };
-    }
+    private $logLevels = [
+        Logger::DEBUG     => 7,
+        Logger::INFO      => 6,
+        Logger::NOTICE    => 5,
+        Logger::WARNING   => 4,
+        Logger::ERROR     => 3,
+        Logger::CRITICAL  => 2,
+        Logger::ALERT     => 1,
+        Logger::EMERGENCY => 0,
+    ];
 
     public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null)
     {
@@ -71,52 +78,64 @@ class GelfMessageFormatter extends NormalizerFormatter
 
         parent::__construct('U.u');
 
-        $this->systemName = (null === $systemName || $systemName === '') ? (string) gethostname() : $systemName;
+        $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName;
 
-        $this->extraPrefix = null === $extraPrefix ? '' : $extraPrefix;
+        $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix;
         $this->contextPrefix = $contextPrefix;
-        $this->maxLength = null === $maxLength ? self::DEFAULT_MAX_LENGTH : $maxLength;
+        $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength;
+
+        if (method_exists(Message::class, 'setFacility')) {
+            $this->gelfVersion = 1;
+        }
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record): Message
+    public function format(array $record): Message
     {
         $context = $extra = [];
-        if (isset($record->context)) {
+        if (isset($record['context'])) {
             /** @var mixed[] $context */
-            $context = parent::normalize($record->context);
+            $context = parent::normalize($record['context']);
         }
-        if (isset($record->extra)) {
+        if (isset($record['extra'])) {
             /** @var mixed[] $extra */
-            $extra = parent::normalize($record->extra);
+            $extra = parent::normalize($record['extra']);
+        }
+
+        if (!isset($record['datetime'], $record['message'], $record['level'])) {
+            throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given');
         }
 
         $message = new Message();
         $message
-            ->setTimestamp($record->datetime)
-            ->setShortMessage($record->message)
+            ->setTimestamp($record['datetime'])
+            ->setShortMessage((string) $record['message'])
             ->setHost($this->systemName)
-            ->setLevel($this->getGraylog2Priority($record->level));
+            ->setLevel($this->logLevels[$record['level']]);
 
         // message length + system name length + 200 for padding / metadata
-        $len = 200 + strlen($record->message) + strlen($this->systemName);
+        $len = 200 + strlen((string) $record['message']) + strlen($this->systemName);
 
         if ($len > $this->maxLength) {
-            $message->setShortMessage(Utils::substr($record->message, 0, $this->maxLength));
+            $message->setShortMessage(Utils::substr($record['message'], 0, $this->maxLength));
         }
 
-        if (isset($record->channel)) {
-            $message->setAdditional('facility', $record->channel);
-        }
-        if (isset($extra['line'])) {
-            $message->setAdditional('line', $extra['line']);
-            unset($extra['line']);
-        }
-        if (isset($extra['file'])) {
-            $message->setAdditional('file', $extra['file']);
-            unset($extra['file']);
+        if ($this->gelfVersion === 1) {
+            if (isset($record['channel'])) {
+                $message->setFacility($record['channel']);
+            }
+            if (isset($extra['line'])) {
+                $message->setLine($extra['line']);
+                unset($extra['line']);
+            }
+            if (isset($extra['file'])) {
+                $message->setFile($extra['file']);
+                unset($extra['file']);
+            }
+        } else {
+            $message->setAdditional('facility', $record['channel']);
         }
 
         foreach ($extra as $key => $val) {
@@ -141,10 +160,13 @@ class GelfMessageFormatter extends NormalizerFormatter
             $message->setAdditional($this->contextPrefix . $key, $val);
         }
 
-        if (!$message->hasAdditional('file') && isset($context['exception']['file'])) {
-            if (1 === preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) {
-                $message->setAdditional('file', $matches[1]);
-                $message->setAdditional('line', $matches[2]);
+        if ($this->gelfVersion === 1) {
+            /** @phpstan-ignore-next-line */
+            if (null === $message->getFile() && isset($context['exception']['file'])) {
+                if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) {
+                    $message->setFile($matches[1]);
+                    $message->setLine($matches[2]);
+                }
             }
         }
 
index d37d1e0ccbde211045ad0c3a55c304530d6a825c..ca52ebf4e5cc3c0d4087c97ef617a468e1d2b3d6 100644 (file)
@@ -17,23 +17,24 @@ use Monolog\LogRecord;
 /**
  * Encodes message information into JSON in a format compatible with Cloud logging.
  *
+ * @see https://cloud.google.com/logging/docs/structured-logging
  * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
  *
  * @author Luís Cobucci <lcobucci@gmail.com>
  */
 final class GoogleCloudLoggingFormatter extends JsonFormatter
 {
-    protected function normalizeRecord(LogRecord $record): array
+    /** {@inheritdoc} **/
+    public function format(array $record): string
     {
-        $normalized = parent::normalizeRecord($record);
-
         // Re-key level for GCP logging
-        $normalized['severity'] = $normalized['level_name'];
-        $normalized['timestamp'] = $record->datetime->format(DateTimeInterface::RFC3339_EXTENDED);
+        $record['severity'] = $record['level_name'];
+        $record['time'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED);
 
         // Remove keys that are not used by GCP
-        unset($normalized['level'], $normalized['level_name'], $normalized['datetime']);
+        unset($record['level'], $record['level_name'], $record['datetime']);
 
-        return $normalized;
+        return parent::format($record);
     }
 }
+
index bf1c61da39580aca8711d4f80294ecb280529ede..10a4311cb55c0c2c4cc9007497631e64eb778cce 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Formats incoming records into an HTML table
@@ -26,20 +25,19 @@ class HtmlFormatter extends NormalizerFormatter
 {
     /**
      * Translates Monolog log levels to html color priorities.
+     *
+     * @var array<int, string>
      */
-    protected function getLevelColor(Level $level): string
-    {
-        return match ($level) {
-            Level::Debug     => '#CCCCCC',
-            Level::Info      => '#28A745',
-            Level::Notice    => '#17A2B8',
-            Level::Warning   => '#FFC107',
-            Level::Error     => '#FD7E14',
-            Level::Critical  => '#DC3545',
-            Level::Alert     => '#821722',
-            Level::Emergency => '#000000',
-        };
-    }
+    protected $logLevels = [
+        Logger::DEBUG     => '#CCCCCC',
+        Logger::INFO      => '#28A745',
+        Logger::NOTICE    => '#17A2B8',
+        Logger::WARNING   => '#FFC107',
+        Logger::ERROR     => '#FD7E14',
+        Logger::CRITICAL  => '#DC3545',
+        Logger::ALERT     => '#821722',
+        Logger::EMERGENCY => '#000000',
+    ];
 
     /**
      * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format
@@ -69,13 +67,15 @@ class HtmlFormatter extends NormalizerFormatter
     /**
      * Create a HTML h1 tag
      *
-     * @param string $title Text to be in the h1
+     * @param  string $title Text to be in the h1
+     * @param  int    $level Error level
+     * @return string
      */
-    protected function addTitle(string $title, Level $level): string
+    protected function addTitle(string $title, int $level): string
     {
         $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
 
-        return '<h1 style="background: '.$this->getLevelColor($level).';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
+        return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
     }
 
     /**
@@ -83,25 +83,25 @@ class HtmlFormatter extends NormalizerFormatter
      *
      * @return string The formatted record
      */
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
-        $output = $this->addTitle($record->level->getName(), $record->level);
+        $output = $this->addTitle($record['level_name'], $record['level']);
         $output .= '<table cellspacing="1" width="100%" class="monolog-output">';
 
-        $output .= $this->addRow('Message', $record->message);
-        $output .= $this->addRow('Time', $this->formatDate($record->datetime));
-        $output .= $this->addRow('Channel', $record->channel);
-        if (\count($record->context) > 0) {
+        $output .= $this->addRow('Message', (string) $record['message']);
+        $output .= $this->addRow('Time', $this->formatDate($record['datetime']));
+        $output .= $this->addRow('Channel', $record['channel']);
+        if ($record['context']) {
             $embeddedTable = '<table cellspacing="1" width="100%">';
-            foreach ($record->context as $key => $value) {
+            foreach ($record['context'] as $key => $value) {
                 $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value));
             }
             $embeddedTable .= '</table>';
             $output .= $this->addRow('Context', $embeddedTable, false);
         }
-        if (\count($record->extra) > 0) {
+        if ($record['extra']) {
             $embeddedTable = '<table cellspacing="1" width="100%">';
-            foreach ($record->extra as $key => $value) {
+            foreach ($record['extra'] as $key => $value) {
                 $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value));
             }
             $embeddedTable .= '</table>';
index b2fc5bcbcce1227dd229817f5b9f176983b8df35..b737d82e35cdf8bfad74afadfba745e5b8c56a45 100644 (file)
@@ -11,9 +11,7 @@
 
 namespace Monolog\Formatter;
 
-use Stringable;
 use Throwable;
-use Monolog\LogRecord;
 
 /**
  * Encodes whatever record data is passed to it as json
@@ -21,6 +19,8 @@ use Monolog\LogRecord;
  * This can be useful to log to databases or remote APIs
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class JsonFormatter extends NormalizerFormatter
 {
@@ -28,13 +28,13 @@ class JsonFormatter extends NormalizerFormatter
     public const BATCH_MODE_NEWLINES = 2;
 
     /** @var self::BATCH_MODE_* */
-    protected int $batchMode;
-
-    protected bool $appendNewline;
-
-    protected bool $ignoreEmptyContextAndExtra;
-
-    protected bool $includeStacktraces = false;
+    protected $batchMode;
+    /** @var bool */
+    protected $appendNewline;
+    /** @var bool */
+    protected $ignoreEmptyContextAndExtra;
+    /** @var bool */
+    protected $includeStacktraces = false;
 
     /**
      * @param self::BATCH_MODE_* $batchMode
@@ -70,11 +70,11 @@ class JsonFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
-        $normalized = parent::format($record);
+        $normalized = $this->normalize($record);
 
         if (isset($normalized['context']) && $normalized['context'] === []) {
             if ($this->ignoreEmptyContextAndExtra) {
@@ -95,16 +95,23 @@ class JsonFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function formatBatch(array $records): string
     {
-        return match ($this->batchMode) {
-            static::BATCH_MODE_NEWLINES => $this->formatBatchNewlines($records),
-            default => $this->formatBatchJson($records),
-        };
+        switch ($this->batchMode) {
+            case static::BATCH_MODE_NEWLINES:
+                return $this->formatBatchNewlines($records);
+
+            case static::BATCH_MODE_JSON:
+            default:
+                return $this->formatBatchJson($records);
+        }
     }
 
+    /**
+     * @return self
+     */
     public function includeStacktraces(bool $include = true): self
     {
         $this->includeStacktraces = $include;
@@ -115,7 +122,7 @@ class JsonFormatter extends NormalizerFormatter
     /**
      * Return a JSON-encoded array of records.
      *
-     * @phpstan-param LogRecord[] $records
+     * @phpstan-param Record[] $records
      */
     protected function formatBatchJson(array $records): string
     {
@@ -126,24 +133,30 @@ class JsonFormatter extends NormalizerFormatter
      * Use new lines to separate records instead of a
      * JSON-encoded array.
      *
-     * @phpstan-param LogRecord[] $records
+     * @phpstan-param Record[] $records
      */
     protected function formatBatchNewlines(array $records): string
     {
+        $instance = $this;
+
         $oldNewline = $this->appendNewline;
         $this->appendNewline = false;
-        $formatted = array_map(fn (LogRecord $record) => $this->format($record), $records);
+        array_walk($records, function (&$value, $key) use ($instance) {
+            $value = $instance->format($value);
+        });
         $this->appendNewline = $oldNewline;
 
-        return implode("\n", $formatted);
+        return implode("\n", $records);
     }
 
     /**
      * Normalizes given $data.
      *
-     * @return null|scalar|array<mixed[]|scalar|null|object>|object
+     * @param mixed $data
+     *
+     * @return mixed
      */
-    protected function normalize(mixed $data, int $depth = 0): mixed
+    protected function normalize($data, int $depth = 0)
     {
         if ($depth > $this->maxNormalizeDepth) {
             return 'Over '.$this->maxNormalizeDepth.' levels deep, aborting normalization';
@@ -179,7 +192,7 @@ class JsonFormatter extends NormalizerFormatter
                 return $data;
             }
 
-            if ($data instanceof Stringable) {
+            if (method_exists($data, '__toString')) {
                 return $data->__toString();
             }
 
@@ -197,7 +210,7 @@ class JsonFormatter extends NormalizerFormatter
      * Normalizes given exception with or without its own stack trace based on
      * `includeStacktraces` property.
      *
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function normalizeException(Throwable $e, int $depth = 0): array
     {
index 19fb72c5304239b067d6347b9dc8bf40ae0c1b61..b31b2971a14e98f6a1fbb4c490b6a5fab951df3d 100644 (file)
@@ -11,9 +11,7 @@
 
 namespace Monolog\Formatter;
 
-use Closure;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Formats incoming records into a one-line string
@@ -27,16 +25,22 @@ class LineFormatter extends NormalizerFormatter
 {
     public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
 
-    protected string $format;
-    protected bool $allowInlineLineBreaks;
-    protected bool $ignoreEmptyContextAndExtra;
-    protected bool $includeStacktraces;
-    protected Closure|null $stacktracesParser = null;
+    /** @var string */
+    protected $format;
+    /** @var bool */
+    protected $allowInlineLineBreaks;
+    /** @var bool */
+    protected $ignoreEmptyContextAndExtra;
+    /** @var bool */
+    protected $includeStacktraces;
+    /** @var ?callable */
+    protected $stacktracesParser;
 
     /**
-     * @param string|null $format                The format of the message
-     * @param string|null $dateFormat            The format of the timestamp: one supported by DateTime::format
-     * @param bool        $allowInlineLineBreaks Whether to allow inline line breaks in log entries
+     * @param string|null $format                     The format of the message
+     * @param string|null $dateFormat                 The format of the timestamp: one supported by DateTime::format
+     * @param bool        $allowInlineLineBreaks      Whether to allow inline line breaks in log entries
+     * @param bool        $ignoreEmptyContextAndExtra
      */
     public function __construct(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = false, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = false)
     {
@@ -47,7 +51,7 @@ class LineFormatter extends NormalizerFormatter
         parent::__construct($dateFormat);
     }
 
-    public function includeStacktraces(bool $include = true, ?Closure $parser = null): self
+    public function includeStacktraces(bool $include = true, ?callable $parser = null): self
     {
         $this->includeStacktraces = $include;
         if ($this->includeStacktraces) {
@@ -73,13 +77,14 @@ class LineFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
         $vars = parent::format($record);
 
         $output = $this->format;
+
         foreach ($vars['extra'] as $var => $val) {
             if (false !== strpos($output, '%extra.'.$var.'%')) {
                 $output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
@@ -95,12 +100,12 @@ class LineFormatter extends NormalizerFormatter
         }
 
         if ($this->ignoreEmptyContextAndExtra) {
-            if (\count($vars['context']) === 0) {
+            if (empty($vars['context'])) {
                 unset($vars['context']);
                 $output = str_replace('%context%', '', $output);
             }
 
-            if (\count($vars['extra']) === 0) {
+            if (empty($vars['extra'])) {
                 unset($vars['extra']);
                 $output = str_replace('%extra%', '', $output);
             }
@@ -117,7 +122,6 @@ class LineFormatter extends NormalizerFormatter
             $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
             if (null === $output) {
                 $pcreErrorCode = preg_last_error();
-
                 throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
             }
         }
@@ -147,7 +151,7 @@ class LineFormatter extends NormalizerFormatter
     {
         $str = $this->formatException($e);
 
-        if (($previous = $e->getPrevious()) instanceof \Throwable) {
+        if ($previous = $e->getPrevious()) {
             do {
                 $depth++;
                 if ($depth > $this->maxNormalizeDepth) {
@@ -228,7 +232,7 @@ class LineFormatter extends NormalizerFormatter
     {
         $trace = $e->getTraceAsString();
 
-        if ($this->stacktracesParser !== null) {
+        if ($this->stacktracesParser) {
             $trace = $this->stacktracesParserCustom($trace);
         }
 
index 5f0b6a453fc2706f46334f4dfce11ae88832bb4b..29841aa3818bc3f910a6fcd1183e22f549efc1d9 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
  * Encodes message information into JSON in a format compatible with Loggly.
  *
@@ -35,13 +33,13 @@ class LogglyFormatter extends JsonFormatter
      * @see https://www.loggly.com/docs/automated-parsing/#json
      * @see \Monolog\Formatter\JsonFormatter::format()
      */
-    protected function normalizeRecord(LogRecord $record): array
+    public function format(array $record): string
     {
-        $recordData = parent::normalizeRecord($record);
-
-        $recordData["timestamp"] = $record->datetime->format("Y-m-d\TH:i:s.uO");
-        unset($recordData["datetime"]);
+        if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTimeInterface)) {
+            $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO");
+            unset($record["datetime"]);
+        }
 
-        return $recordData;
+        return parent::format($record);
     }
 }
index 10ad0d9c0a683930af37fbfaa8379c4266627995..b0451aba7859d5359014c0bf9ec554773a1ab2dd 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
  * Encodes message information into JSON in a format compatible with Logmatic.
  *
@@ -22,9 +20,15 @@ class LogmaticFormatter extends JsonFormatter
 {
     protected const MARKERS = ["sourcecode", "php"];
 
-    protected string $hostname = '';
+    /**
+     * @var string
+     */
+    protected $hostname = '';
 
-    protected string $appName = '';
+    /**
+     * @var string
+     */
+    protected $appname = '';
 
     public function setHostname(string $hostname): self
     {
@@ -33,9 +37,9 @@ class LogmaticFormatter extends JsonFormatter
         return $this;
     }
 
-    public function setAppName(string $appName): self
+    public function setAppname(string $appname): self
     {
-        $this->appName = $appName;
+        $this->appname = $appname;
 
         return $this;
     }
@@ -46,19 +50,17 @@ class LogmaticFormatter extends JsonFormatter
      * @see http://doc.logmatic.io/docs/basics-to-send-data
      * @see \Monolog\Formatter\JsonFormatter::format()
      */
-    public function normalizeRecord(LogRecord $record): array
+    public function format(array $record): string
     {
-        $record = parent::normalizeRecord($record);
-
-        if ($this->hostname !== '') {
+        if (!empty($this->hostname)) {
             $record["hostname"] = $this->hostname;
         }
-        if ($this->appName !== '') {
-            $record["appname"] = $this->appName;
+        if (!empty($this->appname)) {
+            $record["appname"] = $this->appname;
         }
 
         $record["@marker"] = static::MARKERS;
 
-        return $record;
+        return parent::format($record);
     }
 }
index d0e8749e30cf7a1b79e2419d93058cf0541d9800..f8de0d33312f378e2510cab1419630b66471ffcf 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
  * Serializes a log message to Logstash Event Format
  *
@@ -26,22 +24,22 @@ class LogstashFormatter extends NormalizerFormatter
     /**
      * @var string the name of the system for the Logstash log message, used to fill the @source field
      */
-    protected string $systemName;
+    protected $systemName;
 
     /**
      * @var string an application name for the Logstash log message, used to fill the @type field
      */
-    protected string $applicationName;
+    protected $applicationName;
 
     /**
      * @var string the key for 'extra' fields from the Monolog record
      */
-    protected string $extraKey;
+    protected $extraKey;
 
     /**
      * @var string the key for 'context' fields from the Monolog record
      */
-    protected string $contextKey;
+    protected $contextKey;
 
     /**
      * @param string      $applicationName The application that sends the data, used as the "type" field of logstash
@@ -61,38 +59,41 @@ class LogstashFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
-        $recordData = parent::format($record);
+        $record = parent::format($record);
 
+        if (empty($record['datetime'])) {
+            $record['datetime'] = gmdate('c');
+        }
         $message = [
-            '@timestamp' => $recordData['datetime'],
+            '@timestamp' => $record['datetime'],
             '@version' => 1,
             'host' => $this->systemName,
         ];
-        if (isset($recordData['message'])) {
-            $message['message'] = $recordData['message'];
+        if (isset($record['message'])) {
+            $message['message'] = $record['message'];
         }
-        if (isset($recordData['channel'])) {
-            $message['type'] = $recordData['channel'];
-            $message['channel'] = $recordData['channel'];
+        if (isset($record['channel'])) {
+            $message['type'] = $record['channel'];
+            $message['channel'] = $record['channel'];
         }
-        if (isset($recordData['level_name'])) {
-            $message['level'] = $recordData['level_name'];
+        if (isset($record['level_name'])) {
+            $message['level'] = $record['level_name'];
         }
-        if (isset($recordData['level'])) {
-            $message['monolog_level'] = $recordData['level'];
+        if (isset($record['level'])) {
+            $message['monolog_level'] = $record['level'];
         }
-        if ('' !== $this->applicationName) {
+        if ($this->applicationName) {
             $message['type'] = $this->applicationName;
         }
-        if (\count($recordData['extra']) > 0) {
-            $message[$this->extraKey] = $recordData['extra'];
+        if (!empty($record['extra'])) {
+            $message[$this->extraKey] = $record['extra'];
         }
-        if (\count($recordData['context']) > 0) {
-            $message[$this->contextKey] = $recordData['context'];
+        if (!empty($record['context'])) {
+            $message[$this->contextKey] = $record['context'];
         }
 
         return $this->toJson($message) . "\n";
index a3bdd4f872342ecc0012a0808a0ac344d7ebcfb1..fca69a899d34e7b617e85816f810b37ee49a379b 100644 (file)
@@ -14,7 +14,6 @@ namespace Monolog\Formatter;
 use MongoDB\BSON\Type;
 use MongoDB\BSON\UTCDateTime;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Formats a record for use with the MongoDBHandler.
@@ -23,12 +22,15 @@ use Monolog\LogRecord;
  */
 class MongoDBFormatter implements FormatterInterface
 {
-    private bool $exceptionTraceAsString;
-    private int $maxNestingLevel;
-    private bool $isLegacyMongoExt;
+    /** @var bool */
+    private $exceptionTraceAsString;
+    /** @var int */
+    private $maxNestingLevel;
+    /** @var bool */
+    private $isLegacyMongoExt;
 
     /**
-     * @param int  $maxNestingLevel        0 means infinite nesting, the $record itself is level 1, $record->context is 2
+     * @param int  $maxNestingLevel        0 means infinite nesting, the $record itself is level 1, $record['context'] is 2
      * @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
      */
     public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsString = true)
@@ -40,20 +42,20 @@ class MongoDBFormatter implements FormatterInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @return mixed[]
      */
-    public function format(LogRecord $record): array
+    public function format(array $record): array
     {
         /** @var mixed[] $res */
-        $res = $this->formatArray($record->toArray());
+        $res = $this->formatArray($record);
 
         return $res;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @return array<mixed[]>
      */
index 1323587b50797e38240c9f0a998153a7f0533556..5441bc0aadb521beef20e2b7417e8364a8efb6d3 100644 (file)
@@ -14,7 +14,6 @@ namespace Monolog\Formatter;
 use Monolog\DateTimeImmutable;
 use Monolog\Utils;
 use Throwable;
-use Monolog\LogRecord;
 
 /**
  * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
@@ -25,11 +24,15 @@ class NormalizerFormatter implements FormatterInterface
 {
     public const SIMPLE_DATE = "Y-m-d\TH:i:sP";
 
-    protected string $dateFormat;
-    protected int $maxNormalizeDepth = 9;
-    protected int $maxNormalizeItemCount = 1000;
+    /** @var string */
+    protected $dateFormat;
+    /** @var int */
+    protected $maxNormalizeDepth = 9;
+    /** @var int */
+    protected $maxNormalizeItemCount = 1000;
 
-    private int $jsonEncodeOptions = Utils::DEFAULT_JSON_FLAGS;
+    /** @var int */
+    private $jsonEncodeOptions = Utils::DEFAULT_JSON_FLAGS;
 
     /**
      * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format
@@ -43,25 +46,17 @@ class NormalizerFormatter implements FormatterInterface
     }
 
     /**
-     * @inheritDoc
-     */
-    public function format(LogRecord $record)
-    {
-        return $this->normalizeRecord($record);
-    }
-
-    /**
-     * Normalize an arbitrary value to a scalar|array|null
+     * {@inheritDoc}
      *
-     * @return null|scalar|array<mixed[]|scalar|null>
+     * @param mixed[] $record
      */
-    public function normalizeValue(mixed $data): mixed
+    public function format(array $record)
     {
-        return $this->normalize($data);
+        return $this->normalize($record);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function formatBatch(array $records)
     {
@@ -129,25 +124,10 @@ class NormalizerFormatter implements FormatterInterface
     }
 
     /**
-     * Provided as extension point
-     *
-     * Because normalize is called with sub-values of context data etc, normalizeRecord can be
-     * extended when data needs to be appended on the record array but not to other normalized data.
-     *
-     * @return array<mixed[]|scalar|null>
+     * @param  mixed                $data
+     * @return null|scalar|array<array|scalar|null>
      */
-    protected function normalizeRecord(LogRecord $record): array
-    {
-        /** @var array<mixed> $normalized */
-        $normalized = $this->normalize($record->toArray());
-
-        return $normalized;
-    }
-
-    /**
-     * @return null|scalar|array<mixed[]|scalar|null>
-     */
-    protected function normalize(mixed $data, int $depth = 0): mixed
+    protected function normalize($data, int $depth = 0)
     {
         if ($depth > $this->maxNormalizeDepth) {
             return 'Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization';
@@ -192,14 +172,14 @@ class NormalizerFormatter implements FormatterInterface
             }
 
             if ($data instanceof \JsonSerializable) {
-                /** @var null|scalar|array<mixed[]|scalar|null> $value */
+                /** @var null|scalar|array<array|scalar|null> $value */
                 $value = $data->jsonSerialize();
             } elseif (method_exists($data, '__toString')) {
                 /** @var string $value */
                 $value = $data->__toString();
             } else {
                 // the rest is normalized by json encoding and decoding it
-                /** @var null|scalar|array<mixed[]|scalar|null> $value */
+                /** @var null|scalar|array<array|scalar|null> $value */
                 $value = json_decode($this->toJson($data, true), true);
             }
 
@@ -253,12 +233,12 @@ class NormalizerFormatter implements FormatterInterface
 
         $trace = $e->getTrace();
         foreach ($trace as $frame) {
-            if (isset($frame['file'], $frame['line'])) {
+            if (isset($frame['file'])) {
                 $data['trace'][] = $frame['file'].':'.$frame['line'];
             }
         }
 
-        if (($previous = $e->getPrevious()) instanceof \Throwable) {
+        if ($previous = $e->getPrevious()) {
             $data['previous'] = $this->normalizeException($previous, $depth + 1);
         }
 
@@ -277,7 +257,10 @@ class NormalizerFormatter implements FormatterInterface
         return Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors);
     }
 
-    protected function formatDate(\DateTimeInterface $date): string
+    /**
+     * @return string
+     */
+    protected function formatDate(\DateTimeInterface $date)
     {
         // in case the date format isn't custom then we defer to the custom DateTimeImmutable
         // formatting logic, which will pick the right format based on whether useMicroseconds is on
index 4bc20a08cde7aa087e81312e2b8d1b99a29a2a75..187bc550de160b7b60a0a4751abaeec16783d531 100644 (file)
 
 namespace Monolog\Formatter;
 
-use Monolog\LogRecord;
-
 /**
- * Formats data into an associative array of scalar (+ null) values.
+ * Formats data into an associative array of scalar values.
  * Objects and arrays will be JSON encoded.
  *
  * @author Andrew Lawson <adlawson@gmail.com>
@@ -22,21 +20,25 @@ use Monolog\LogRecord;
 class ScalarFormatter extends NormalizerFormatter
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @phpstan-return array<string, scalar|null> $record
      */
-    public function format(LogRecord $record): array
+    public function format(array $record): array
     {
         $result = [];
-        foreach ($record->toArray() as $key => $value) {
-            $result[$key] = $this->toScalar($value);
+        foreach ($record as $key => $value) {
+            $result[$key] = $this->normalizeValue($value);
         }
 
         return $result;
     }
 
-    protected function toScalar(mixed $value): string|int|float|bool|null
+    /**
+     * @param  mixed                      $value
+     * @return scalar|null
+     */
+    protected function normalizeValue($value)
     {
         $normalized = $this->normalize($value);
 
diff --git a/monolog/vendor/monolog/monolog/src/Monolog/Formatter/SyslogFormatter.php b/monolog/vendor/monolog/monolog/src/Monolog/Formatter/SyslogFormatter.php
deleted file mode 100644 (file)
index 6ed7e92..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php declare(strict_types=1);
-
-/*
- * This file is part of the Monolog package.
- *
- * (c) Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Monolog\Formatter;
-
-use Monolog\Level;
-use Monolog\LogRecord;
-
-/**
- * Serializes a log message according to RFC 5424
- *
- * @author Dalibor Karlović <dalibor.karlovic@sigwin.hr>
- * @author Renat Gabdullin <renatobyj@gmail.com>
- */
-class SyslogFormatter extends LineFormatter
-{
-    private const SYSLOG_FACILITY_USER = 1;
-    private const FORMAT = "<%extra.priority%>1 %datetime% %extra.hostname% %extra.app-name% %extra.procid% %channel% %extra.structured-data% %level_name%: %message% %context% %extra%\n";
-    private const NILVALUE = '-';
-
-    private string $hostname;
-    private int $procid;
-
-    public function __construct(private string $applicationName = self::NILVALUE)
-    {
-        parent::__construct(self::FORMAT, 'Y-m-d\TH:i:s.uP', true, true);
-        $this->hostname = (string) gethostname();
-        $this->procid = (int) getmypid();
-    }
-
-    public function format(LogRecord $record): string
-    {
-        $record->extra = $this->formatExtra($record);
-
-        return parent::format($record);
-    }
-
-    /**
-     * @param LogRecord $record
-     * @return array<string, mixed>
-     */
-    private function formatExtra(LogRecord $record): array
-    {
-        $extra = $record->extra;
-        $extra['app-name'] = $this->applicationName;
-        $extra['hostname'] = $this->hostname;
-        $extra['procid'] = $this->procid;
-        $extra['priority'] = self::calculatePriority($record->level);
-        $extra['structured-data'] = self::NILVALUE;
-
-        return $extra;
-    }
-
-    private static function calculatePriority(Level $level): int
-    {
-        return (self::SYSLOG_FACILITY_USER * 8) + $level->toRFC5424Level();
-    }
-}
index 8ef7b7d14dfef14a56043876c97a460efe6d6823..6539b34739bdac03909e7bc515fc6e1ee7619f3e 100644 (file)
@@ -11,8 +11,7 @@
 
 namespace Monolog\Formatter;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Serializes a log message according to Wildfire's header requirements
@@ -20,9 +19,27 @@ use Monolog\LogRecord;
  * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
  * @author Christophe Coevoet <stof@notk.org>
  * @author Kirill chEbba Chebunin <iam@chebba.org>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 class WildfireFormatter extends NormalizerFormatter
 {
+    /**
+     * Translates Monolog log levels to Wildfire levels.
+     *
+     * @var array<Level, string>
+     */
+    private $logLevels = [
+        Logger::DEBUG     => 'LOG',
+        Logger::INFO      => 'INFO',
+        Logger::NOTICE    => 'INFO',
+        Logger::WARNING   => 'WARN',
+        Logger::ERROR     => 'ERROR',
+        Logger::CRITICAL  => 'ERROR',
+        Logger::ALERT     => 'ERROR',
+        Logger::EMERGENCY => 'ERROR',
+    ];
+
     /**
      * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format
      */
@@ -35,61 +52,46 @@ class WildfireFormatter extends NormalizerFormatter
     }
 
     /**
-     * Translates Monolog log levels to Wildfire levels.
+     * {@inheritDoc}
      *
-     * @return 'LOG'|'INFO'|'WARN'|'ERROR'
-     */
-    private function toWildfireLevel(Level $level): string
-    {
-        return match ($level) {
-            Level::Debug     => 'LOG',
-            Level::Info      => 'INFO',
-            Level::Notice    => 'INFO',
-            Level::Warning   => 'WARN',
-            Level::Error     => 'ERROR',
-            Level::Critical  => 'ERROR',
-            Level::Alert     => 'ERROR',
-            Level::Emergency => 'ERROR',
-        };
-    }
-
-    /**
-     * @inheritDoc
+     * @return string
      */
-    public function format(LogRecord $record): string
+    public function format(array $record): string
     {
         // Retrieve the line and file if set and remove them from the formatted extra
         $file = $line = '';
-        if (isset($record->extra['file'])) {
-            $file = $record->extra['file'];
-            unset($record->extra['file']);
+        if (isset($record['extra']['file'])) {
+            $file = $record['extra']['file'];
+            unset($record['extra']['file']);
         }
-        if (isset($record->extra['line'])) {
-            $line = $record->extra['line'];
-            unset($record->extra['line']);
+        if (isset($record['extra']['line'])) {
+            $line = $record['extra']['line'];
+            unset($record['extra']['line']);
         }
 
-        $message = ['message' => $record->message];
+        /** @var mixed[] $record */
+        $record = $this->normalize($record);
+        $message = ['message' => $record['message']];
         $handleError = false;
-        if (count($record->context) > 0) {
-            $message['context'] = $this->normalize($record->context);
+        if ($record['context']) {
+            $message['context'] = $record['context'];
             $handleError = true;
         }
-        if (count($record->extra) > 0) {
-            $message['extra'] = $this->normalize($record->extra);
+        if ($record['extra']) {
+            $message['extra'] = $record['extra'];
             $handleError = true;
         }
         if (count($message) === 1) {
             $message = reset($message);
         }
 
-        if (is_array($message) && isset($message['context']['table'])) {
+        if (isset($record['context']['table'])) {
             $type  = 'TABLE';
-            $label = $record->channel .': '. $record->message;
-            $message = $message['context']['table'];
+            $label = $record['channel'] .': '. $record['message'];
+            $message = $record['context']['table'];
         } else {
-            $type  = $this->toWildfireLevel($record->level);
-            $label = $record->channel;
+            $type  = $this->logLevels[$record['level']];
+            $label = $record['channel'];
         }
 
         // Create JSON object describing the appearance of the message in the console
@@ -112,7 +114,7 @@ class WildfireFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @phpstan-return never
      */
@@ -122,11 +124,11 @@ class WildfireFormatter extends NormalizerFormatter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
-     * @return null|scalar|array<mixed[]|scalar|null>|object
+     * @return null|scalar|array<array|scalar|null>|object
      */
-    protected function normalize(mixed $data, int $depth = 0): mixed
+    protected function normalize($data, int $depth = 0)
     {
         if (is_object($data) && !$data instanceof \DateTimeInterface) {
             return $data;
index 3399a54e237fbd9111f7586a179ab8a8517623ea..a5cdaa71fa7e6175f6f4bcffd99912289368a5fc 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Monolog\ResettableInterface;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Base Handler class providing basic level/bubble support
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 abstract class AbstractHandler extends Handler implements ResettableInterface
 {
-    protected Level $level = Level::Debug;
-    protected bool $bubble = true;
+    /**
+     * @var int
+     * @phpstan-var Level
+     */
+    protected $level = Logger::DEBUG;
+    /** @var bool */
+    protected $bubble = true;
 
     /**
-     * @param int|string|Level|LogLevel::* $level  The minimum logging level at which this handler will be triggered
-     * @param bool                                   $bubble Whether the messages that are handled can bubble up the stack or not
+     * @param int|string $level  The minimum logging level at which this handler will be triggered
+     * @param bool       $bubble Whether the messages that are handled can bubble up the stack or not
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($level = Logger::DEBUG, bool $bubble = true)
     {
         $this->setLevel($level);
         $this->bubble = $bubble;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
-        return $record->level->value >= $this->level->value;
+        return $record['level'] >= $this->level;
     }
 
     /**
      * Sets minimum logging level at which this handler will be triggered.
      *
-     * @param Level|LogLevel::* $level Level or level name
-     *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @param  Level|LevelName|LogLevel::* $level Level or level name
+     * @return self
      */
-    public function setLevel(int|string|Level $level): self
+    public function setLevel($level): self
     {
         $this->level = Logger::toMonologLevel($level);
 
@@ -63,8 +68,12 @@ abstract class AbstractHandler extends Handler implements ResettableInterface
 
     /**
      * Gets minimum logging level at which this handler will be triggered.
+     *
+     * @return int
+     *
+     * @phpstan-return Level
      */
-    public function getLevel(): Level
+    public function getLevel(): int
     {
         return $this->level;
     }
@@ -72,8 +81,9 @@ abstract class AbstractHandler extends Handler implements ResettableInterface
     /**
      * Sets the bubbling behavior.
      *
-     * @param bool $bubble true means that this handler allows bubbling.
-     *                     false means that bubbling is not permitted.
+     * @param  bool $bubble true means that this handler allows bubbling.
+     *                      false means that bubbling is not permitted.
+     * @return self
      */
     public function setBubble(bool $bubble): self
     {
@@ -94,9 +104,9 @@ abstract class AbstractHandler extends Handler implements ResettableInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function reset(): void
+    public function reset()
     {
     }
 }
index de13a76bec87441509538d97212a8992def79793..77e533fca5855d37257638bbd77769567ca98986 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Handler;
 
-use Monolog\LogRecord;
-
 /**
  * Base Handler class providing the Handler structure, including processors and formatters
  *
@@ -20,6 +18,11 @@ use Monolog\LogRecord;
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
  * @author Christophe Coevoet <stof@notk.org>
+ *
+ * @phpstan-import-type LevelName from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed}
  */
 abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
 {
@@ -27,19 +30,20 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc
     use FormattableHandlerTrait;
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         if (!$this->isHandling($record)) {
             return false;
         }
 
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
-        $record->formatted = $this->getFormatter()->format($record);
+        $record['formatted'] = $this->getFormatter()->format($record);
 
         $this->write($record);
 
@@ -47,11 +51,16 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc
     }
 
     /**
-     * Writes the (already formatted) record down to the log of the implementing handler
+     * Writes the record down to the log of the implementing handler
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    abstract protected function write(LogRecord $record): void;
+    abstract protected function write(array $record): void;
 
-    public function reset(): void
+    /**
+     * @return void
+     */
+    public function reset()
     {
         parent::reset();
 
index 695a1c07f4f2543e250f825f33a88292031b73f0..5e5ad1c1f4f320a364a6151dc64a57903e047632 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LineFormatter;
 
 /**
  * Common syslog functionality
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 abstract class AbstractSyslogHandler extends AbstractProcessingHandler
 {
-    protected int $facility;
+    /** @var int */
+    protected $facility;
 
     /**
-     * List of valid log facility names.
-     * @var array<string, int>
+     * Translates Monolog log levels to syslog log priorities.
+     * @var array
+     * @phpstan-var array<Level, int>
      */
-    protected array $facilities = [
-        'auth'     => \LOG_AUTH,
-        'authpriv' => \LOG_AUTHPRIV,
-        'cron'     => \LOG_CRON,
-        'daemon'   => \LOG_DAEMON,
-        'kern'     => \LOG_KERN,
-        'lpr'      => \LOG_LPR,
-        'mail'     => \LOG_MAIL,
-        'news'     => \LOG_NEWS,
-        'syslog'   => \LOG_SYSLOG,
-        'user'     => \LOG_USER,
-        'uucp'     => \LOG_UUCP,
+    protected $logLevels = [
+        Logger::DEBUG     => LOG_DEBUG,
+        Logger::INFO      => LOG_INFO,
+        Logger::NOTICE    => LOG_NOTICE,
+        Logger::WARNING   => LOG_WARNING,
+        Logger::ERROR     => LOG_ERR,
+        Logger::CRITICAL  => LOG_CRIT,
+        Logger::ALERT     => LOG_ALERT,
+        Logger::EMERGENCY => LOG_EMERG,
     ];
 
     /**
-     * Translates Monolog log levels to syslog log priorities.
+     * List of valid log facility names.
+     * @var array<string, int>
      */
-    protected function toSyslogPriority(Level $level): int
-    {
-        return $level->toRFC5424Level();
-    }
+    protected $facilities = [
+        'auth'     => LOG_AUTH,
+        'authpriv' => LOG_AUTHPRIV,
+        'cron'     => LOG_CRON,
+        'daemon'   => LOG_DAEMON,
+        'kern'     => LOG_KERN,
+        'lpr'      => LOG_LPR,
+        'mail'     => LOG_MAIL,
+        'news'     => LOG_NEWS,
+        'syslog'   => LOG_SYSLOG,
+        'user'     => LOG_USER,
+        'uucp'     => LOG_UUCP,
+    ];
 
     /**
      * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
      */
-    public function __construct(string|int $facility = \LOG_USER, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
         if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
-            $this->facilities['local0'] = \LOG_LOCAL0;
-            $this->facilities['local1'] = \LOG_LOCAL1;
-            $this->facilities['local2'] = \LOG_LOCAL2;
-            $this->facilities['local3'] = \LOG_LOCAL3;
-            $this->facilities['local4'] = \LOG_LOCAL4;
-            $this->facilities['local5'] = \LOG_LOCAL5;
-            $this->facilities['local6'] = \LOG_LOCAL6;
-            $this->facilities['local7'] = \LOG_LOCAL7;
+            $this->facilities['local0'] = LOG_LOCAL0;
+            $this->facilities['local1'] = LOG_LOCAL1;
+            $this->facilities['local2'] = LOG_LOCAL2;
+            $this->facilities['local3'] = LOG_LOCAL3;
+            $this->facilities['local4'] = LOG_LOCAL4;
+            $this->facilities['local5'] = LOG_LOCAL5;
+            $this->facilities['local6'] = LOG_LOCAL6;
+            $this->facilities['local7'] = LOG_LOCAL7;
         } else {
             $this->facilities['local0'] = 128; // LOG_LOCAL0
             $this->facilities['local1'] = 136; // LOG_LOCAL1
@@ -86,7 +97,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index b25e4f139abd53562e08dddc07e1c3f32ad8067c..994872ce899cc84a56d973e4ce657514c42498a2 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\JsonFormatter;
 use PhpAmqpLib\Message\AMQPMessage;
 use PhpAmqpLib\Channel\AMQPChannel;
 use AMQPExchange;
-use Monolog\LogRecord;
 
+/**
+ * @phpstan-import-type Record from \Monolog\Logger
+ */
 class AmqpHandler extends AbstractProcessingHandler
 {
-    protected AMQPExchange|AMQPChannel $exchange;
-
-    /** @var array<string, mixed> */
-    private array $extraAttributes = [];
-
-    protected string $exchangeName;
-
     /**
-     * @param AMQPExchange|AMQPChannel $exchange     AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
-     * @param string|null              $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only
+     * @var AMQPExchange|AMQPChannel $exchange
      */
-    public function __construct(AMQPExchange|AMQPChannel $exchange, ?string $exchangeName = null, int|string|Level $level = Level::Debug, bool $bubble = true)
-    {
-        if ($exchange instanceof AMQPChannel) {
-            $this->exchangeName = (string) $exchangeName;
-        } elseif ($exchangeName !== null) {
-            @trigger_error('The $exchangeName parameter can only be passed when using PhpAmqpLib, if using an AMQPExchange instance configure it beforehand', E_USER_DEPRECATED);
-        }
-        $this->exchange = $exchange;
-
-        parent::__construct($level, $bubble);
-    }
+    protected $exchange;
+    /** @var array<string, mixed> */
+    private $extraAttributes = [];
 
     /**
      * @return array<string, mixed>
@@ -59,7 +45,7 @@ class AmqpHandler extends AbstractProcessingHandler
      *                                               message_id, user_id, app_id, delivery_mode,
      *                                               priority, timestamp, expiration, type
      *                                               or reply_to, headers.
-     * @return $this
+     * @return AmqpHandler
      */
     public function setExtraAttributes(array $extraAttributes): self
     {
@@ -68,11 +54,34 @@ class AmqpHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * @var string
      */
-    protected function write(LogRecord $record): void
+    protected $exchangeName;
+
+    /**
+     * @param AMQPExchange|AMQPChannel $exchange     AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
+     * @param string|null              $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only
+     */
+    public function __construct($exchange, ?string $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true)
+    {
+        if ($exchange instanceof AMQPChannel) {
+            $this->exchangeName = (string) $exchangeName;
+        } elseif (!$exchange instanceof AMQPExchange) {
+            throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required');
+        } elseif ($exchangeName) {
+            @trigger_error('The $exchangeName parameter can only be passed when using PhpAmqpLib, if using an AMQPExchange instance configure it beforehand', E_USER_DEPRECATED);
+        }
+        $this->exchange = $exchange;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record): void
     {
-        $data = $record->formatted;
+        $data = $record["formatted"];
         $routingKey = $this->getRoutingKey($record);
 
         if ($this->exchange instanceof AMQPExchange) {
@@ -80,7 +89,7 @@ class AmqpHandler extends AbstractProcessingHandler
                 'delivery_mode' => 2,
                 'content_type'  => 'application/json',
             ];
-            if (\count($this->extraAttributes) > 0) {
+            if ($this->extraAttributes) {
                 $attributes = array_merge($attributes, $this->extraAttributes);
             }
             $this->exchange->publish(
@@ -99,7 +108,7 @@ class AmqpHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -114,6 +123,7 @@ class AmqpHandler extends AbstractProcessingHandler
                 continue;
             }
 
+            /** @var Record $record */
             $record = $this->processRecord($record);
             $data = $this->getFormatter()->format($record);
 
@@ -129,27 +139,30 @@ class AmqpHandler extends AbstractProcessingHandler
 
     /**
      * Gets the routing key for the AMQP exchange
+     *
+     * @phpstan-param Record $record
      */
-    protected function getRoutingKey(LogRecord $record): string
+    protected function getRoutingKey(array $record): string
     {
-        $routingKey = sprintf('%s.%s', $record->level->name, $record->channel);
+        $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']);
 
         return strtolower($routingKey);
     }
 
     private function createAmqpMessage(string $data): AMQPMessage
     {
-        return new AMQPMessage(
-            $data,
-            [
-                'delivery_mode' => 2,
-                'content_type' => 'application/json',
-            ]
-        );
+        $attributes = [
+            'delivery_mode' => 2,
+            'content_type' => 'application/json',
+        ];
+        if ($this->extraAttributes) {
+            $attributes = array_merge($attributes, $this->extraAttributes);
+        }
+        return new AMQPMessage($data, $attributes);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 28564b3fc0ccd2223b748bf14ecb4466eaa5a3b0..95bbfed42630815a98e0fb521b0b054ff61c4662 100644 (file)
@@ -14,30 +14,35 @@ namespace Monolog\Handler;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LineFormatter;
 use Monolog\Utils;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 use function count;
 use function headers_list;
 use function stripos;
+use function trigger_error;
+
+use const E_USER_DEPRECATED;
 
 /**
  * Handler sending logs to browser's javascript console with no browser extension required
  *
  * @author Olivier Poitrey <rs@dailymotion.com>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class BrowserConsoleHandler extends AbstractProcessingHandler
 {
-    protected static bool $initialized = false;
-
-    /** @var LogRecord[] */
-    protected static array $records = [];
+    /** @var bool */
+    protected static $initialized = false;
+    /** @var FormattedRecord[] */
+    protected static $records = [];
 
     protected const FORMAT_HTML = 'html';
     protected const FORMAT_JS = 'js';
     protected const FORMAT_UNKNOWN = 'unknown';
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format.
      *
@@ -51,9 +56,9 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         // Accumulate records
         static::$records[] = $record;
@@ -76,11 +81,11 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
             return;
         }
 
-        if (count(static::$records) > 0) {
+        if (count(static::$records)) {
             if ($format === self::FORMAT_HTML) {
-                static::writeOutput('<script>' . self::generateScript() . '</script>');
-            } else { // js format
-                static::writeOutput(self::generateScript());
+                static::writeOutput('<script>' . static::generateScript() . '</script>');
+            } elseif ($format === self::FORMAT_JS) {
+                static::writeOutput(static::generateScript());
             }
             static::resetStatic();
         }
@@ -91,7 +96,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
         self::resetStatic();
     }
 
-    public function reset(): void
+    public function reset()
     {
         parent::reset();
 
@@ -169,18 +174,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
     {
         $script = [];
         foreach (static::$records as $record) {
-            $context = self::dump('Context', $record->context);
-            $extra = self::dump('Extra', $record->extra);
+            $context = static::dump('Context', $record['context']);
+            $extra = static::dump('Extra', $record['extra']);
 
-            if (\count($context) === 0 && \count($extra) === 0) {
-                $script[] = self::call_array('log', self::handleStyles($record->formatted));
+            if (empty($context) && empty($extra)) {
+                $script[] = static::call_array(static::getConsoleMethodForLevel($record['level']), static::handleStyles($record['formatted']));
             } else {
                 $script = array_merge(
                     $script,
-                    [self::call_array('groupCollapsed', self::handleStyles($record->formatted))],
+                    [static::call_array('groupCollapsed', static::handleStyles($record['formatted']))],
                     $context,
                     $extra,
-                    [self::call('groupEnd')]
+                    [static::call('groupEnd')]
                 );
             }
         }
@@ -188,6 +193,20 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
         return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
     }
 
+    private static function getConsoleMethodForLevel(int $level): string
+    {
+        return [
+            Logger::DEBUG => 'debug',
+            Logger::INFO => 'info',
+            Logger::NOTICE => 'info',
+            Logger::WARNING => 'warn',
+            Logger::ERROR => 'error',
+            Logger::CRITICAL => 'error',
+            Logger::ALERT => 'error',
+            Logger::EMERGENCY => 'error',
+        ][$level] ?? 'log';
+    }
+
     /**
      * @return string[]
      */
@@ -199,14 +218,14 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
 
         foreach (array_reverse($matches) as $match) {
             $args[] = '"font-weight: normal"';
-            $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0]));
+            $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
 
             $pos = $match[0][1];
             $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + strlen($match[0][0]));
         }
 
-        $args[] = self::quote('font-weight: normal');
-        $args[] = self::quote($format);
+        $args[] = static::quote('font-weight: normal');
+        $args[] = static::quote($format);
 
         return array_reverse($args);
     }
@@ -232,7 +251,6 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
 
         if (null === $style) {
             $pcreErrorCode = preg_last_error();
-
             throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
         }
 
@@ -247,16 +265,16 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
     {
         $script = [];
         $dict = array_filter($dict);
-        if (\count($dict) === 0) {
+        if (empty($dict)) {
             return $script;
         }
-        $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title));
+        $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title));
         foreach ($dict as $key => $value) {
             $value = json_encode($value);
             if (empty($value)) {
-                $value = self::quote('');
+                $value = static::quote('');
             }
-            $script[] = self::call('log', self::quote('%s: %o'), self::quote((string) $key), $value);
+            $script[] = static::call('log', static::quote('%s: %o'), static::quote((string) $key), $value);
         }
 
         return $script;
@@ -277,7 +295,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
             throw new \UnexpectedValueException('Expected the first arg to be a string, got: '.var_export($method, true));
         }
 
-        return self::call_array($method, $args);
+        return static::call_array($method, $args);
     }
 
     /**
index ff89faa8a31fe85061c56eb9edd824b010f12ad9..fcce5d630977707a1582772387c0fe7593e3a663 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\ResettableInterface;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Buffers all records until closing the handler and then pass them as batch.
@@ -23,30 +22,32 @@ use Monolog\LogRecord;
  * sending one per log message.
  *
  * @author Christophe Coevoet <stof@notk.org>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
 {
     use ProcessableHandlerTrait;
 
-    protected HandlerInterface $handler;
-
-    protected int $bufferSize = 0;
-
-    protected int $bufferLimit;
-
-    protected bool $flushOnOverflow;
-
-    /** @var LogRecord[] */
-    protected array $buffer = [];
-
-    protected bool $initialized = false;
+    /** @var HandlerInterface */
+    protected $handler;
+    /** @var int */
+    protected $bufferSize = 0;
+    /** @var int */
+    protected $bufferLimit;
+    /** @var bool */
+    protected $flushOnOverflow;
+    /** @var Record[] */
+    protected $buffer = [];
+    /** @var bool */
+    protected $initialized = false;
 
     /**
      * @param HandlerInterface $handler         Handler.
      * @param int              $bufferLimit     How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
      * @param bool             $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
      */
-    public function __construct(HandlerInterface $handler, int $bufferLimit = 0, int|string|Level $level = Level::Debug, bool $bubble = true, bool $flushOnOverflow = false)
+    public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $level = Logger::DEBUG, bool $bubble = true, bool $flushOnOverflow = false)
     {
         parent::__construct($level, $bubble);
         $this->handler = $handler;
@@ -55,11 +56,11 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if ($record->level->isLowerThan($this->level)) {
+        if ($record['level'] < $this->level) {
             return false;
         }
 
@@ -78,7 +79,8 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
             }
         }
 
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
@@ -106,7 +108,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -124,7 +126,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
         $this->buffer = [];
     }
 
-    public function reset(): void
+    public function reset()
     {
         $this->flush();
 
@@ -138,7 +140,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -152,7 +154,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
index 3742d47d9d826ffefb36da51fda2c5515bc5ed9a..234ecf614e25f2f36ac0502794fb0dbdc8b6356d 100644 (file)
@@ -13,10 +13,8 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\ChromePHPFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
-use Monolog\DateTimeImmutable;
 
 /**
  * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
@@ -24,6 +22,8 @@ use Monolog\DateTimeImmutable;
  * This also works out of the box with Firefox 43+
  *
  * @author Christophe Coevoet <stof@notk.org>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class ChromePHPHandler extends AbstractProcessingHandler
 {
@@ -44,25 +44,29 @@ class ChromePHPHandler extends AbstractProcessingHandler
      */
     protected const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}';
 
-    protected static bool $initialized = false;
+    /** @var bool */
+    protected static $initialized = false;
 
     /**
      * Tracks whether we sent too much data
      *
      * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending
+     *
+     * @var bool
      */
-    protected static bool $overflowed = false;
+    protected static $overflowed = false;
 
     /** @var mixed[] */
-    protected static array $json = [
+    protected static $json = [
         'version' => self::VERSION,
         'columns' => ['label', 'log', 'backtrace', 'type'],
         'rows' => [],
     ];
 
-    protected static bool $sendHeaders = true;
+    /** @var bool */
+    protected static $sendHeaders = true;
 
-    public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
         if (!function_exists('json_encode')) {
@@ -71,7 +75,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -82,15 +86,15 @@ class ChromePHPHandler extends AbstractProcessingHandler
         $messages = [];
 
         foreach ($records as $record) {
-            if ($record->level < $this->level) {
+            if ($record['level'] < $this->level) {
                 continue;
             }
-
+            /** @var Record $message */
             $message = $this->processRecord($record);
             $messages[] = $message;
         }
 
-        if (\count($messages) > 0) {
+        if (!empty($messages)) {
             $messages = $this->getFormatter()->formatBatch($messages);
             self::$json['rows'] = array_merge(self::$json['rows'], $messages);
             $this->send();
@@ -98,7 +102,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
@@ -111,13 +115,13 @@ class ChromePHPHandler extends AbstractProcessingHandler
      * @see sendHeader()
      * @see send()
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!$this->isWebRequest()) {
             return;
         }
 
-        self::$json['rows'][] = $record->formatted;
+        self::$json['rows'][] = $record['formatted'];
 
         $this->send();
     }
@@ -149,12 +153,15 @@ class ChromePHPHandler extends AbstractProcessingHandler
         if (strlen($data) > 3 * 1024) {
             self::$overflowed = true;
 
-            $record = new LogRecord(
-                message: 'Incomplete logs, chrome header size limit reached',
-                level: Level::Warning,
-                channel: 'monolog',
-                datetime: new DateTimeImmutable(true),
-            );
+            $record = [
+                'message' => 'Incomplete logs, chrome header size limit reached',
+                'context' => [],
+                'level' => Logger::WARNING,
+                'level_name' => Logger::getLevelName(Logger::WARNING),
+                'channel' => 'monolog',
+                'datetime' => new \DateTimeImmutable(),
+                'extra' => [],
+            ];
             self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
             $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true);
             $data = base64_encode($json);
@@ -180,7 +187,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
      */
     protected function headersAccepted(): bool
     {
-        if (!isset($_SERVER['HTTP_USER_AGENT'])) {
+        if (empty($_SERVER['HTTP_USER_AGENT'])) {
             return false;
         }
 
index 8d9c10e761327f51216d3399c2b0e0cd35b257dc..52657613230f700dbb0108f8950a919a684c4f65 100644 (file)
@@ -13,42 +13,22 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\JsonFormatter;
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * CouchDB handler
  *
  * @author Markus Bachmann <markus.bachmann@bachi.biz>
- * @phpstan-type Options array{
- *     host: string,
- *     port: int,
- *     dbname: string,
- *     username: string|null,
- *     password: string|null
- * }
- * @phpstan-type InputOptions array{
- *     host?: string,
- *     port?: int,
- *     dbname?: string,
- *     username?: string|null,
- *     password?: string|null
- * }
  */
 class CouchDBHandler extends AbstractProcessingHandler
 {
-    /**
-     * @var mixed[]
-     * @phpstan-var Options
-     */
-    private array $options;
+    /** @var mixed[] */
+    private $options;
 
     /**
      * @param mixed[] $options
-     *
-     * @phpstan-param InputOptions $options
      */
-    public function __construct(array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(array $options = [], $level = Logger::DEBUG, bool $bubble = true)
     {
         $this->options = array_merge([
             'host'     => 'localhost',
@@ -62,12 +42,12 @@ class CouchDBHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         $basicAuth = null;
-        if (null !== $this->options['username'] && null !== $this->options['password']) {
+        if ($this->options['username']) {
             $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
         }
 
@@ -75,7 +55,7 @@ class CouchDBHandler extends AbstractProcessingHandler
         $context = stream_context_create([
             'http' => [
                 'method'        => 'POST',
-                'content'       => $record->formatted,
+                'content'       => $record['formatted'],
                 'ignore_errors' => true,
                 'max_redirects' => 0,
                 'header'        => 'Content-type: application/json',
@@ -88,7 +68,7 @@ class CouchDBHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 8388f5ade74d4a6bb22fd2b0a46699fbc999e000..3535a4fcd75c6259f6eeb1603a24a6c543456ef9 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Logs to Cube.
@@ -24,13 +23,18 @@ use Monolog\LogRecord;
  */
 class CubeHandler extends AbstractProcessingHandler
 {
-    private ?\Socket $udpConnection = null;
-    private ?\CurlHandle $httpConnection = null;
-    private string $scheme;
-    private string $host;
-    private int $port;
+    /** @var resource|\Socket|null */
+    private $udpConnection = null;
+    /** @var resource|\CurlHandle|null */
+    private $httpConnection = null;
+    /** @var string */
+    private $scheme;
+    /** @var string */
+    private $host;
+    /** @var int */
+    private $port;
     /** @var string[] */
-    private array $acceptedSchemes = ['http', 'udp'];
+    private $acceptedSchemes = ['http', 'udp'];
 
     /**
      * Create a Cube handler
@@ -39,7 +43,7 @@ class CubeHandler extends AbstractProcessingHandler
      *                                   A valid url must consist of three parts : protocol://host:port
      *                                   Only valid protocols used by Cube are http and udp
      */
-    public function __construct(string $url, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(string $url, $level = Logger::DEBUG, bool $bubble = true)
     {
         $urlInfo = parse_url($url);
 
@@ -47,7 +51,7 @@ class CubeHandler extends AbstractProcessingHandler
             throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
         }
 
-        if (!in_array($urlInfo['scheme'], $this->acceptedSchemes, true)) {
+        if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) {
             throw new \UnexpectedValueException(
                 'Invalid protocol (' . $urlInfo['scheme']  . ').'
                 . ' Valid options are ' . implode(', ', $this->acceptedSchemes)
@@ -56,7 +60,7 @@ class CubeHandler extends AbstractProcessingHandler
 
         $this->scheme = $urlInfo['scheme'];
         $this->host = $urlInfo['host'];
-        $this->port = $urlInfo['port'];
+        $this->port = (int) $urlInfo['port'];
 
         parent::__construct($level, $bubble);
     }
@@ -107,24 +111,24 @@ class CubeHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $date = $record->datetime;
+        $date = $record['datetime'];
 
         $data = ['time' => $date->format('Y-m-d\TH:i:s.uO')];
-        $context = $record->context;
+        unset($record['datetime']);
 
-        if (isset($context['type'])) {
-            $data['type'] = $context['type'];
-            unset($context['type']);
+        if (isset($record['context']['type'])) {
+            $data['type'] = $record['context']['type'];
+            unset($record['context']['type']);
         } else {
-            $data['type'] = $record->channel;
+            $data['type'] = $record['channel'];
         }
 
-        $data['data'] = $context;
-        $data['data']['level'] = $record->level;
+        $data['data'] = $record['context'];
+        $data['data']['level'] = $record['level'];
 
         if ($this->scheme === 'http') {
             $this->writeHttp(Utils::jsonEncode($data));
@@ -135,20 +139,16 @@ class CubeHandler extends AbstractProcessingHandler
 
     private function writeUdp(string $data): void
     {
-        if (null === $this->udpConnection) {
+        if (!$this->udpConnection) {
             $this->connectUdp();
         }
 
-        if (null === $this->udpConnection) {
-            throw new \LogicException('No UDP socket could be opened');
-        }
-
         socket_send($this->udpConnection, $data, strlen($data), 0);
     }
 
     private function writeHttp(string $data): void
     {
-        if (null === $this->httpConnection) {
+        if (!$this->httpConnection) {
             $this->connectHttp();
         }
 
index 4decf0e62ed931027e5f8ee5394282f998bfbd6f..7213e8ee237de86e5da030b89bd7c7d83c219178 100644 (file)
@@ -21,7 +21,7 @@ use CurlHandle;
 final class Util
 {
     /** @var array<int> */
-    private static array $retriableErrorCodes = [
+    private static $retriableErrorCodes = [
         CURLE_COULDNT_RESOLVE_HOST,
         CURLE_COULDNT_CONNECT,
         CURLE_HTTP_NOT_FOUND,
@@ -34,17 +34,19 @@ final class Util
     /**
      * Executes a CURL request with optional retries and exception on failure
      *
-     * @param  CurlHandle  $ch curl handler
-     * @return bool|string @see curl_exec
+     * @param  resource|CurlHandle $ch             curl handler
+     * @param  int                 $retries
+     * @param  bool                $closeAfterDone
+     * @return bool|string         @see curl_exec
      */
-    public static function execute(CurlHandle $ch, int $retries = 5, bool $closeAfterDone = true)
+    public static function execute($ch, int $retries = 5, bool $closeAfterDone = true)
     {
         while ($retries--) {
             $curlResponse = curl_exec($ch);
             if ($curlResponse === false) {
                 $curlErrno = curl_errno($ch);
 
-                if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || $retries === 0) {
+                if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) {
                     $curlError = curl_error($ch);
 
                     if ($closeAfterDone) {
index 355491219044b3e6d8a9842434fbec2f2b860c1d..9b85ae7edc7f5c89e61fa864df239e4d54ae47f9 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Simple handler wrapper that deduplicates log records across multiple requests
@@ -35,29 +33,45 @@ use Monolog\LogRecord;
  * same way.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 class DeduplicationHandler extends BufferHandler
 {
-    protected string $deduplicationStore;
+    /**
+     * @var string
+     */
+    protected $deduplicationStore;
 
-    protected Level $deduplicationLevel;
+    /**
+     * @var Level
+     */
+    protected $deduplicationLevel;
 
-    protected int $time;
+    /**
+     * @var int
+     */
+    protected $time;
 
-    private bool $gc = false;
+    /**
+     * @var bool
+     */
+    private $gc = false;
 
     /**
-     * @param HandlerInterface                       $handler            Handler.
-     * @param string                                 $deduplicationStore The file/path where the deduplication log should be kept
-     * @param int|string|Level|LogLevel::* $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
-     * @param int                                    $time               The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
-     * @param bool                                   $bubble             Whether the messages that are handled can bubble up the stack or not
+     * @param HandlerInterface $handler            Handler.
+     * @param string           $deduplicationStore The file/path where the deduplication log should be kept
+     * @param string|int       $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
+     * @param int              $time               The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
+     * @param bool             $bubble             Whether the messages that are handled can bubble up the stack or not
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $deduplicationLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $deduplicationLevel
      */
-    public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, int|string|Level $deduplicationLevel = Level::Error, int $time = 60, bool $bubble = true)
+    public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true)
     {
-        parent::__construct($handler, 0, Level::Debug, $bubble, false);
+        parent::__construct($handler, 0, Logger::DEBUG, $bubble, false);
 
         $this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore;
         $this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel);
@@ -73,8 +87,8 @@ class DeduplicationHandler extends BufferHandler
         $passthru = null;
 
         foreach ($this->buffer as $record) {
-            if ($record->level->value >= $this->deduplicationLevel->value) {
-                $passthru = $passthru === true || !$this->isDuplicate($record);
+            if ($record['level'] >= $this->deduplicationLevel) {
+                $passthru = $passthru || !$this->isDuplicate($record);
                 if ($passthru) {
                     $this->appendRecord($record);
                 }
@@ -93,7 +107,10 @@ class DeduplicationHandler extends BufferHandler
         }
     }
 
-    private function isDuplicate(LogRecord $record): bool
+    /**
+     * @phpstan-param Record $record
+     */
+    private function isDuplicate(array $record): bool
     {
         if (!file_exists($this->deduplicationStore)) {
             return false;
@@ -105,13 +122,13 @@ class DeduplicationHandler extends BufferHandler
         }
 
         $yesterday = time() - 86400;
-        $timestampValidity = $record->datetime->getTimestamp() - $this->time;
-        $expectedMessage = preg_replace('{[\r\n].*}', '', $record->message);
+        $timestampValidity = $record['datetime']->getTimestamp() - $this->time;
+        $expectedMessage = preg_replace('{[\r\n].*}', '', $record['message']);
 
         for ($i = count($store) - 1; $i >= 0; $i--) {
             list($timestamp, $level, $message) = explode(':', $store[$i], 3);
 
-            if ($level === $record->level->getName() && $message === $expectedMessage && $timestamp > $timestampValidity) {
+            if ($level === $record['level_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) {
                 return true;
             }
 
@@ -131,7 +148,7 @@ class DeduplicationHandler extends BufferHandler
 
         $handle = fopen($this->deduplicationStore, 'rw+');
 
-        if (false === $handle) {
+        if (!$handle) {
             throw new \RuntimeException('Failed to open file for reading and writing: ' . $this->deduplicationStore);
         }
 
@@ -142,7 +159,7 @@ class DeduplicationHandler extends BufferHandler
 
         while (!feof($handle)) {
             $log = fgets($handle);
-            if (is_string($log) && '' !== $log && substr($log, 0, 10) >= $timestampValidity) {
+            if ($log && substr($log, 0, 10) >= $timestampValidity) {
                 $validLogs[] = $log;
             }
         }
@@ -159,8 +176,11 @@ class DeduplicationHandler extends BufferHandler
         $this->gc = false;
     }
 
-    private function appendRecord(LogRecord $record): void
+    /**
+     * @phpstan-param Record $record
+     */
+    private function appendRecord(array $record): void
     {
-        file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->level->getName() . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND);
+        file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND);
     }
 }
index eab9f1089d834b596472508a12c9a91c5537d8a1..ebd52c3a0de1c68cf432b36abc83e973b0aeab60 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\NormalizerFormatter;
 use Monolog\Formatter\FormatterInterface;
 use Doctrine\CouchDB\CouchDBClient;
-use Monolog\LogRecord;
 
 /**
  * CouchDB handler for Doctrine CouchDB ODM
@@ -24,20 +23,21 @@ use Monolog\LogRecord;
  */
 class DoctrineCouchDBHandler extends AbstractProcessingHandler
 {
-    private CouchDBClient $client;
+    /** @var CouchDBClient */
+    private $client;
 
-    public function __construct(CouchDBClient $client, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool $bubble = true)
     {
         $this->client = $client;
         parent::__construct($level, $bubble);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->client->postDocument($record->formatted);
+        $this->client->postDocument($record['formatted']);
     }
 
     protected function getDefaultFormatter(): FormatterInterface
index f1c5a9590dfd992dad3a62c0d8fc874344f10983..21840bf60bc875cd1d2c201a169d1190f883a8d5 100644 (file)
@@ -16,8 +16,7 @@ use Aws\DynamoDb\DynamoDbClient;
 use Monolog\Formatter\FormatterInterface;
 use Aws\DynamoDb\Marshaler;
 use Monolog\Formatter\ScalarFormatter;
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
@@ -29,15 +28,35 @@ class DynamoDbHandler extends AbstractProcessingHandler
 {
     public const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
 
-    protected DynamoDbClient $client;
+    /**
+     * @var DynamoDbClient
+     */
+    protected $client;
 
-    protected string $table;
+    /**
+     * @var string
+     */
+    protected $table;
 
-    protected Marshaler $marshaler;
+    /**
+     * @var int
+     */
+    protected $version;
+
+    /**
+     * @var Marshaler
+     */
+    protected $marshaler;
 
-    public function __construct(DynamoDbClient $client, string $table, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true)
     {
-        $this->marshaler = new Marshaler;
+        /** @phpstan-ignore-next-line */
+        if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) {
+            $this->version = 3;
+            $this->marshaler = new Marshaler;
+        } else {
+            $this->version = 2;
+        }
 
         $this->client = $client;
         $this->table = $table;
@@ -46,12 +65,17 @@ class DynamoDbHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $filtered = $this->filterEmptyFields($record->formatted);
-        $formatted = $this->marshaler->marshalItem($filtered);
+        $filtered = $this->filterEmptyFields($record['formatted']);
+        if ($this->version === 3) {
+            $formatted = $this->marshaler->marshalItem($filtered);
+        } else {
+            /** @phpstan-ignore-next-line */
+            $formatted = $this->client->formatAttributes($filtered);
+        }
 
         $this->client->putItem([
             'TableName' => $this->table,
@@ -66,12 +90,12 @@ class DynamoDbHandler extends AbstractProcessingHandler
     protected function filterEmptyFields(array $record): array
     {
         return array_filter($record, function ($value) {
-            return [] !== $value;
+            return !empty($value) || false === $value || 0 === $value;
         });
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index d9b85b4d0ec8ae6d960e78678b4c86b7daaa6580..fc92ca42d574d5c51ee50e0baf24397124f32816 100644 (file)
@@ -14,10 +14,9 @@ namespace Monolog\Handler;
 use Elastica\Document;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\ElasticaFormatter;
-use Monolog\Level;
+use Monolog\Logger;
 use Elastica\Client;
 use Elastica\Exception\ExceptionInterface;
-use Monolog\LogRecord;
 
 /**
  * Elastic Search handler
@@ -34,34 +33,24 @@ use Monolog\LogRecord;
  *    $log->pushHandler($handler);
  *
  * @author Jelle Vink <jelle.vink@gmail.com>
- * @phpstan-type Options array{
- *     index: string,
- *     type: string,
- *     ignore_error: bool
- * }
- * @phpstan-type InputOptions array{
- *     index?: string,
- *     type?: string,
- *     ignore_error?: bool
- * }
  */
 class ElasticaHandler extends AbstractProcessingHandler
 {
-    protected Client $client;
+    /**
+     * @var Client
+     */
+    protected $client;
 
     /**
      * @var mixed[] Handler config options
-     * @phpstan-var Options
      */
-    protected array $options;
+    protected $options = [];
 
     /**
      * @param Client  $client  Elastica Client object
      * @param mixed[] $options Handler configuration
-     *
-     * @phpstan-param InputOptions $options
      */
-    public function __construct(Client $client, array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
         $this->client = $client;
@@ -76,15 +65,15 @@ class ElasticaHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->bulkSend([$record->formatted]);
+        $this->bulkSend([$record['formatted']]);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -97,8 +86,6 @@ class ElasticaHandler extends AbstractProcessingHandler
 
     /**
      * @return mixed[]
-     *
-     * @phpstan-return Options
      */
     public function getOptions(): array
     {
@@ -106,7 +93,7 @@ class ElasticaHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
@@ -114,7 +101,7 @@ class ElasticaHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
index c288824aac7322cc6f0caf436acbcf3eca33cbc5..e88375c0e5701d5bfcd1f6913d8a31b7b98f9389 100644 (file)
@@ -14,13 +14,12 @@ namespace Monolog\Handler;
 use Elastic\Elasticsearch\Response\Elasticsearch;
 use Throwable;
 use RuntimeException;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\ElasticsearchFormatter;
 use InvalidArgumentException;
 use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException;
 use Elasticsearch\Client;
-use Monolog\LogRecord;
 use Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException;
 use Elastic\Elasticsearch\Client as Client8;
 
@@ -44,26 +43,18 @@ use Elastic\Elasticsearch\Client as Client8;
  *    $log->pushHandler($handler);
  *
  * @author Avtandil Kikabidze <akalongman@gmail.com>
- * @phpstan-type Options array{
- *     index: string,
- *     type: string,
- *     ignore_error: bool
- * }
- * @phpstan-type InputOptions array{
- *     index?: string,
- *     type?: string,
- *     ignore_error?: bool
- * }
  */
 class ElasticsearchHandler extends AbstractProcessingHandler
 {
-    protected Client|Client8 $client;
+    /**
+     * @var Client|Client8
+     */
+    protected $client;
 
     /**
      * @var mixed[] Handler config options
-     * @phpstan-var Options
      */
-    protected array $options;
+    protected $options = [];
 
     /**
      * @var bool
@@ -73,11 +64,13 @@ class ElasticsearchHandler extends AbstractProcessingHandler
     /**
      * @param Client|Client8 $client  Elasticsearch Client object
      * @param mixed[]        $options Handler configuration
-     *
-     * @phpstan-param InputOptions $options
      */
-    public function __construct(Client|Client8 $client, array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($client, array $options = [], $level = Logger::DEBUG, bool $bubble = true)
     {
+        if (!$client instanceof Client && !$client instanceof Client8) {
+            throw new \TypeError('Elasticsearch\Client or Elastic\Elasticsearch\Client instance required');
+        }
+
         parent::__construct($level, $bubble);
         $this->client = $client;
         $this->options = array_merge(
@@ -99,15 +92,15 @@ class ElasticsearchHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->bulkSend([$record->formatted]);
+        $this->bulkSend([$record['formatted']]);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -122,8 +115,6 @@ class ElasticsearchHandler extends AbstractProcessingHandler
      * Getter options
      *
      * @return mixed[]
-     *
-     * @phpstan-return Options
      */
     public function getOptions(): array
     {
@@ -131,7 +122,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
@@ -139,7 +130,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -150,7 +141,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler
     /**
      * Use Elasticsearch bulk API to send list of documents
      *
-     * @param  array<array<mixed>> $records Records + _index/_type keys
+     * @param  array[]           $records Records + _index/_type keys
      * @throws \RuntimeException
      */
     protected function bulkSend(array $records): void
index 477d7e45aa8a721837471ace531dc5b7519eaf43..f2e22036bd73fe53f23f1dccc59b4ebd89780cae 100644 (file)
@@ -13,9 +13,8 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Stores to PHP error_log() handler.
@@ -27,14 +26,16 @@ class ErrorLogHandler extends AbstractProcessingHandler
     public const OPERATING_SYSTEM = 0;
     public const SAPI = 4;
 
-    protected int $messageType;
-    protected bool $expandNewlines;
+    /** @var int */
+    protected $messageType;
+    /** @var bool */
+    protected $expandNewlines;
 
     /**
      * @param int  $messageType    Says where the error should go.
      * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
      */
-    public function __construct(int $messageType = self::OPERATING_SYSTEM, int|string|Level $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false)
+    public function __construct(int $messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, bool $bubble = true, bool $expandNewlines = false)
     {
         parent::__construct($level, $bubble);
 
@@ -60,7 +61,7 @@ class ErrorLogHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
@@ -68,20 +69,19 @@ class ErrorLogHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!$this->expandNewlines) {
-            error_log((string) $record->formatted, $this->messageType);
+            error_log((string) $record['formatted'], $this->messageType);
 
             return;
         }
 
-        $lines = preg_split('{[\r\n]+}', (string) $record->formatted);
+        $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
         if ($lines === false) {
             $pcreErrorCode = preg_last_error();
-
             throw new \RuntimeException('Failed to preg_split formatted string: ' . $pcreErrorCode . ' / '. Utils::pcreLastErrorMessage($pcreErrorCode));
         }
         foreach ($lines as $line) {
index 1776eb517fc4a4ad601c1689c928caace4170b7d..d4e234ce0573664d961d0e09b9af3eb1c56f7098 100644 (file)
@@ -12,7 +12,6 @@
 namespace Monolog\Handler;
 
 use Throwable;
-use Monolog\LogRecord;
 
 /**
  * Forwards records to at most one handler
@@ -20,15 +19,18 @@ use Monolog\LogRecord;
  * If a handler fails, the exception is suppressed and the record is forwarded to the next handler.
  *
  * As soon as one handler handles a record successfully, the handling stops there.
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class FallbackGroupHandler extends GroupHandler
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
         foreach ($this->handlers as $handler) {
@@ -44,15 +46,16 @@ class FallbackGroupHandler extends GroupHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
             $processed = [];
             foreach ($records as $record) {
                 $processed[] = $this->processRecord($record);
             }
+            /** @var Record[] $records */
             $records = $processed;
         }
 
index 00381ab4d136ff41a2cc26246cb1a33b649ea82e..718f17ef19c64447689340f9b68d9c58d44aa40b 100644 (file)
 
 namespace Monolog\Handler;
 
-use Closure;
-use Monolog\Level;
 use Monolog\Logger;
 use Monolog\ResettableInterface;
 use Monolog\Formatter\FormatterInterface;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Simple handler wrapper that filters records based on a list of levels
@@ -26,99 +23,110 @@ use Monolog\LogRecord;
  *
  * @author Hennadiy Verkh
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class FilterHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface
 {
     use ProcessableHandlerTrait;
 
     /**
-     * Handler or factory Closure($record, $this)
+     * Handler or factory callable($record, $this)
      *
-     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * @var callable|HandlerInterface
+     * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface
      */
-    protected Closure|HandlerInterface $handler;
+    protected $handler;
 
     /**
      * Minimum level for logs that are passed to handler
      *
-     * @var bool[] Map of Level value => true
-     * @phpstan-var array<value-of<Level::VALUES>, true>
+     * @var int[]
+     * @phpstan-var array<Level, int>
      */
-    protected array $acceptedLevels;
+    protected $acceptedLevels;
 
     /**
      * Whether the messages that are handled can bubble up the stack or not
+     *
+     * @var bool
      */
-    protected bool $bubble;
+    protected $bubble;
 
     /**
-     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler
      *
-     * @param Closure|HandlerInterface                                                 $handler        Handler or factory Closure($record|null, $filterHandler).
-     * @param int|string|Level|array<int|string|Level|LogLevel::*> $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
-     * @param int|string|Level|LogLevel::*                                   $maxLevel       Maximum level to accept, only used if $minLevelOrList is not an array
-     * @param bool                                                                     $bubble         Whether the messages that are handled can bubble up the stack or not
+     * @param callable|HandlerInterface $handler        Handler or factory callable($record|null, $filterHandler).
+     * @param int|array                 $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
+     * @param int|string                $maxLevel       Maximum level to accept, only used if $minLevelOrList is not an array
+     * @param bool                      $bubble         Whether the messages that are handled can bubble up the stack or not
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*|array<value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*> $minLevelOrList
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $maxLevel
+     * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList
+     * @phpstan-param Level|LevelName|LogLevel::* $maxLevel
      */
-    public function __construct(Closure|HandlerInterface $handler, int|string|Level|array $minLevelOrList = Level::Debug, int|string|Level $maxLevel = Level::Emergency, bool $bubble = true)
+    public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true)
     {
         $this->handler  = $handler;
         $this->bubble   = $bubble;
         $this->setAcceptedLevels($minLevelOrList, $maxLevel);
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
     }
 
     /**
-     * @phpstan-return list<Level> List of levels
+     * @phpstan-return array<int, Level>
      */
     public function getAcceptedLevels(): array
     {
-        return array_map(fn (int $level) => Level::from($level), array_keys($this->acceptedLevels));
+        return array_flip($this->acceptedLevels);
     }
 
     /**
-     * @param int|string|Level|LogLevel::*|array<int|string|Level|LogLevel::*> $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided
-     * @param int|string|Level|LogLevel::*                                               $maxLevel       Maximum level or level name to accept, only used if $minLevelOrList is not an array
+     * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided
+     * @param int|string       $maxLevel       Maximum level or level name to accept, only used if $minLevelOrList is not an array
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*|array<value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*> $minLevelOrList
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $maxLevel
+     * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList
+     * @phpstan-param Level|LevelName|LogLevel::*                                    $maxLevel
      */
-    public function setAcceptedLevels(int|string|Level|array $minLevelOrList = Level::Debug, int|string|Level $maxLevel = Level::Emergency): self
+    public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self
     {
         if (is_array($minLevelOrList)) {
-            $acceptedLevels = array_map(Logger::toMonologLevel(...), $minLevelOrList);
+            $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
         } else {
             $minLevelOrList = Logger::toMonologLevel($minLevelOrList);
             $maxLevel = Logger::toMonologLevel($maxLevel);
-            $acceptedLevels = array_values(array_filter(Level::cases(), fn (Level $level) => $level->value >= $minLevelOrList->value && $level->value <= $maxLevel->value));
-        }
-        $this->acceptedLevels = [];
-        foreach ($acceptedLevels as $level) {
-            $this->acceptedLevels[$level->value] = true;
+            $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
+                return $level >= $minLevelOrList && $level <= $maxLevel;
+            }));
         }
+        $this->acceptedLevels = array_flip($acceptedLevels);
 
         return $this;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
-        return isset($this->acceptedLevels[$record->level->value]);
+        return isset($this->acceptedLevels[$record['level']]);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         if (!$this->isHandling($record)) {
             return false;
         }
 
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
@@ -128,7 +136,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -147,23 +155,26 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     /**
      * Return the nested handler
      *
-     * If the handler was provided as a factory, this will trigger the handler's instantiation.
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @return HandlerInterface
+     *
+     * @phpstan-param Record $record
      */
-    public function getHandler(LogRecord $record = null): HandlerInterface
+    public function getHandler(array $record = null)
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $handler = ($this->handler)($record, $this);
-            if (!$handler instanceof HandlerInterface) {
-                throw new \RuntimeException("The factory Closure should return a HandlerInterface");
+            $this->handler = ($this->handler)($record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
-            $this->handler = $handler;
         }
 
         return $this->handler;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -178,7 +189,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
@@ -190,7 +201,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
         throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.');
     }
 
-    public function reset(): void
+    public function reset()
     {
         $this->resetProcessors();
 
index e8a1b0b0dbb6765d1f8678b847ae852751319aef..0aa5607b1512397cd122f75d48e9ec2fee30c87c 100644 (file)
 
 namespace Monolog\Handler\FingersCrossed;
 
-use Monolog\LogRecord;
-
 /**
  * Interface for activation strategies for the FingersCrossedHandler.
  *
  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 interface ActivationStrategyInterface
 {
     /**
      * Returns whether the given record activates the handler.
+     *
+     * @phpstan-param Record $record
      */
-    public function isHandlerActivated(LogRecord $record): bool;
+    public function isHandlerActivated(array $record): bool;
 }
index 383e19af962dc1008b3013a74ba6a202c6eebcd8..7b9abb582ecf75992922bd74883d8362e75ef7e8 100644 (file)
 
 namespace Monolog\Handler\FingersCrossed;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Channel and Error level based monolog activation strategy. Allows to trigger activation
@@ -25,45 +23,55 @@ use Monolog\LogRecord;
  *
  * <code>
  *   $activationStrategy = new ChannelLevelActivationStrategy(
- *       Level::Critical,
+ *       Logger::CRITICAL,
  *       array(
- *           'request' => Level::Alert,
- *           'sensitive' => Level::Error,
+ *           'request' => Logger::ALERT,
+ *           'sensitive' => Logger::ERROR,
  *       )
  *   );
  *   $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
  * </code>
  *
  * @author Mike Meessen <netmikey@gmail.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class ChannelLevelActivationStrategy implements ActivationStrategyInterface
 {
-    private Level $defaultActionLevel;
+    /**
+     * @var Level
+     */
+    private $defaultActionLevel;
 
     /**
      * @var array<string, Level>
      */
-    private array $channelToActionLevel;
+    private $channelToActionLevel;
 
     /**
-     * @param int|string|Level|LogLevel::*                $defaultActionLevel   The default action level to be used if the record's category doesn't match any
-     * @param array<string, int|string|Level|LogLevel::*> $channelToActionLevel An array that maps channel names to action levels.
+     * @param int|string         $defaultActionLevel   The default action level to be used if the record's category doesn't match any
+     * @param array<string, int> $channelToActionLevel An array that maps channel names to action levels.
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $defaultActionLevel
-     * @phpstan-param array<string, value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*> $channelToActionLevel
+     * @phpstan-param array<string, Level>        $channelToActionLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel
      */
-    public function __construct(int|string|Level $defaultActionLevel, array $channelToActionLevel = [])
+    public function __construct($defaultActionLevel, array $channelToActionLevel = [])
     {
         $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel);
-        $this->channelToActionLevel = array_map(Logger::toMonologLevel(...), $channelToActionLevel);
+        $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel);
     }
 
-    public function isHandlerActivated(LogRecord $record): bool
+    /**
+     * @phpstan-param Record $record
+     */
+    public function isHandlerActivated(array $record): bool
     {
-        if (isset($this->channelToActionLevel[$record->channel])) {
-            return $record->level->value >= $this->channelToActionLevel[$record->channel]->value;
+        if (isset($this->channelToActionLevel[$record['channel']])) {
+            return $record['level'] >= $this->channelToActionLevel[$record['channel']];
         }
 
-        return $record->level->value >= $this->defaultActionLevel->value;
+        return $record['level'] >= $this->defaultActionLevel;
     }
 }
index c3ca2967ab6b6dbfcc857aacf83c5fdbc52858d9..5ec88eab6e29cd7b2c24f839d632747bd78b06fd 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Handler\FingersCrossed;
 
-use Monolog\Level;
-use Monolog\LogRecord;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
 
@@ -20,23 +18,29 @@ use Psr\Log\LogLevel;
  * Error level based activation strategy.
  *
  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class ErrorLevelActivationStrategy implements ActivationStrategyInterface
 {
-    private Level $actionLevel;
+    /**
+     * @var Level
+     */
+    private $actionLevel;
 
     /**
-     * @param int|string|Level $actionLevel Level or name or value
+     * @param int|string $actionLevel Level or name or value
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $actionLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $actionLevel
      */
-    public function __construct(int|string|Level $actionLevel)
+    public function __construct($actionLevel)
     {
         $this->actionLevel = Logger::toMonologLevel($actionLevel);
     }
 
-    public function isHandlerActivated(LogRecord $record): bool
+    public function isHandlerActivated(array $record): bool
     {
-        return $record->level->value >= $this->actionLevel->value;
+        return $record['level'] >= $this->actionLevel;
     }
 }
index ce2a3a8e11e5000147630e197c53c4721db778f5..0627b44514128267193456fec4e6d64281a2b0e1 100644 (file)
 
 namespace Monolog\Handler;
 
-use Closure;
 use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
 use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
-use Monolog\Level;
 use Monolog\Logger;
 use Monolog\ResettableInterface;
 use Monolog\Formatter\FormatterInterface;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Buffers all records until a certain level is reached
@@ -36,50 +33,55 @@ use Monolog\LogRecord;
  * Monolog\Handler\FingersCrossed\ namespace.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface
 {
     use ProcessableHandlerTrait;
 
     /**
-     * Handler or factory Closure($record, $this)
-     *
-     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * @var callable|HandlerInterface
+     * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface
      */
-    protected Closure|HandlerInterface $handler;
-
-    protected ActivationStrategyInterface $activationStrategy;
-
-    protected bool $buffering = true;
-
-    protected int $bufferSize;
-
-    /** @var LogRecord[] */
-    protected array $buffer = [];
-
-    protected bool $stopBuffering;
-
-    protected Level|null $passthruLevel = null;
-
-    protected bool $bubble;
+    protected $handler;
+    /** @var ActivationStrategyInterface */
+    protected $activationStrategy;
+    /** @var bool */
+    protected $buffering = true;
+    /** @var int */
+    protected $bufferSize;
+    /** @var Record[] */
+    protected $buffer = [];
+    /** @var bool */
+    protected $stopBuffering;
+    /**
+     * @var ?int
+     * @phpstan-var ?Level
+     */
+    protected $passthruLevel;
+    /** @var bool */
+    protected $bubble;
 
     /**
-     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler
      *
-     * @param Closure|HandlerInterface                    $handler            Handler or factory Closure($record|null, $fingersCrossedHandler).
-     * @param int|string|Level|LogLevel::*      $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated
-     * @param int                                         $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
-     * @param bool                                        $bubble             Whether the messages that are handled can bubble up the stack or not
-     * @param bool                                        $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
-     * @param int|string|Level|LogLevel::*|null $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
+     * @param callable|HandlerInterface              $handler            Handler or factory callable($record|null, $fingersCrossedHandler).
+     * @param int|string|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated
+     * @param int                                    $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+     * @param bool                                   $bubble             Whether the messages that are handled can bubble up the stack or not
+     * @param bool                                   $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
+     * @param int|string                             $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::*|ActivationStrategyInterface $activationStrategy
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $passthruLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $passthruLevel
+     * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy
      */
-    public function __construct(Closure|HandlerInterface $handler, int|string|Level|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|null $passthruLevel = null)
+    public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null)
     {
         if (null === $activationStrategy) {
-            $activationStrategy = new ErrorLevelActivationStrategy(Level::Warning);
+            $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
         }
 
         // convert simple int activationStrategy to an object
@@ -96,12 +98,16 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
         if ($passthruLevel !== null) {
             $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
         }
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
         return true;
     }
@@ -120,11 +126,12 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
@@ -144,7 +151,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -153,7 +160,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
         $this->getHandler()->close();
     }
 
-    public function reset(): void
+    public function reset()
     {
         $this->flushBuffer();
 
@@ -183,7 +190,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
         if (null !== $this->passthruLevel) {
             $level = $this->passthruLevel;
             $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
-                return $record->level >= $level;
+                return $record['level'] >= $level;
             });
             if (count($this->buffer) > 0) {
                 $this->getHandler(end($this->buffer))->handleBatch($this->buffer);
@@ -197,23 +204,26 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     /**
      * Return the nested handler
      *
-     * If the handler was provided as a factory, this will trigger the handler's instantiation.
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @return HandlerInterface
+     *
+     * @phpstan-param Record $record
      */
-    public function getHandler(LogRecord $record = null): HandlerInterface
+    public function getHandler(array $record = null)
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $handler = ($this->handler)($record, $this);
-            if (!$handler instanceof HandlerInterface) {
-                throw new \RuntimeException("The factory Closure should return a HandlerInterface");
+            $this->handler = ($this->handler)($record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
-            $this->handler = $handler;
         }
 
         return $this->handler;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -228,7 +238,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
index 6b9e5103a9e79ddcffd0dae93d7d190c108573e0..72718de631ef9b8c9c9a7afdcdfbf7280f9d29e5 100644 (file)
@@ -13,12 +13,13 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\WildfireFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
  *
  * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class FirePHPHandler extends AbstractProcessingHandler
 {
@@ -46,15 +47,18 @@ class FirePHPHandler extends AbstractProcessingHandler
 
     /**
      * Whether or not Wildfire vendor-specific headers have been generated & sent yet
+     * @var bool
      */
-    protected static bool $initialized = false;
+    protected static $initialized = false;
 
     /**
      * Shared static message index between potentially multiple handlers
+     * @var int
      */
-    protected static int $messageIndex = 1;
+    protected static $messageIndex = 1;
 
-    protected static bool $sendHeaders = true;
+    /** @var bool */
+    protected static $sendHeaders = true;
 
     /**
      * Base header creation function used by init headers & record headers
@@ -81,19 +85,21 @@ class FirePHPHandler extends AbstractProcessingHandler
      * @phpstan-return non-empty-array<string, string>
      *
      * @see createHeader()
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    protected function createRecordHeader(LogRecord $record): array
+    protected function createRecordHeader(array $record): array
     {
         // Wildfire is extensible to support multiple protocols & plugins in a single request,
         // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
         return $this->createHeader(
             [1, 1, 1, self::$messageIndex++],
-            $record->formatted
+            $record['formatted']
         );
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
@@ -134,7 +140,7 @@ class FirePHPHandler extends AbstractProcessingHandler
      * @see sendHeader()
      * @see sendInitHeaders()
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!self::$sendHeaders || !$this->isWebRequest()) {
             return;
@@ -165,7 +171,7 @@ class FirePHPHandler extends AbstractProcessingHandler
      */
     protected function headersAccepted(): bool
     {
-        if (isset($_SERVER['HTTP_USER_AGENT']) && 1 === preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
+        if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
             return true;
         }
 
index 9f44ba719e64aea076910bc447d0adca1c1177f9..85c95b9d76d80b2e79cd2b344b3127bad4b4ad50 100644 (file)
@@ -13,8 +13,7 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LineFormatter;
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Sends logs to Fleep.io using Webhook integrations
@@ -23,6 +22,8 @@ use Monolog\LogRecord;
  *
  * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation
  * @author Ando Roots <ando@sqroot.eu>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class FleepHookHandler extends SocketHandler
 {
@@ -33,7 +34,7 @@ class FleepHookHandler extends SocketHandler
     /**
      * @var string Webhook token (specifies the conversation where logs are sent)
      */
-    protected string $token;
+    protected $token;
 
     /**
      * Construct a new Fleep.io Handler.
@@ -41,12 +42,12 @@ class FleepHookHandler extends SocketHandler
      * For instructions on how to create a new web hook in your conversations
      * see https://fleep.io/integrations/webhooks/
      *
-     * @param  string                    $token Webhook token
+     * @param  string                    $token  Webhook token
      * @throws MissingExtensionException
      */
     public function __construct(
         string $token,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         bool $persistent = false,
         float $timeout = 0.0,
@@ -88,16 +89,16 @@ class FleepHookHandler extends SocketHandler
     /**
      * Handles a log record
      */
-    public function write(LogRecord $record): void
+    public function write(array $record): void
     {
         parent::write($record);
         $this->closeSocket();
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
         $content = $this->buildContent($record);
 
@@ -120,11 +121,13 @@ class FleepHookHandler extends SocketHandler
 
     /**
      * Builds the body of API call
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    private function buildContent(LogRecord $record): string
+    private function buildContent(array $record): string
     {
         $dataArray = [
-            'message' => $record->formatted,
+            'message' => $record['formatted'],
         ];
 
         return http_build_query($dataArray);
index 1358154850e37c600d7e1a632d11b2fc57ec21e3..5715d5800fe5089975efb6679bd7bf6c10095c7b 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use Monolog\Formatter\FlowdockFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Sends notifications through the Flowdock push API
@@ -27,17 +26,23 @@ use Monolog\LogRecord;
  *
  * @author Dominik Liebler <liebler.dominik@gmail.com>
  * @see https://www.flowdock.com/api/push
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
+ * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4
  */
 class FlowdockHandler extends SocketHandler
 {
-    protected string $apiToken;
+    /**
+     * @var string
+     */
+    protected $apiToken;
 
     /**
      * @throws MissingExtensionException if OpenSSL is missing
      */
     public function __construct(
         string $apiToken,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         bool $persistent = false,
         float $timeout = 0.0,
@@ -63,7 +68,7 @@ class FlowdockHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -83,9 +88,9 @@ class FlowdockHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         parent::write($record);
 
@@ -93,9 +98,9 @@ class FlowdockHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
         $content = $this->buildContent($record);
 
@@ -104,10 +109,12 @@ class FlowdockHandler extends SocketHandler
 
     /**
      * Builds the body of API call
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    private function buildContent(LogRecord $record): string
+    private function buildContent(array $record): string
     {
-        return Utils::jsonEncode($record->formatted);
+        return Utils::jsonEncode($record['formatted']['flowdock']);
     }
 
     /**
index 72da59e1c58739aa971be12aea1edfda8bc7ca01..fc1693cd08785ddba6f226fed1dde4de9ba63aa3 100644 (file)
@@ -23,12 +23,15 @@ interface FormattableHandlerInterface
     /**
      * Sets the formatter.
      *
-     * @return HandlerInterface self
+     * @param  FormatterInterface $formatter
+     * @return HandlerInterface   self
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface;
 
     /**
      * Gets the formatter.
+     *
+     * @return FormatterInterface
      */
     public function getFormatter(): FormatterInterface;
 }
index c044e0786ca66f63e7fb9e5c6e0cf7adb63bac10..b60bdce0ef7edae8c6a32f3b34f5f4841f34b66a 100644 (file)
@@ -21,10 +21,13 @@ use Monolog\Formatter\LineFormatter;
  */
 trait FormattableHandlerTrait
 {
-    protected FormatterInterface|null $formatter = null;
+    /**
+     * @var ?FormatterInterface
+     */
+    protected $formatter;
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -34,11 +37,11 @@ trait FormattableHandlerTrait
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
-        if (null === $this->formatter) {
+        if (!$this->formatter) {
             $this->formatter = $this->getDefaultFormatter();
         }
 
index ba5bb975d85b6affdac1f4060006bfcb108a1ba5..4ff26c4cd087c4acf8e000b5114d8d59fe206ea0 100644 (file)
 namespace Monolog\Handler;
 
 use Gelf\PublisherInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\GelfMessageFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Handler to send messages to a Graylog2 (http://www.graylog2.org) server
@@ -28,12 +27,12 @@ class GelfHandler extends AbstractProcessingHandler
     /**
      * @var PublisherInterface the publisher object that sends the message to the server
      */
-    protected PublisherInterface $publisher;
+    protected $publisher;
 
     /**
      * @param PublisherInterface $publisher a gelf publisher object
      */
-    public function __construct(PublisherInterface $publisher, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
@@ -41,15 +40,15 @@ class GelfHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->publisher->publish($record->formatted);
+        $this->publisher->publish($record['formatted']);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 7ab8bd973aa4cd25be99cae407decbc4bf6cc6fc..3c9dc4b3b75424bbedffbe565d68d8677eafa535 100644 (file)
@@ -13,20 +13,22 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
 use Monolog\ResettableInterface;
-use Monolog\LogRecord;
 
 /**
  * Forwards records to multiple handlers
  *
  * @author Lenar Lõhmus <lenar@city.ee>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface
 {
     use ProcessableHandlerTrait;
 
     /** @var HandlerInterface[] */
-    protected array $handlers;
-    protected bool $bubble;
+    protected $handlers;
+    /** @var bool */
+    protected $bubble;
 
     /**
      * @param HandlerInterface[] $handlers Array of Handlers.
@@ -45,9 +47,9 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
         foreach ($this->handlers as $handler) {
             if ($handler->isHandling($record)) {
@@ -59,11 +61,12 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
@@ -75,15 +78,16 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
             $processed = [];
             foreach ($records as $record) {
                 $processed[] = $this->processRecord($record);
             }
+            /** @var Record[] $records */
             $records = $processed;
         }
 
@@ -92,7 +96,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
         }
     }
 
-    public function reset(): void
+    public function reset()
     {
         $this->resetProcessors();
 
@@ -113,7 +117,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
index e89f969b8ffd87b50024253f7d5ad02a66ed12c0..34b4935dd8c63251d7fda0c4ef51d41a3b0e9ff4 100644 (file)
@@ -19,7 +19,7 @@ namespace Monolog\Handler;
 abstract class Handler implements HandlerInterface
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -29,7 +29,7 @@ abstract class Handler implements HandlerInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
index 83905c323d156a9156e72a221adb64661c823bdf..affcc51fca76f18506a594ad2431df1e6516e19f 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\LogRecord;
-
 /**
  * Interface that all Monolog Handlers must implement
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 interface HandlerInterface
 {
@@ -29,9 +30,13 @@ interface HandlerInterface
      * is no guarantee that handle() will not be called, and isHandling() might not be called
      * for a given record.
      *
-     * @param LogRecord $record Partial log record having only a level initialized
+     * @param array $record Partial log record containing only a level key
+     *
+     * @return bool
+     *
+     * @phpstan-param array{level: Level} $record
      */
-    public function isHandling(LogRecord $record): bool;
+    public function isHandling(array $record): bool;
 
     /**
      * Handles a record.
@@ -43,16 +48,20 @@ interface HandlerInterface
      * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
      * calling further handlers in the stack with a given log record.
      *
-     * @param  LogRecord $record The record to handle
-     * @return bool      true means that this handler handled the record, and that bubbling is not permitted.
-     *                          false means the record was either not processed or that this handler allows bubbling.
+     * @param  array $record The record to handle
+     * @return bool  true means that this handler handled the record, and that bubbling is not permitted.
+     *                      false means the record was either not processed or that this handler allows bubbling.
+     *
+     * @phpstan-param Record $record
      */
-    public function handle(LogRecord $record): bool;
+    public function handle(array $record): bool;
 
     /**
      * Handles a set of records at once.
      *
-     * @param array<LogRecord> $records The records to handle
+     * @param array $records The records to handle (an array of record arrays)
+     *
+     * @phpstan-param Record[] $records
      */
     public function handleBatch(array $records): void;
 
index 541ec2541a2305e4585f3794c20a37d9a190127e..d4351b9f9d9c94e7ffe9fa205d281cc41b21aeae 100644 (file)
@@ -13,7 +13,6 @@ namespace Monolog\Handler;
 
 use Monolog\ResettableInterface;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * This simple wrapper class can be used to extend handlers functionality.
@@ -22,7 +21,7 @@ use Monolog\LogRecord;
  *
  * Inherit from this class and override handle() like this:
  *
- *   public function handle(LogRecord $record)
+ *   public function handle(array $record)
  *   {
  *        if ($record meets certain conditions) {
  *            return false;
@@ -34,7 +33,10 @@ use Monolog\LogRecord;
  */
 class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface
 {
-    protected HandlerInterface $handler;
+    /**
+     * @var HandlerInterface
+     */
+    protected $handler;
 
     public function __construct(HandlerInterface $handler)
     {
@@ -42,23 +44,23 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
         return $this->handler->isHandling($record);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         return $this->handler->handle($record);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
@@ -66,7 +68,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -74,7 +76,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function pushProcessor(callable $callback): HandlerInterface
     {
@@ -88,7 +90,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function popProcessor(): callable
     {
@@ -100,7 +102,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -114,7 +116,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
@@ -125,7 +127,7 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
         throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class);
     }
 
-    public function reset(): void
+    public function reset()
     {
         if ($this->handler instanceof ResettableInterface) {
             $this->handler->reset();
index ee7f81f6a08b54e85060789fff014f789f8cad19..000ccea40e2e05033da80c8fb9a8ce4808c6c94a 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * IFTTTHandler uses cURL to trigger IFTTT Maker actions
@@ -28,14 +27,16 @@ use Monolog\LogRecord;
  */
 class IFTTTHandler extends AbstractProcessingHandler
 {
-    private string $eventName;
-    private string $secretKey;
+    /** @var string */
+    private $eventName;
+    /** @var string */
+    private $secretKey;
 
     /**
      * @param string $eventName The name of the IFTTT Maker event that should be triggered
      * @param string $secretKey A valid IFTTT secret key
      */
-    public function __construct(string $eventName, string $secretKey, int|string|Level $level = Level::Error, bool $bubble = true)
+    public function __construct(string $eventName, string $secretKey, $level = Logger::ERROR, bool $bubble = true)
     {
         if (!extension_loaded('curl')) {
             throw new MissingExtensionException('The curl extension is needed to use the IFTTTHandler');
@@ -48,14 +49,14 @@ class IFTTTHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function write(LogRecord $record): void
+    public function write(array $record): void
     {
         $postData = [
-            "value1" => $record->channel,
+            "value1" => $record["channel"],
             "value2" => $record["level_name"],
-            "value3" => $record->message,
+            "value3" => $record["message"],
         ];
         $postString = Utils::jsonEncode($postData);
 
index abb2f88f7cf6ca84d1ef010a2eca6ff0fb6c1b9c..71f64a267d683687a9e79c42ef7e50f858842188 100644 (file)
@@ -11,8 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Inspired on LogEntriesHandler.
@@ -22,12 +21,15 @@ use Monolog\LogRecord;
  */
 class InsightOpsHandler extends SocketHandler
 {
-    protected string $logToken;
+    /**
+     * @var string
+     */
+    protected $logToken;
 
     /**
-     * @param string $token  Log token supplied by InsightOps
-     * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
-     * @param bool   $useSSL Whether or not SSL encryption should be used
+     * @param string     $token  Log token supplied by InsightOps
+     * @param string     $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
+     * @param bool       $useSSL Whether or not SSL encryption should be used
      *
      * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
      */
@@ -35,7 +37,7 @@ class InsightOpsHandler extends SocketHandler
         string $token,
         string $region = 'us',
         bool $useSSL = true,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         bool $persistent = false,
         float $timeout = 0.0,
@@ -65,10 +67,10 @@ class InsightOpsHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
-        return $this->logToken . ' ' . $record->formatted;
+        return $this->logToken . ' ' . $record['formatted'];
     }
 }
index 00259834eb3e5b28afbfc97fd6c227810e2c5c42..25fcd1594b3c6f01970c98fa22ad6731ebd93d27 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * @author Robert Kaufmann III <rok3@rok3.me>
  */
 class LogEntriesHandler extends SocketHandler
 {
-    protected string $logToken;
+    /**
+     * @var string
+     */
+    protected $logToken;
 
     /**
-     * @param string $token  Log token supplied by LogEntries
-     * @param bool   $useSSL Whether or not SSL encryption should be used.
-     * @param string $host   Custom hostname to send the data to if needed
+     * @param string     $token  Log token supplied by LogEntries
+     * @param bool       $useSSL Whether or not SSL encryption should be used.
+     * @param string     $host   Custom hostname to send the data to if needed
      *
      * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
      */
     public function __construct(
         string $token,
         bool $useSSL = true,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         string $host = 'data.logentries.com',
         bool $persistent = false,
@@ -59,10 +61,10 @@ class LogEntriesHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
-        return $this->logToken . ' ' . $record->formatted;
+        return $this->logToken . ' ' . $record['formatted'];
     }
 }
index 2d8e66f18017eb0f3792586308fc25c3b6848145..6d13db375a469989c0dab4aae99c5f2956cf034c 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LogglyFormatter;
 use function array_key_exists;
 use CurlHandle;
-use Monolog\LogRecord;
 
 /**
  * Sends errors to Loggly.
@@ -34,21 +33,22 @@ class LogglyHandler extends AbstractProcessingHandler
     /**
      * Caches the curl handlers for every given endpoint.
      *
-     * @var CurlHandle[]
+     * @var resource[]|CurlHandle[]
      */
-    protected array $curlHandlers = [];
+    protected $curlHandlers = [];
 
-    protected string $token;
+    /** @var string */
+    protected $token;
 
     /** @var string[] */
-    protected array $tag = [];
+    protected $tag = [];
 
     /**
      * @param string $token API token supplied by Loggly
      *
      * @throws MissingExtensionException If the curl extension is missing
      */
-    public function __construct(string $token, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true)
     {
         if (!extension_loaded('curl')) {
             throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler');
@@ -61,8 +61,12 @@ class LogglyHandler extends AbstractProcessingHandler
 
     /**
      * Loads and returns the shared curl handler for the given endpoint.
+     *
+     * @param string $endpoint
+     *
+     * @return resource|CurlHandle
      */
-    protected function getCurlHandler(string $endpoint): CurlHandle
+    protected function getCurlHandler(string $endpoint)
     {
         if (!array_key_exists($endpoint, $this->curlHandlers)) {
             $this->curlHandlers[$endpoint] = $this->loadCurlHandle($endpoint);
@@ -73,8 +77,12 @@ class LogglyHandler extends AbstractProcessingHandler
 
     /**
      * Starts a fresh curl session for the given endpoint and returns its handler.
+     *
+     * @param string $endpoint
+     *
+     * @return resource|CurlHandle
      */
-    private function loadCurlHandle(string $endpoint): CurlHandle
+    private function loadCurlHandle(string $endpoint)
     {
         $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token);
 
@@ -90,13 +98,10 @@ class LogglyHandler extends AbstractProcessingHandler
     /**
      * @param string[]|string $tag
      */
-    public function setTag(string|array $tag): self
+    public function setTag($tag): self
     {
-        if ('' === $tag || [] === $tag) {
-            $this->tag = [];
-        } else {
-            $this->tag = is_array($tag) ? $tag : [$tag];
-        }
+        $tag = !empty($tag) ? $tag : [];
+        $this->tag = is_array($tag) ? $tag : [$tag];
 
         return $this;
     }
@@ -104,9 +109,9 @@ class LogglyHandler extends AbstractProcessingHandler
     /**
      * @param string[]|string $tag
      */
-    public function addTag(string|array $tag): self
+    public function addTag($tag): self
     {
-        if ('' !== $tag) {
+        if (!empty($tag)) {
             $tag = is_array($tag) ? $tag : [$tag];
             $this->tag = array_unique(array_merge($this->tag, $tag));
         }
@@ -114,9 +119,9 @@ class LogglyHandler extends AbstractProcessingHandler
         return $this;
     }
 
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->send($record->formatted, static::ENDPOINT_SINGLE);
+        $this->send($record["formatted"], static::ENDPOINT_SINGLE);
     }
 
     public function handleBatch(array $records): void
@@ -124,10 +129,10 @@ class LogglyHandler extends AbstractProcessingHandler
         $level = $this->level;
 
         $records = array_filter($records, function ($record) use ($level) {
-            return ($record->level >= $level);
+            return ($record['level'] >= $level);
         });
 
-        if (\count($records) > 0) {
+        if ($records) {
             $this->send($this->getFormatter()->formatBatch($records), static::ENDPOINT_BATCH);
         }
     }
@@ -138,7 +143,7 @@ class LogglyHandler extends AbstractProcessingHandler
 
         $headers = ['Content-Type: application/json'];
 
-        if (\count($this->tag) > 0) {
+        if (!empty($this->tag)) {
             $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag);
         }
 
index 876b1a953ffb85dc6201c0dada7868a1c117db8e..859a469065ff4f3f77aed123b5417fca755d2626 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LogmaticFormatter;
-use Monolog\LogRecord;
 
 /**
  * @author Julien Breux <julien.breux@gmail.com>
  */
 class LogmaticHandler extends SocketHandler
 {
-    private string $logToken;
+    /**
+     * @var string
+     */
+    private $logToken;
 
-    private string $hostname;
+    /**
+     * @var string
+     */
+    private $hostname;
 
-    private string $appName;
+    /**
+     * @var string
+     */
+    private $appname;
 
     /**
-     * @param string $token    Log token supplied by Logmatic.
-     * @param string $hostname Host name supplied by Logmatic.
-     * @param string $appName  Application name supplied by Logmatic.
-     * @param bool   $useSSL   Whether or not SSL encryption should be used.
+     * @param string     $token    Log token supplied by Logmatic.
+     * @param string     $hostname Host name supplied by Logmatic.
+     * @param string     $appname  Application name supplied by Logmatic.
+     * @param bool       $useSSL   Whether or not SSL encryption should be used.
      *
      * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
      */
     public function __construct(
         string $token,
         string $hostname = '',
-        string $appName = '',
+        string $appname = '',
         bool $useSSL = true,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         bool $persistent = false,
         float $timeout = 0.0,
@@ -68,29 +76,29 @@ class LogmaticHandler extends SocketHandler
 
         $this->logToken = $token;
         $this->hostname = $hostname;
-        $this->appName  = $appName;
+        $this->appname  = $appname;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
-        return $this->logToken . ' ' . $record->formatted;
+        return $this->logToken . ' ' . $record['formatted'];
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
         $formatter = new LogmaticFormatter();
 
-        if ($this->hostname !== '') {
+        if (!empty($this->hostname)) {
             $formatter->setHostname($this->hostname);
         }
-        if ($this->appName !== '') {
-            $formatter->setAppName($this->appName);
+        if (!empty($this->appname)) {
+            $formatter->setAppname($this->appname);
         }
 
         return $formatter;
index b6c8227726647ee41295482a27e814b71367f263..97f343202895648d4b6bea2473d07750483bc774 100644 (file)
@@ -13,32 +13,33 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\HtmlFormatter;
-use Monolog\LogRecord;
 
 /**
  * Base class for all mail handlers
  *
  * @author Gyula Sallai
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 abstract class MailHandler extends AbstractProcessingHandler
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
         $messages = [];
 
         foreach ($records as $record) {
-            if ($record->level->isLowerThan($this->level)) {
+            if ($record['level'] < $this->level) {
                 continue;
             }
-
+            /** @var Record $message */
             $message = $this->processRecord($record);
             $messages[] = $message;
         }
 
-        if (\count($messages) > 0) {
+        if (!empty($messages)) {
             $this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
         }
     }
@@ -49,26 +50,27 @@ abstract class MailHandler extends AbstractProcessingHandler
      * @param string $content formatted email body to be sent
      * @param array  $records the array of log records that formed this content
      *
-     * @phpstan-param non-empty-array<LogRecord> $records
+     * @phpstan-param Record[] $records
      */
     abstract protected function send(string $content, array $records): void;
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->send((string) $record->formatted, [$record]);
+        $this->send((string) $record['formatted'], [$record]);
     }
 
     /**
-     * @phpstan-param non-empty-array<LogRecord> $records
+     * @phpstan-param non-empty-array<Record> $records
+     * @phpstan-return Record
      */
-    protected function getHighestRecord(array $records): LogRecord
+    protected function getHighestRecord(array $records): array
     {
         $highestRecord = null;
         foreach ($records as $record) {
-            if ($highestRecord === null || $record->level->isHigherThan($highestRecord->level)) {
+            if ($highestRecord === null || $highestRecord['level'] < $record['level']) {
                 $highestRecord = $record;
             }
         }
@@ -83,6 +85,8 @@ abstract class MailHandler extends AbstractProcessingHandler
 
     /**
      * Gets the default formatter.
+     *
+     * @return FormatterInterface
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 0f923bc527456cf50b4fd942bd50c328713297a0..3003500ec041c73573f0bd0ce842be9006f8a4d3 100644 (file)
@@ -11,7 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Swift;
 use Swift_Message;
 
@@ -22,20 +22,22 @@ use Swift_Message;
  */
 class MandrillHandler extends MailHandler
 {
-    protected Swift_Message $message;
-    protected string $apiKey;
+    /** @var Swift_Message */
+    protected $message;
+    /** @var string */
+    protected $apiKey;
 
     /**
-     * @phpstan-param (Swift_Message|callable(): Swift_Message) $message
+     * @psalm-param Swift_Message|callable(): Swift_Message $message
      *
      * @param string                 $apiKey  A valid Mandrill API key
      * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced
      */
-    public function __construct(string $apiKey, callable|Swift_Message $message, int|string|Level $level = Level::Error, bool $bubble = true)
+    public function __construct(string $apiKey, $message, $level = Logger::ERROR, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
-        if (!$message instanceof Swift_Message) {
+        if (!$message instanceof Swift_Message && is_callable($message)) {
             $message = $message();
         }
         if (!$message instanceof Swift_Message) {
@@ -46,7 +48,7 @@ class MandrillHandler extends MailHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function send(string $content, array $records): void
     {
index 33ab68c6d080baef5d1ad7eeb44a8c01989595a7..306309119917c7ddca83c9c8e44524803393f8e7 100644 (file)
@@ -14,10 +14,9 @@ namespace Monolog\Handler;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\Manager;
 use MongoDB\Client;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\MongoDBFormatter;
-use Monolog\LogRecord;
 
 /**
  * Logs to a MongoDB database.
@@ -34,11 +33,12 @@ use Monolog\LogRecord;
  */
 class MongoDBHandler extends AbstractProcessingHandler
 {
-    private \MongoDB\Collection $collection;
-
-    private Client|Manager $manager;
-
-    private string|null $namespace = null;
+    /** @var \MongoDB\Collection */
+    private $collection;
+    /** @var Client|Manager */
+    private $manager;
+    /** @var string */
+    private $namespace;
 
     /**
      * Constructor.
@@ -47,8 +47,12 @@ class MongoDBHandler extends AbstractProcessingHandler
      * @param string         $database   Database name
      * @param string         $collection Collection name
      */
-    public function __construct(Client|Manager $mongodb, string $database, string $collection, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true)
     {
+        if (!($mongodb instanceof Client || $mongodb instanceof Manager)) {
+            throw new \InvalidArgumentException('MongoDB\Client or MongoDB\Driver\Manager instance required');
+        }
+
         if ($mongodb instanceof Client) {
             $this->collection = $mongodb->selectCollection($database, $collection);
         } else {
@@ -59,21 +63,21 @@ class MongoDBHandler extends AbstractProcessingHandler
         parent::__construct($level, $bubble);
     }
 
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (isset($this->collection)) {
-            $this->collection->insertOne($record->formatted);
+            $this->collection->insertOne($record['formatted']);
         }
 
         if (isset($this->manager, $this->namespace)) {
             $bulk = new BulkWrite;
-            $bulk->insert($record->formatted);
+            $bulk->insert($record["formatted"]);
             $this->manager->executeBulkWrite($this->namespace, $bulk);
         }
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index d4c9d801079cf485131cdec8923ac16968c266cf..0c0a3bdb1cdde2bcde8421f554ec778e667ead4d 100644 (file)
@@ -11,7 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\LineFormatter;
 
 /**
@@ -26,39 +26,43 @@ class NativeMailerHandler extends MailHandler
      * The email addresses to which the message will be sent
      * @var string[]
      */
-    protected array $to;
+    protected $to;
 
     /**
      * The subject of the email
+     * @var string
      */
-    protected string $subject;
+    protected $subject;
 
     /**
      * Optional headers for the message
      * @var string[]
      */
-    protected array $headers = [];
+    protected $headers = [];
 
     /**
      * Optional parameters for the message
      * @var string[]
      */
-    protected array $parameters = [];
+    protected $parameters = [];
 
     /**
      * The wordwrap length for the message
+     * @var int
      */
-    protected int $maxColumnWidth;
+    protected $maxColumnWidth;
 
     /**
      * The Content-type for the message
+     * @var string|null
      */
-    protected string|null $contentType = null;
+    protected $contentType;
 
     /**
      * The encoding for the message
+     * @var string
      */
-    protected string $encoding = 'utf-8';
+    protected $encoding = 'utf-8';
 
     /**
      * @param string|string[] $to             The receiver of the mail
@@ -66,7 +70,7 @@ class NativeMailerHandler extends MailHandler
      * @param string          $from           The sender of the mail
      * @param int             $maxColumnWidth The maximum column width that the message lines will have
      */
-    public function __construct(string|array $to, string $subject, string $from, int|string|Level $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70)
+    public function __construct($to, string $subject, string $from, $level = Logger::ERROR, bool $bubble = true, int $maxColumnWidth = 70)
     {
         parent::__construct($level, $bubble);
         $this->to = (array) $to;
@@ -105,11 +109,11 @@ class NativeMailerHandler extends MailHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function send(string $content, array $records): void
     {
-        $contentType = $this->getContentType() ?? ($this->isHtmlBody($content) ? 'text/html' : 'text/plain');
+        $contentType = $this->getContentType() ?: ($this->isHtmlBody($content) ? 'text/html' : 'text/plain');
 
         if ($contentType !== 'text/html') {
             $content = wordwrap($content, $this->maxColumnWidth);
@@ -121,8 +125,11 @@ class NativeMailerHandler extends MailHandler
             $headers .= 'MIME-Version: 1.0' . "\r\n";
         }
 
-        $subjectFormatter = new LineFormatter($this->subject);
-        $subject = $subjectFormatter->format($this->getHighestRecord($records));
+        $subject = $this->subject;
+        if ($records) {
+            $subjectFormatter = new LineFormatter($this->subject);
+            $subject = $subjectFormatter->format($this->getHighestRecord($records));
+        }
 
         $parameters = implode(' ', $this->parameters);
         foreach ($this->to as $to) {
index b8cb3785b830191b1c9941f21b902acd6b59894b..114d749eb97c36b22499cc8e73145eaf04549e2f 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use Monolog\Formatter\NormalizerFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Class to record a log on a NewRelic application.
  * Enabling New Relic High Security mode may prevent capture of useful information.
  *
- * This handler requires a NormalizerFormatter to function and expects an array in $record->formatted
+ * This handler requires a NormalizerFormatter to function and expects an array in $record['formatted']
  *
  * @see https://docs.newrelic.com/docs/agents/php-agent
  * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
@@ -29,58 +28,75 @@ use Monolog\LogRecord;
 class NewRelicHandler extends AbstractProcessingHandler
 {
     /**
-     * @inheritDoc
+     * Name of the New Relic application that will receive logs from this handler.
+     *
+     * @var ?string
+     */
+    protected $appName;
+
+    /**
+     * Name of the current transaction
+     *
+     * @var ?string
+     */
+    protected $transactionName;
+
+    /**
+     * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
+     * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
+     *
+     * @var bool
+     */
+    protected $explodeArrays;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string|null $appName
+     * @param bool        $explodeArrays
+     * @param string|null $transactionName
      */
     public function __construct(
-        int|string|Level $level = Level::Error,
+        $level = Logger::ERROR,
         bool $bubble = true,
-
-        /**
-         * Name of the New Relic application that will receive logs from this handler.
-         */
-        protected string|null $appName = null,
-
-        /**
-         * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
-         * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
-         */
-        protected bool $explodeArrays = false,
-
-        /**
-         * Name of the current transaction
-         */
-        protected string|null $transactionName = null
+        ?string $appName = null,
+        bool $explodeArrays = false,
+        ?string $transactionName = null
     ) {
         parent::__construct($level, $bubble);
+
+        $this->appName       = $appName;
+        $this->explodeArrays = $explodeArrays;
+        $this->transactionName = $transactionName;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!$this->isNewRelicEnabled()) {
             throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
         }
 
-        if (null !== ($appName = $this->getAppName($record->context))) {
+        if ($appName = $this->getAppName($record['context'])) {
             $this->setNewRelicAppName($appName);
         }
 
-        if (null !== ($transactionName = $this->getTransactionName($record->context))) {
+        if ($transactionName = $this->getTransactionName($record['context'])) {
             $this->setNewRelicTransactionName($transactionName);
-            unset($record->formatted['context']['transaction_name']);
+            unset($record['formatted']['context']['transaction_name']);
         }
 
-        if (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) {
-            newrelic_notice_error($record->message, $record->context['exception']);
-            unset($record->formatted['context']['exception']);
+        if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) {
+            newrelic_notice_error($record['message'], $record['context']['exception']);
+            unset($record['formatted']['context']['exception']);
         } else {
-            newrelic_notice_error($record->message);
+            newrelic_notice_error($record['message']);
         }
 
-        if (isset($record->formatted['context']) && is_array($record->formatted['context'])) {
-            foreach ($record->formatted['context'] as $key => $parameter) {
+        if (isset($record['formatted']['context']) && is_array($record['formatted']['context'])) {
+            foreach ($record['formatted']['context'] as $key => $parameter) {
                 if (is_array($parameter) && $this->explodeArrays) {
                     foreach ($parameter as $paramKey => $paramValue) {
                         $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
@@ -91,8 +107,8 @@ class NewRelicHandler extends AbstractProcessingHandler
             }
         }
 
-        if (isset($record->formatted['extra']) && is_array($record->formatted['extra'])) {
-            foreach ($record->formatted['extra'] as $key => $parameter) {
+        if (isset($record['formatted']['extra']) && is_array($record['formatted']['extra'])) {
+            foreach ($record['formatted']['extra'] as $key => $parameter) {
                 if (is_array($parameter) && $this->explodeArrays) {
                     foreach ($parameter as $paramKey => $paramValue) {
                         $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
@@ -106,6 +122,8 @@ class NewRelicHandler extends AbstractProcessingHandler
 
     /**
      * Checks whether the NewRelic extension is enabled in the system.
+     *
+     * @return bool
      */
     protected function isNewRelicEnabled(): bool
     {
@@ -159,7 +177,8 @@ class NewRelicHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @param mixed $value
+     * @param string $key
+     * @param mixed  $value
      */
     protected function setNewRelicParameter(string $key, $value): void
     {
@@ -171,7 +190,7 @@ class NewRelicHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index d9fea180c50d45df06b54f0d9aba31864205427f..1ddf0beb91773e60edd352acc679dc34a764f093 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Handler;
 
-use Monolog\LogRecord;
-
 /**
  * No-op
  *
@@ -25,17 +23,17 @@ use Monolog\LogRecord;
 class NoopHandler extends Handler
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
         return true;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         return false;
     }
index 1aa84e4f8d7122d8d5cf6bce5b42ac88c0e4b930..e75ee0c6e90c0bcc617931d0503c3bb4efa6ba80 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
-use Psr\Log\LogLevel;
 use Monolog\Logger;
-use Monolog\LogRecord;
+use Psr\Log\LogLevel;
 
 /**
  * Blackhole
@@ -23,34 +21,40 @@ use Monolog\LogRecord;
  * to put on top of an existing stack to override it temporarily.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class NullHandler extends Handler
 {
-    private Level $level;
+    /**
+     * @var int
+     */
+    private $level;
 
     /**
-     * @param string|int|Level $level The minimum logging level at which this handler will be triggered
+     * @param string|int $level The minimum logging level at which this handler will be triggered
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function __construct(string|int|Level $level = Level::Debug)
+    public function __construct($level = Logger::DEBUG)
     {
         $this->level = Logger::toMonologLevel($level);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
-        return $record->level->value >= $this->level->value;
+        return $record['level'] >= $this->level;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        return $record->level->value >= $this->level->value;
+        return $record['level'] >= $this->level;
     }
 }
index a72b7a11d771a11e913a66f2a043b59bc9089c2b..22068c9a397929127f49871c056f725b1aa6cdfd 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Handler to only pass log messages when a certain threshold of number of messages is reached.
@@ -28,7 +27,7 @@ use Monolog\LogRecord;
  *   $handler = new SomeHandler(...)
  *
  *   // Pass all warnings to the handler when more than 10 & all error messages when more then 5
- *   $overflow = new OverflowHandler($handler, [Level::Warning->value => 10, Level::Error->value => 5]);
+ *   $overflow = new OverflowHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]);
  *
  *   $log->pushHandler($overflow);
  *```
@@ -37,25 +36,36 @@ use Monolog\LogRecord;
  */
 class OverflowHandler extends AbstractHandler implements FormattableHandlerInterface
 {
-    private HandlerInterface $handler;
-
-    /** @var array<int, int> */
-    private array $thresholdMap = [];
+    /** @var HandlerInterface */
+    private $handler;
+
+    /** @var int[] */
+    private $thresholdMap = [
+        Logger::DEBUG => 0,
+        Logger::INFO => 0,
+        Logger::NOTICE => 0,
+        Logger::WARNING => 0,
+        Logger::ERROR => 0,
+        Logger::CRITICAL => 0,
+        Logger::ALERT => 0,
+        Logger::EMERGENCY => 0,
+    ];
 
     /**
      * Buffer of all messages passed to the handler before the threshold was reached
      *
      * @var mixed[][]
      */
-    private array $buffer = [];
+    private $buffer = [];
 
     /**
-     * @param array<int, int> $thresholdMap Dictionary of log level value => threshold
+     * @param HandlerInterface $handler
+     * @param int[]            $thresholdMap Dictionary of logger level => threshold
      */
     public function __construct(
         HandlerInterface $handler,
         array $thresholdMap = [],
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true
     ) {
         $this->handler = $handler;
@@ -75,15 +85,15 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter
      * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
      * calling further handlers in the stack with a given log record.
      *
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if ($record->level->isLowerThan($this->level)) {
+        if ($record['level'] < $this->level) {
             return false;
         }
 
-        $level = $record->level->value;
+        $level = $record['level'];
 
         if (!isset($this->thresholdMap[$level])) {
             $this->thresholdMap[$level] = 0;
@@ -112,7 +122,7 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -126,7 +136,7 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
index 8aa78e4c429805ee487cabc61bbd1755ccbf6153..23a1d1178fb047f755fe2a1d3b2897dbc76f22f2 100644 (file)
@@ -13,13 +13,11 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use PhpConsole\Connector;
 use PhpConsole\Handler as VendorPhpConsoleHandler;
 use PhpConsole\Helper;
-use Monolog\LogRecord;
-use PhpConsole\Storage;
 
 /**
  * Monolog handler for Google Chrome extension "PHP Console"
@@ -39,59 +37,14 @@ use PhpConsole\Storage;
  *      PC::debug($_SERVER); // PHP Console debugger for any type of vars
  *
  * @author Sergey Barbushin https://www.linkedin.com/in/barbushin
- * @phpstan-type Options array{
- *     enabled: bool,
- *     classesPartialsTraceIgnore: string[],
- *     debugTagsKeysInContext: array<int|string>,
- *     useOwnErrorsHandler: bool,
- *     useOwnExceptionsHandler: bool,
- *     sourcesBasePath: string|null,
- *     registerHelper: bool,
- *     serverEncoding: string|null,
- *     headersLimit: int|null,
- *     password: string|null,
- *     enableSslOnlyMode: bool,
- *     ipMasks: string[],
- *     enableEvalListener: bool,
- *     dumperDetectCallbacks: bool,
- *     dumperLevelLimit: int,
- *     dumperItemsCountLimit: int,
- *     dumperItemSizeLimit: int,
- *     dumperDumpSizeLimit: int,
- *     detectDumpTraceAndSource: bool,
- *     dataStorage: Storage|null
- * }
- * @phpstan-type InputOptions array{
- *     enabled?: bool,
- *     classesPartialsTraceIgnore?: string[],
- *     debugTagsKeysInContext?: array<int|string>,
- *     useOwnErrorsHandler?: bool,
- *     useOwnExceptionsHandler?: bool,
- *     sourcesBasePath?: string|null,
- *     registerHelper?: bool,
- *     serverEncoding?: string|null,
- *     headersLimit?: int|null,
- *     password?: string|null,
- *     enableSslOnlyMode?: bool,
- *     ipMasks?: string[],
- *     enableEvalListener?: bool,
- *     dumperDetectCallbacks?: bool,
- *     dumperLevelLimit?: int,
- *     dumperItemsCountLimit?: int,
- *     dumperItemSizeLimit?: int,
- *     dumperDumpSizeLimit?: int,
- *     detectDumpTraceAndSource?: bool,
- *     dataStorage?: Storage|null
- * }
  *
+ * @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
 {
-    /**
-     * @phpstan-var Options
-     */
-    private array $options = [
+    /** @var array<string, mixed> */
+    private $options = [
         'enabled' => true, // bool Is PHP Console server enabled
         'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with...
         'debugTagsKeysInContext' => [0, 'tag'], // bool Is PHP Console server enabled
@@ -114,15 +67,15 @@ class PHPConsoleHandler extends AbstractProcessingHandler
         'dataStorage' => null, // \PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ)
     ];
 
-    private Connector $connector;
+    /** @var Connector */
+    private $connector;
 
     /**
      * @param  array<string, mixed> $options   See \Monolog\Handler\PHPConsoleHandler::$options for more details
      * @param  Connector|null       $connector Instance of \PhpConsole\Connector class (optional)
      * @throws \RuntimeException
-     * @phpstan-param InputOptions $options
      */
-    public function __construct(array $options = [], ?Connector $connector = null, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true)
     {
         if (!class_exists('PhpConsole\Connector')) {
             throw new \RuntimeException('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
@@ -133,16 +86,14 @@ class PHPConsoleHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @param  array<string, mixed> $options
-     * @return array<string, mixed>
+     * @param array<string, mixed> $options
      *
-     * @phpstan-param InputOptions $options
-     * @phpstan-return Options
+     * @return array<string, mixed>
      */
     private function initOptions(array $options): array
     {
         $wrongOptions = array_diff(array_keys($options), array_keys($this->options));
-        if (\count($wrongOptions) > 0) {
+        if ($wrongOptions) {
             throw new \RuntimeException('Unknown options: ' . implode(', ', $wrongOptions));
         }
 
@@ -151,8 +102,8 @@ class PHPConsoleHandler extends AbstractProcessingHandler
 
     private function initConnector(?Connector $connector = null): Connector
     {
-        if (null === $connector) {
-            if ($this->options['dataStorage'] instanceof Storage) {
+        if (!$connector) {
+            if ($this->options['dataStorage']) {
                 Connector::setPostponeStorage($this->options['dataStorage']);
             }
             $connector = Connector::getInstance();
@@ -169,22 +120,22 @@ class PHPConsoleHandler extends AbstractProcessingHandler
                 $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']);
                 $handler->start();
             }
-            if (null !== $this->options['sourcesBasePath']) {
+            if ($this->options['sourcesBasePath']) {
                 $connector->setSourcesBasePath($this->options['sourcesBasePath']);
             }
-            if (null !== $this->options['serverEncoding']) {
+            if ($this->options['serverEncoding']) {
                 $connector->setServerEncoding($this->options['serverEncoding']);
             }
-            if (null !== $this->options['password']) {
+            if ($this->options['password']) {
                 $connector->setPassword($this->options['password']);
             }
             if ($this->options['enableSslOnlyMode']) {
                 $connector->enableSslOnlyMode();
             }
-            if (\count($this->options['ipMasks']) > 0) {
+            if ($this->options['ipMasks']) {
                 $connector->setAllowedIpMasks($this->options['ipMasks']);
             }
-            if (null !== $this->options['headersLimit'] && $this->options['headersLimit'] > 0) {
+            if ($this->options['headersLimit']) {
                 $connector->setHeadersLimit($this->options['headersLimit']);
             }
             if ($this->options['detectDumpTraceAndSource']) {
@@ -217,7 +168,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler
         return $this->options;
     }
 
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         if ($this->options['enabled'] && $this->connector->isActiveClient()) {
             return parent::handle($record);
@@ -229,39 +180,48 @@ class PHPConsoleHandler extends AbstractProcessingHandler
     /**
      * Writes the record down to the log of the implementing handler
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        if ($record->level->isLowerThan(Level::Notice)) {
+        if ($record['level'] < Logger::NOTICE) {
             $this->handleDebugRecord($record);
-        } elseif (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) {
+        } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) {
             $this->handleExceptionRecord($record);
         } else {
             $this->handleErrorRecord($record);
         }
     }
 
-    private function handleDebugRecord(LogRecord $record): void
+    /**
+     * @phpstan-param Record $record
+     */
+    private function handleDebugRecord(array $record): void
     {
-        [$tags, $filteredContext] = $this->getRecordTags($record);
-        $message = $record->message;
-        if (\count($filteredContext) > 0) {
-            $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($filteredContext)), null, true);
+        $tags = $this->getRecordTags($record);
+        $message = $record['message'];
+        if ($record['context']) {
+            $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true);
         }
         $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
     }
 
-    private function handleExceptionRecord(LogRecord $record): void
+    /**
+     * @phpstan-param Record $record
+     */
+    private function handleExceptionRecord(array $record): void
     {
-        $this->connector->getErrorsDispatcher()->dispatchException($record->context['exception']);
+        $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']);
     }
 
-    private function handleErrorRecord(LogRecord $record): void
+    /**
+     * @phpstan-param Record $record
+     */
+    private function handleErrorRecord(array $record): void
     {
-        $context = $record->context;
+        $context = $record['context'];
 
         $this->connector->getErrorsDispatcher()->dispatchError(
             $context['code'] ?? null,
-            $context['message'] ?? $record->message,
+            $context['message'] ?? $record['message'],
             $context['file'] ?? null,
             $context['line'] ?? null,
             $this->options['classesPartialsTraceIgnore']
@@ -269,32 +229,32 @@ class PHPConsoleHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @return array{string, mixed[]}
+     * @phpstan-param Record $record
+     * @return string
      */
-    private function getRecordTags(LogRecord $record): array
+    private function getRecordTags(array &$record)
     {
         $tags = null;
-        $filteredContext = [];
-        if ($record->context !== []) {
-            $filteredContext = $record->context;
+        if (!empty($record['context'])) {
+            $context = & $record['context'];
             foreach ($this->options['debugTagsKeysInContext'] as $key) {
-                if (isset($filteredContext[$key])) {
-                    $tags = $filteredContext[$key];
+                if (!empty($context[$key])) {
+                    $tags = $context[$key];
                     if ($key === 0) {
-                        array_shift($filteredContext);
+                        array_shift($context);
                     } else {
-                        unset($filteredContext[$key]);
+                        unset($context[$key]);
                     }
                     break;
                 }
             }
         }
 
-        return [$tags ?? $record->level->toPsrLogLevel(), $filteredContext];
+        return $tags ?: strtolower($record['level_name']);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 9edc9ac543d6b1bfbef8b2cd2c2c3449923a3201..8a8cf1be6608edddc365833d1a7e35226bbfb02c 100644 (file)
@@ -11,8 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Stores to STDIN of any process, specified by a command.
@@ -34,14 +33,20 @@ class ProcessHandler extends AbstractProcessingHandler
      */
     private $process;
 
-    private string $command;
+    /**
+     * @var string
+     */
+    private $command;
 
-    private ?string $cwd;
+    /**
+     * @var string|null
+     */
+    private $cwd;
 
     /**
      * @var resource[]
      */
-    private array $pipes = [];
+    private $pipes = [];
 
     /**
      * @var array<int, string[]>
@@ -58,7 +63,7 @@ class ProcessHandler extends AbstractProcessingHandler
      * @param  string|null               $cwd     "Current working directory" (CWD) for the process to be executed in.
      * @throws \InvalidArgumentException
      */
-    public function __construct(string $command, int|string|Level $level = Level::Debug, bool $bubble = true, ?string $cwd = null)
+    public function __construct(string $command, $level = Logger::DEBUG, bool $bubble = true, ?string $cwd = null)
     {
         if ($command === '') {
             throw new \InvalidArgumentException('The command argument must be a non-empty string.');
@@ -78,14 +83,14 @@ class ProcessHandler extends AbstractProcessingHandler
      *
      * @throws \UnexpectedValueException
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         $this->ensureProcessIsStarted();
 
-        $this->writeProcessInput($record->formatted);
+        $this->writeProcessInput($record['formatted']);
 
         $errors = $this->readProcessErrors();
-        if ($errors !== '') {
+        if (empty($errors) === false) {
             throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors));
         }
     }
@@ -129,7 +134,7 @@ class ProcessHandler extends AbstractProcessingHandler
 
         $errors = $this->readProcessErrors();
 
-        if (is_resource($this->process) === false || $errors !== '') {
+        if (is_resource($this->process) === false || empty($errors) === false) {
             throw new \UnexpectedValueException(
                 sprintf('The process "%s" could not be opened: ' . $errors, $this->command)
             );
@@ -171,7 +176,7 @@ class ProcessHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
index 9fb290faadbc945eca68edf787c5e6f2c373389e..3adec7a4d8e1614e463f1a7981ce3ce93c4a8397 100644 (file)
 namespace Monolog\Handler;
 
 use Monolog\Processor\ProcessorInterface;
-use Monolog\LogRecord;
 
 /**
  * Interface to describe loggers that have processors
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 interface ProcessableHandlerInterface
 {
     /**
      * Adds a processor in the stack.
      *
-     * @phpstan-param ProcessorInterface|(callable(LogRecord): LogRecord) $callback
+     * @psalm-param ProcessorInterface|callable(Record): Record $callback
      *
      * @param  ProcessorInterface|callable $callback
      * @return HandlerInterface            self
@@ -34,7 +35,7 @@ interface ProcessableHandlerInterface
     /**
      * Removes the processor on top of the stack and returns it.
      *
-     * @phpstan-return ProcessorInterface|(callable(LogRecord): LogRecord) $callback
+     * @psalm-return ProcessorInterface|callable(Record): Record $callback
      *
      * @throws \LogicException             In case the processor stack is empty
      * @return callable|ProcessorInterface
index 74eeddddcec3f3afec7a960abb9c7bbfa2382cc6..9ef6e301c54ca11055eba08e9e7d1b04d2d6efde 100644 (file)
@@ -13,23 +13,24 @@ namespace Monolog\Handler;
 
 use Monolog\ResettableInterface;
 use Monolog\Processor\ProcessorInterface;
-use Monolog\LogRecord;
 
 /**
  * Helper trait for implementing ProcessableInterface
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 trait ProcessableHandlerTrait
 {
     /**
      * @var callable[]
-     * @phpstan-var array<(callable(LogRecord): LogRecord)|ProcessorInterface>
+     * @phpstan-var array<ProcessorInterface|callable(Record): Record>
      */
-    protected array $processors = [];
+    protected $processors = [];
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function pushProcessor(callable $callback): HandlerInterface
     {
@@ -39,18 +40,24 @@ trait ProcessableHandlerTrait
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function popProcessor(): callable
     {
-        if (\count($this->processors) === 0) {
+        if (!$this->processors) {
             throw new \LogicException('You tried to pop from an empty processor stack.');
         }
 
         return array_shift($this->processors);
     }
 
-    protected function processRecord(LogRecord $record): LogRecord
+    /**
+     * Processes a record.
+     *
+     * @phpstan-param  Record $record
+     * @phpstan-return Record
+     */
+    protected function processRecord(array $record): array
     {
         foreach ($this->processors as $processor) {
             $record = $processor($record);
index 6599a83b42458d51770fde580d5310e48b576db7..36e19cccf2f283ff1f05db0f34f65f73e66d27ad 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Psr\Log\LoggerInterface;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Proxies log messages to an existing PSR-3 compliant logger.
@@ -29,15 +28,20 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface
 {
     /**
      * PSR-3 compliant logger
+     *
+     * @var LoggerInterface
      */
-    protected LoggerInterface $logger;
+    protected $logger;
 
-    protected FormatterInterface|null $formatter = null;
+    /**
+     * @var FormatterInterface|null
+     */
+    protected $formatter;
 
     /**
      * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied
      */
-    public function __construct(LoggerInterface $logger, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
@@ -45,19 +49,19 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         if (!$this->isHandling($record)) {
             return false;
         }
 
-        if ($this->formatter !== null) {
+        if ($this->formatter) {
             $formatted = $this->formatter->format($record);
-            $this->logger->log($record->level->toPsrLogLevel(), (string) $formatted, $record->context);
+            $this->logger->log(strtolower($record['level_name']), (string) $formatted, $record['context']);
         } else {
-            $this->logger->log($record->level->toPsrLogLevel(), $record->message, $record->context);
+            $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']);
         }
 
         return false === $this->bubble;
@@ -65,6 +69,8 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface
 
     /**
      * Sets the formatter.
+     *
+     * @param FormatterInterface $formatter
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -75,10 +81,12 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface
 
     /**
      * Gets the formatter.
+     *
+     * @return FormatterInterface
      */
     public function getFormatter(): FormatterInterface
     {
-        if ($this->formatter === null) {
+        if (!$this->formatter) {
             throw new \LogicException('No formatter has been set and this handler does not have a default formatter');
         }
 
index 118f5760a110e5711774bd4aca8b7d2fb64e5078..fed2303d7b572606fc354ffa28789a38047e9163 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Monolog\Utils;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Sends notifications through the pushover api to mobile phones
  *
  * @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
  * @see    https://www.pushover.net/api
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class PushoverHandler extends SocketHandler
 {
-    private string $token;
-
+    /** @var string */
+    private $token;
     /** @var array<int|string> */
-    private array $users;
-
-    private string $title;
-
-    private string|int|null $user = null;
-
-    private int $retry;
-
-    private int $expire;
-
-    private Level $highPriorityLevel;
-
-    private Level $emergencyLevel;
-
-    private bool $useFormattedMessage = false;
+    private $users;
+    /** @var string */
+    private $title;
+    /** @var string|int|null */
+    private $user = null;
+    /** @var int */
+    private $retry;
+    /** @var int */
+    private $expire;
+
+    /** @var int */
+    private $highPriorityLevel;
+    /** @var int */
+    private $emergencyLevel;
+    /** @var bool */
+    private $useFormattedMessage = false;
 
     /**
      * All parameters that can be sent to Pushover
      * @see https://pushover.net/api
      * @var array<string, bool>
      */
-    private array $parameterNames = [
+    private $parameterNames = [
         'token' => true,
         'user' => true,
         'message' => true,
@@ -70,42 +73,40 @@ class PushoverHandler extends SocketHandler
      * @see https://pushover.net/api#sounds
      * @var string[]
      */
-    private array $sounds = [
+    private $sounds = [
         'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming',
         'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb',
         'persistent', 'echo', 'updown', 'none',
     ];
 
     /**
-     * @param string       $token  Pushover api token
-     * @param string|array $users  Pushover user id or array of ids the message will be sent to
-     * @param string|null  $title  Title sent to the Pushover API
-     * @param bool         $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
-     *                             the pushover.net app owner. OpenSSL is required for this option.
-     * @param int          $retry  The retry parameter specifies how often (in seconds) the Pushover servers will
-     *                             send the same notification to the user.
-     * @param int          $expire The expire parameter specifies how many seconds your notification will continue
-     *                             to be retried for (every retry seconds).
-     *
-     * @param int|string|Level|LogLevel::* $highPriorityLevel The minimum logging level at which this handler will start
-     *                                                                  sending "high priority" requests to the Pushover API
-     * @param int|string|Level|LogLevel::* $emergencyLevel    The minimum logging level at which this handler will start
-     *                                                                  sending "emergency" requests to the Pushover API
-     *
+     * @param string       $token             Pushover api token
+     * @param string|array $users             Pushover user id or array of ids the message will be sent to
+     * @param string|null  $title             Title sent to the Pushover API
+     * @param bool         $useSSL            Whether to connect via SSL. Required when pushing messages to users that are not
+     *                                        the pushover.net app owner. OpenSSL is required for this option.
+     * @param string|int   $highPriorityLevel The minimum logging level at which this handler will start
+     *                                        sending "high priority" requests to the Pushover API
+     * @param string|int   $emergencyLevel    The minimum logging level at which this handler will start
+     *                                        sending "emergency" requests to the Pushover API
+     * @param int          $retry             The retry parameter specifies how often (in seconds) the Pushover servers will
+     *                                        send the same notification to the user.
+     * @param int          $expire            The expire parameter specifies how many seconds your notification will continue
+     *                                        to be retried for (every retry seconds).
      *
      * @phpstan-param string|array<int|string>    $users
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $highPriorityLevel
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $emergencyLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel
+     * @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel
      */
     public function __construct(
         string $token,
         $users,
         ?string $title = null,
-        int|string|Level $level = Level::Critical,
+        $level = Logger::CRITICAL,
         bool $bubble = true,
         bool $useSSL = true,
-        int|string|Level $highPriorityLevel = Level::Critical,
-        int|string|Level $emergencyLevel = Level::Emergency,
+        $highPriorityLevel = Logger::CRITICAL,
+        $emergencyLevel = Logger::EMERGENCY,
         int $retry = 30,
         int $expire = 25200,
         bool $persistent = false,
@@ -128,29 +129,32 @@ class PushoverHandler extends SocketHandler
 
         $this->token = $token;
         $this->users = (array) $users;
-        $this->title = $title ?? (string) gethostname();
+        $this->title = $title ?: (string) gethostname();
         $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
         $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
         $this->retry = $retry;
         $this->expire = $expire;
     }
 
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
         $content = $this->buildContent($record);
 
         return $this->buildHeader($content) . $content;
     }
 
-    private function buildContent(LogRecord $record): string
+    /**
+     * @phpstan-param FormattedRecord $record
+     */
+    private function buildContent(array $record): string
     {
         // Pushover has a limit of 512 characters on title and message combined.
         $maxMessageLength = 512 - strlen($this->title);
 
-        $message = ($this->useFormattedMessage) ? $record->formatted : $record->message;
+        $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message'];
         $message = Utils::substr($message, 0, $maxMessageLength);
 
-        $timestamp = $record->datetime->getTimestamp();
+        $timestamp = $record['datetime']->getTimestamp();
 
         $dataArray = [
             'token' => $this->token,
@@ -160,23 +164,23 @@ class PushoverHandler extends SocketHandler
             'timestamp' => $timestamp,
         ];
 
-        if ($record->level->value >= $this->emergencyLevel->value) {
+        if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
             $dataArray['priority'] = 2;
             $dataArray['retry'] = $this->retry;
             $dataArray['expire'] = $this->expire;
-        } elseif ($record->level->value >= $this->highPriorityLevel->value) {
+        } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) {
             $dataArray['priority'] = 1;
         }
 
         // First determine the available parameters
-        $context = array_intersect_key($record->context, $this->parameterNames);
-        $extra = array_intersect_key($record->extra, $this->parameterNames);
+        $context = array_intersect_key($record['context'], $this->parameterNames);
+        $extra = array_intersect_key($record['extra'], $this->parameterNames);
 
         // Least important info should be merged with subsequent info
         $dataArray = array_merge($extra, $context, $dataArray);
 
         // Only pass sounds that are supported by the API
-        if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds, true)) {
+        if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds)) {
             unset($dataArray['sound']);
         }
 
@@ -194,7 +198,7 @@ class PushoverHandler extends SocketHandler
         return $header;
     }
 
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         foreach ($this->users as $user) {
             $this->user = $user;
@@ -207,25 +211,25 @@ class PushoverHandler extends SocketHandler
     }
 
     /**
-     * @param int|string|Level|LogLevel::* $level
+     * @param int|string $value
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $value
      */
-    public function setHighPriorityLevel(int|string|Level $level): self
+    public function setHighPriorityLevel($value): self
     {
-        $this->highPriorityLevel = Logger::toMonologLevel($level);
+        $this->highPriorityLevel = Logger::toMonologLevel($value);
 
         return $this;
     }
 
     /**
-     * @param int|string|Level|LogLevel::* $level
+     * @param int|string $value
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $value
      */
-    public function setEmergencyLevel(int|string|Level $level): self
+    public function setEmergencyLevel($value): self
     {
-        $this->emergencyLevel = Logger::toMonologLevel($level);
+        $this->emergencyLevel = Logger::toMonologLevel($value);
 
         return $this;
     }
@@ -233,9 +237,9 @@ class PushoverHandler extends SocketHandler
     /**
      * Use the formatted message?
      */
-    public function useFormattedMessage(bool $useFormattedMessage): self
+    public function useFormattedMessage(bool $value): self
     {
-        $this->useFormattedMessage = $useFormattedMessage;
+        $this->useFormattedMessage = $value;
 
         return $this;
     }
index 5eee5dc693bb49b4c3af16756baa551b3bfcf821..91d16eaf64c5cbb13f4d436bdf6c4c5199898a01 100644 (file)
@@ -13,10 +13,7 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
-use Monolog\LogRecord;
-use Predis\Client as Predis;
-use Redis;
+use Monolog\Logger;
 
 /**
  * Logs to a Redis key using rpush
@@ -28,21 +25,29 @@ use Redis;
  *   $log->pushHandler($redis);
  *
  * @author Thomas Tourlourat <thomas@tourlourat.com>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class RedisHandler extends AbstractProcessingHandler
 {
-    /** @var Predis<Predis>|Redis */
-    private Predis|Redis $redisClient;
-    private string $redisKey;
-    protected int $capSize;
+    /** @var \Predis\Client<\Predis\Client>|\Redis */
+    private $redisClient;
+    /** @var string */
+    private $redisKey;
+    /** @var int */
+    protected $capSize;
 
     /**
-     * @param Predis<Predis>|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
+     * @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
      */
-    public function __construct(Predis|Redis $redis, string $key, int|string|Level $level = Level::Debug, bool $bubble = true, int $capSize = 0)
+    public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true, int $capSize = 0)
     {
+        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+        }
+
         $this->redisClient = $redis;
         $this->redisKey = $key;
         $this->capSize = $capSize;
@@ -51,41 +56,43 @@ class RedisHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        if ($this->capSize > 0) {
+        if ($this->capSize) {
             $this->writeCapped($record);
         } else {
-            $this->redisClient->rpush($this->redisKey, $record->formatted);
+            $this->redisClient->rpush($this->redisKey, $record["formatted"]);
         }
     }
 
     /**
      * Write and cap the collection
      * Writes the record to the redis list and caps its
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    protected function writeCapped(LogRecord $record): void
+    protected function writeCapped(array $record): void
     {
-        if ($this->redisClient instanceof Redis) {
-            $mode = defined('Redis::MULTI') ? Redis::MULTI : 1;
+        if ($this->redisClient instanceof \Redis) {
+            $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1;
             $this->redisClient->multi($mode)
-                ->rPush($this->redisKey, $record->formatted)
+                ->rpush($this->redisKey, $record["formatted"])
                 ->ltrim($this->redisKey, -$this->capSize, -1)
                 ->exec();
         } else {
             $redisKey = $this->redisKey;
             $capSize = $this->capSize;
             $this->redisClient->transaction(function ($tx) use ($record, $redisKey, $capSize) {
-                $tx->rpush($redisKey, $record->formatted);
+                $tx->rpush($redisKey, $record["formatted"]);
                 $tx->ltrim($redisKey, -$capSize, -1);
             });
         }
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index fa8e9e9ffd338c605b3bd76ce9f48ee00c124f25..7789309c1c3967640714e25c7fdd4e46231e55ed 100644 (file)
@@ -13,10 +13,7 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\LineFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
-use Monolog\LogRecord;
-use Predis\Client as Predis;
-use Redis;
+use Monolog\Logger;
 
 /**
  * Sends the message to a Redis Pub/Sub channel using PUBLISH
@@ -24,23 +21,28 @@ use Redis;
  * usage example:
  *
  *   $log = new Logger('application');
- *   $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Level::Warning);
+ *   $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING);
  *   $log->pushHandler($redis);
  *
  * @author Gaëtan Faugère <gaetan@fauge.re>
  */
 class RedisPubSubHandler extends AbstractProcessingHandler
 {
-    /** @var Predis<Predis>|Redis */
-    private Predis|Redis $redisClient;
-    private string $channelKey;
+    /** @var \Predis\Client<\Predis\Client>|\Redis */
+    private $redisClient;
+    /** @var string */
+    private $channelKey;
 
     /**
-     * @param Predis<Predis>|Redis $redis The redis instance
-     * @param string               $key   The channel key to publish records to
+     * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance
+     * @param string                $key   The channel key to publish records to
      */
-    public function __construct(Predis|Redis $redis, string $key, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true)
     {
+        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+        }
+
         $this->redisClient = $redis;
         $this->channelKey = $key;
 
@@ -48,15 +50,15 @@ class RedisPubSubHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->redisClient->publish($this->channelKey, $record->formatted);
+        $this->redisClient->publish($this->channelKey, $record["formatted"]);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function getDefaultFormatter(): FormatterInterface
     {
index 1d124723b49d84bd42bf8eb4ea62f02e91f10125..adcc9395a5835a9dcf67a42391b1fd74d3ce644f 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
 use Rollbar\RollbarLogger;
 use Throwable;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Sends errors to Rollbar
@@ -34,19 +33,37 @@ use Monolog\LogRecord;
  */
 class RollbarHandler extends AbstractProcessingHandler
 {
-    protected RollbarLogger $rollbarLogger;
+    /**
+     * @var RollbarLogger
+     */
+    protected $rollbarLogger;
+
+    /** @var string[] */
+    protected $levelMap = [
+        Logger::DEBUG     => 'debug',
+        Logger::INFO      => 'info',
+        Logger::NOTICE    => 'info',
+        Logger::WARNING   => 'warning',
+        Logger::ERROR     => 'error',
+        Logger::CRITICAL  => 'critical',
+        Logger::ALERT     => 'critical',
+        Logger::EMERGENCY => 'critical',
+    ];
 
     /**
      * Records whether any log records have been added since the last flush of the rollbar notifier
+     *
+     * @var bool
      */
-    private bool $hasRecords = false;
+    private $hasRecords = false;
 
-    protected bool $initialized = false;
+    /** @var bool */
+    protected $initialized = false;
 
     /**
      * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token
      */
-    public function __construct(RollbarLogger $rollbarLogger, int|string|Level $level = Level::Error, bool $bubble = true)
+    public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true)
     {
         $this->rollbarLogger = $rollbarLogger;
 
@@ -54,41 +71,22 @@ class RollbarHandler extends AbstractProcessingHandler
     }
 
     /**
-     * Translates Monolog log levels to Rollbar levels.
-     *
-     * @return 'debug'|'info'|'warning'|'error'|'critical'
-     */
-    protected function toRollbarLevel(Level $level): string
-    {
-        return match ($level) {
-            Level::Debug     => 'debug',
-            Level::Info      => 'info',
-            Level::Notice    => 'info',
-            Level::Warning   => 'warning',
-            Level::Error     => 'error',
-            Level::Critical  => 'critical',
-            Level::Alert     => 'critical',
-            Level::Emergency => 'critical',
-        };
-    }
-
-    /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!$this->initialized) {
             // __destructor() doesn't get called on Fatal errors
-            register_shutdown_function([$this, 'close']);
+            register_shutdown_function(array($this, 'close'));
             $this->initialized = true;
         }
 
-        $context = $record->context;
-        $context = array_merge($context, $record->extra, [
-            'level' => $this->toRollbarLevel($record->level),
-            'monolog_level' => $record->level->getName(),
-            'channel' => $record->channel,
-            'datetime' => $record->datetime->format('U'),
+        $context = $record['context'];
+        $context = array_merge($context, $record['extra'], [
+            'level' => $this->levelMap[$record['level']],
+            'monolog_level' => $record['level_name'],
+            'channel' => $record['channel'],
+            'datetime' => $record['datetime']->format('U'),
         ]);
 
         if (isset($context['exception']) && $context['exception'] instanceof Throwable) {
@@ -96,7 +94,7 @@ class RollbarHandler extends AbstractProcessingHandler
             unset($context['exception']);
             $toLog = $exception;
         } else {
-            $toLog = $record->message;
+            $toLog = $record['message'];
         }
 
         // @phpstan-ignore-next-line
@@ -114,7 +112,7 @@ class RollbarHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -122,9 +120,9 @@ class RollbarHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function reset(): void
+    public function reset()
     {
         $this->flush();
 
index 12ce69236787d05350b7b5ead479841a07c5ec04..17745d22156dc9af2a6dd87e195522b5b328a547 100644 (file)
@@ -12,9 +12,8 @@
 namespace Monolog\Handler;
 
 use InvalidArgumentException;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Stores logs to files that are rotated every day and a limited number of files are kept.
@@ -31,19 +30,26 @@ class RotatingFileHandler extends StreamHandler
     public const FILE_PER_MONTH = 'Y-m';
     public const FILE_PER_YEAR = 'Y';
 
-    protected string $filename;
-    protected int $maxFiles;
-    protected bool|null $mustRotate = null;
-    protected \DateTimeImmutable $nextRotation;
-    protected string $filenameFormat;
-    protected string $dateFormat;
+    /** @var string */
+    protected $filename;
+    /** @var int */
+    protected $maxFiles;
+    /** @var bool */
+    protected $mustRotate;
+    /** @var \DateTimeImmutable */
+    protected $nextRotation;
+    /** @var string */
+    protected $filenameFormat;
+    /** @var string */
+    protected $dateFormat;
 
     /**
-     * @param int      $maxFiles       The maximal amount of files to keep (0 means unlimited)
-     * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
-     * @param bool     $useLocking     Try to lock log file before doing any writes
+     * @param string     $filename
+     * @param int        $maxFiles       The maximal amount of files to keep (0 means unlimited)
+     * @param int|null   $filePermission Optional file permissions (default (0644) are only for owner read/write)
+     * @param bool       $useLocking     Try to lock log file before doing any writes
      */
-    public function __construct(string $filename, int $maxFiles = 0, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false)
+    public function __construct(string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false)
     {
         $this->filename = Utils::canonicalizePath($filename);
         $this->maxFiles = $maxFiles;
@@ -55,7 +61,7 @@ class RotatingFileHandler extends StreamHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -67,9 +73,9 @@ class RotatingFileHandler extends StreamHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function reset(): void
+    public function reset()
     {
         parent::reset();
 
@@ -80,7 +86,7 @@ class RotatingFileHandler extends StreamHandler
 
     public function setFilenameFormat(string $filenameFormat, string $dateFormat): self
     {
-        if (0 === preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
+        if (!preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
             throw new InvalidArgumentException(
                 'Invalid date format - format must be one of '.
                 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '.
@@ -102,16 +108,16 @@ class RotatingFileHandler extends StreamHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         // on the first record written, if the log is new, we should rotate (once per day)
         if (null === $this->mustRotate) {
             $this->mustRotate = null === $this->url || !file_exists($this->url);
         }
 
-        if ($this->nextRotation <= $record->datetime) {
+        if ($this->nextRotation <= $record['datetime']) {
             $this->mustRotate = true;
             $this->close();
         }
index 511ec585421f3ffe5c5c290740fc3b4357f4550b..c128a32d18ebfb5da0299c0b4c5de52b28bd78a7 100644 (file)
@@ -11,9 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Closure;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Sampling handler
@@ -28,42 +26,52 @@ use Monolog\LogRecord;
  *
  * @author Bryan Davis <bd808@wikimedia.org>
  * @author Kunal Mehta <legoktm@gmail.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
 {
     use ProcessableHandlerTrait;
 
     /**
-     * Handler or factory Closure($record, $this)
-     *
-     * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface
+     * @var HandlerInterface|callable
+     * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface
      */
-    protected Closure|HandlerInterface $handler;
+    protected $handler;
 
-    protected int $factor;
+    /**
+     * @var int $factor
+     */
+    protected $factor;
 
     /**
-     * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler
+     * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler
      *
-     * @param Closure|HandlerInterface $handler Handler or factory Closure($record|null, $samplingHandler).
-     * @param int                      $factor  Sample factor (e.g. 10 means every ~10th record is sampled)
+     * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
+     * @param int                       $factor  Sample factor (e.g. 10 means every ~10th record is sampled)
      */
-    public function __construct(Closure|HandlerInterface $handler, int $factor)
+    public function __construct($handler, int $factor)
     {
         parent::__construct();
         $this->handler = $handler;
         $this->factor = $factor;
+
+        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+        }
     }
 
-    public function isHandling(LogRecord $record): bool
+    public function isHandling(array $record): bool
     {
         return $this->getHandler($record)->isHandling($record);
     }
 
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
         if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
-            if (\count($this->processors) > 0) {
+            if ($this->processors) {
+                /** @var Record $record */
                 $record = $this->processRecord($record);
             }
 
@@ -76,23 +84,26 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
     /**
      * Return the nested handler
      *
-     * If the handler was provided as a factory, this will trigger the handler's instantiation.
+     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+     *
+     * @phpstan-param Record|array{level: Level}|null $record
+     *
+     * @return HandlerInterface
      */
-    public function getHandler(LogRecord $record = null): HandlerInterface
+    public function getHandler(array $record = null)
     {
         if (!$this->handler instanceof HandlerInterface) {
-            $handler = ($this->handler)($record, $this);
-            if (!$handler instanceof HandlerInterface) {
-                throw new \RuntimeException("The factory Closure should return a HandlerInterface");
+            $this->handler = ($this->handler)($record, $this);
+            if (!$this->handler instanceof HandlerInterface) {
+                throw new \RuntimeException("The factory callable should return a HandlerInterface");
             }
-            $this->handler = $handler;
         }
 
         return $this->handler;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function setFormatter(FormatterInterface $formatter): HandlerInterface
     {
@@ -107,7 +118,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getFormatter(): FormatterInterface
     {
index 6228a02f29f19c7a257b51bb72749fa1f530224d..1280ee7039f8f187d052d3f54f2f9917272eaa85 100644 (file)
@@ -11,7 +11,7 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 
 /**
  * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html
@@ -22,29 +22,33 @@ class SendGridHandler extends MailHandler
 {
     /**
      * The SendGrid API User
+     * @var string
      */
-    protected string $apiUser;
+    protected $apiUser;
 
     /**
      * The SendGrid API Key
+     * @var string
      */
-    protected string $apiKey;
+    protected $apiKey;
 
     /**
      * The email addresses to which the message will be sent
+     * @var string
      */
-    protected string $from;
+    protected $from;
 
     /**
      * The email addresses to which the message will be sent
      * @var string[]
      */
-    protected array $to;
+    protected $to;
 
     /**
      * The subject of the email
+     * @var string
      */
-    protected string $subject;
+    protected $subject;
 
     /**
      * @param string          $apiUser The SendGrid API User
@@ -53,7 +57,7 @@ class SendGridHandler extends MailHandler
      * @param string|string[] $to      The recipients of the email
      * @param string          $subject The subject of the mail
      */
-    public function __construct(string $apiUser, string $apiKey, string $from, string|array $to, string $subject, int|string|Level $level = Level::Error, bool $bubble = true)
+    public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true)
     {
         if (!extension_loaded('curl')) {
             throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler');
@@ -68,7 +72,7 @@ class SendGridHandler extends MailHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     protected function send(string $content, array $records): void
     {
index 7e9cccc9df4ab8fa145c3af661903d8c53061bcb..71a41094617f1016f469e31efec6e98698768e48 100644 (file)
 
 namespace Monolog\Handler\Slack;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use Monolog\Formatter\NormalizerFormatter;
 use Monolog\Formatter\FormatterInterface;
-use Monolog\LogRecord;
 
 /**
  * Slack record utility helping to log to Slack webhooks or API.
@@ -24,6 +23,9 @@ use Monolog\LogRecord;
  * @author Haralan Dobrev <hkdobrev@gmail.com>
  * @see    https://api.slack.com/incoming-webhooks
  * @see    https://api.slack.com/docs/message-attachments
+ *
+ * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class SlackRecord
 {
@@ -37,43 +39,55 @@ class SlackRecord
 
     /**
      * Slack channel (encoded ID or name)
+     * @var string|null
      */
-    private string|null $channel;
+    private $channel;
 
     /**
      * Name of a bot
+     * @var string|null
      */
-    private string|null $username;
+    private $username;
 
     /**
      * User icon e.g. 'ghost', 'http://example.com/user.png'
+     * @var string|null
      */
-    private string|null $userIcon;
+    private $userIcon;
 
     /**
      * Whether the message should be added to Slack as attachment (plain text otherwise)
+     * @var bool
      */
-    private bool $useAttachment;
+    private $useAttachment;
 
     /**
      * Whether the the context/extra messages added to Slack as attachments are in a short style
+     * @var bool
      */
-    private bool $useShortAttachment;
+    private $useShortAttachment;
 
     /**
      * Whether the attachment should include context and extra data
+     * @var bool
      */
-    private bool $includeContextAndExtra;
+    private $includeContextAndExtra;
 
     /**
      * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
      * @var string[]
      */
-    private array $excludeFields;
+    private $excludeFields;
 
-    private FormatterInterface|null $formatter;
+    /**
+     * @var ?FormatterInterface
+     */
+    private $formatter;
 
-    private NormalizerFormatter $normalizerFormatter;
+    /**
+     * @var NormalizerFormatter
+     */
+    private $normalizerFormatter;
 
     /**
      * @param string[] $excludeFields
@@ -85,7 +99,7 @@ class SlackRecord
         ?string $userIcon = null,
         bool $useShortAttachment = false,
         bool $includeContextAndExtra = false,
-        array $excludeFields = [],
+        array $excludeFields = array(),
         FormatterInterface $formatter = null
     ) {
         $this
@@ -107,76 +121,77 @@ class SlackRecord
      * Returns required data in format that Slack
      * is expecting.
      *
+     * @phpstan-param FormattedRecord $record
      * @phpstan-return mixed[]
      */
-    public function getSlackData(LogRecord $record): array
+    public function getSlackData(array $record): array
     {
-        $dataArray = [];
+        $dataArray = array();
+        $record = $this->removeExcludedFields($record);
 
-        if ($this->username !== null) {
+        if ($this->username) {
             $dataArray['username'] = $this->username;
         }
 
-        if ($this->channel !== null) {
+        if ($this->channel) {
             $dataArray['channel'] = $this->channel;
         }
 
-        if ($this->formatter !== null && !$this->useAttachment) {
+        if ($this->formatter && !$this->useAttachment) {
+            /** @phpstan-ignore-next-line */
             $message = $this->formatter->format($record);
         } else {
-            $message = $record->message;
+            $message = $record['message'];
         }
 
-        $recordData = $this->removeExcludedFields($record);
-
         if ($this->useAttachment) {
-            $attachment = [
-                'fallback'  => $message,
-                'text'      => $message,
-                'color'     => $this->getAttachmentColor($record->level),
-                'fields'    => [],
-                'mrkdwn_in' => ['fields'],
-                'ts'        => $recordData['datetime']->getTimestamp(),
+            $attachment = array(
+                'fallback'    => $message,
+                'text'        => $message,
+                'color'       => $this->getAttachmentColor($record['level']),
+                'fields'      => array(),
+                'mrkdwn_in'   => array('fields'),
+                'ts'          => $record['datetime']->getTimestamp(),
                 'footer'      => $this->username,
                 'footer_icon' => $this->userIcon,
-            ];
+            );
 
             if ($this->useShortAttachment) {
-                $attachment['title'] = $recordData['level_name'];
+                $attachment['title'] = $record['level_name'];
             } else {
                 $attachment['title'] = 'Message';
-                $attachment['fields'][] = $this->generateAttachmentField('Level', $recordData['level_name']);
+                $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']);
             }
 
             if ($this->includeContextAndExtra) {
-                foreach (['extra', 'context'] as $key) {
-                    if (!isset($recordData[$key]) || \count($recordData[$key]) === 0) {
+                foreach (array('extra', 'context') as $key) {
+                    if (empty($record[$key])) {
                         continue;
                     }
 
                     if ($this->useShortAttachment) {
                         $attachment['fields'][] = $this->generateAttachmentField(
-                            $key,
-                            $recordData[$key]
+                            (string) $key,
+                            $record[$key]
                         );
                     } else {
                         // Add all extra fields as individual fields in attachment
                         $attachment['fields'] = array_merge(
                             $attachment['fields'],
-                            $this->generateAttachmentFields($recordData[$key])
+                            $this->generateAttachmentFields($record[$key])
                         );
                     }
                 }
             }
 
-            $dataArray['attachments'] = [$attachment];
+            $dataArray['attachments'] = array($attachment);
         } else {
             $dataArray['text'] = $message;
         }
 
-        if ($this->userIcon !== null) {
-            if (false !== ($iconUrl = filter_var($this->userIcon, FILTER_VALIDATE_URL))) {
-                $dataArray['icon_url'] = $iconUrl;
+        if ($this->userIcon) {
+            if (filter_var($this->userIcon, FILTER_VALIDATE_URL)) {
+                $dataArray['icon_url'] = $this->userIcon;
             } else {
                 $dataArray['icon_emoji'] = ":{$this->userIcon}:";
             }
@@ -189,14 +204,18 @@ class SlackRecord
      * Returns a Slack message attachment color associated with
      * provided level.
      */
-    public function getAttachmentColor(Level $level): string
+    public function getAttachmentColor(int $level): string
     {
-        return match ($level) {
-            Level::Error, Level::Critical, Level::Alert, Level::Emergency => static::COLOR_DANGER,
-            Level::Warning => static::COLOR_WARNING,
-            Level::Info, Level::Notice => static::COLOR_GOOD,
-            Level::Debug => static::COLOR_DEFAULT
-        };
+        switch (true) {
+            case $level >= Logger::ERROR:
+                return static::COLOR_DANGER;
+            case $level >= Logger::WARNING:
+                return static::COLOR_WARNING;
+            case $level >= Logger::INFO:
+                return static::COLOR_GOOD;
+            default:
+                return static::COLOR_DEFAULT;
+        }
     }
 
     /**
@@ -206,13 +225,13 @@ class SlackRecord
      */
     public function stringify(array $fields): string
     {
-        /** @var array<mixed> $normalized */
-        $normalized = $this->normalizerFormatter->normalizeValue($fields);
+        /** @var Record $fields */
+        $normalized = $this->normalizerFormatter->format($fields);
 
-        $hasSecondDimension = \count(array_filter($normalized, 'is_array')) > 0;
-        $hasOnlyNonNumericKeys = \count(array_filter(array_keys($normalized), 'is_numeric')) === 0;
+        $hasSecondDimension = count(array_filter($normalized, 'is_array'));
+        $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
 
-        return $hasSecondDimension || $hasOnlyNonNumericKeys
+        return $hasSecondDimension || $hasNonNumericKeys
             ? Utils::jsonEncode($normalized, JSON_PRETTY_PRINT|Utils::DEFAULT_JSON_FLAGS)
             : Utils::jsonEncode($normalized, Utils::DEFAULT_JSON_FLAGS);
     }
@@ -311,11 +330,11 @@ class SlackRecord
             ? sprintf('```%s```', substr($this->stringify($value), 0, 1990))
             : $value;
 
-        return [
+        return array(
             'title' => ucfirst($title),
             'value' => $value,
             'short' => false,
-        ];
+        );
     }
 
     /**
@@ -327,10 +346,10 @@ class SlackRecord
      */
     private function generateAttachmentFields(array $data): array
     {
-        /** @var array<mixed> $normalized */
-        $normalized = $this->normalizerFormatter->normalizeValue($data);
+        /** @var Record $data */
+        $normalized = $this->normalizerFormatter->format($data);
 
-        $fields = [];
+        $fields = array();
         foreach ($normalized as $key => $value) {
             $fields[] = $this->generateAttachmentField((string) $key, $value);
         }
@@ -341,14 +360,15 @@ class SlackRecord
     /**
      * Get a copy of record with fields excluded according to $this->excludeFields
      *
+     * @phpstan-param FormattedRecord $record
+     *
      * @return mixed[]
      */
-    private function removeExcludedFields(LogRecord $record): array
+    private function removeExcludedFields(array $record): array
     {
-        $recordData = $record->toArray();
         foreach ($this->excludeFields as $field) {
             $keys = explode('.', $field);
-            $node = &$recordData;
+            $node = &$record;
             $lastKey = end($keys);
             foreach ($keys as $key) {
                 if (!isset($node[$key])) {
@@ -362,6 +382,6 @@ class SlackRecord
             }
         }
 
-        return $recordData;
+        return $record;
     }
 }
index 321d8660faaf89e1f89a10711a3cfa81803a45a2..a648513e0e4fd1618bbc62505e5940a555588c6b 100644 (file)
 namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use Monolog\Handler\Slack\SlackRecord;
-use Monolog\LogRecord;
 
 /**
  * Sends notifications through Slack API
  *
  * @author Greg Kedzierski <greg@gregkedzierski.com>
  * @see    https://api.slack.com/
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class SlackHandler extends SocketHandler
 {
     /**
      * Slack API token
+     * @var string
      */
-    private string $token;
+    private $token;
 
     /**
      * Instance of the SlackRecord util class preparing data for Slack API.
+     * @var SlackRecord
      */
-    private SlackRecord $slackRecord;
+    private $slackRecord;
 
     /**
      * @param  string                    $token                  Slack API token
@@ -52,11 +55,11 @@ class SlackHandler extends SocketHandler
         ?string $username = null,
         bool $useAttachment = true,
         ?string $iconEmoji = null,
-        $level = Level::Critical,
+        $level = Logger::CRITICAL,
         bool $bubble = true,
         bool $useShortAttachment = false,
         bool $includeContextAndExtra = false,
-        array $excludeFields = [],
+        array $excludeFields = array(),
         bool $persistent = false,
         float $timeout = 0.0,
         float $writingTimeout = 10.0,
@@ -102,9 +105,9 @@ class SlackHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function generateDataStream(LogRecord $record): string
+    protected function generateDataStream(array $record): string
     {
         $content = $this->buildContent($record);
 
@@ -113,8 +116,10 @@ class SlackHandler extends SocketHandler
 
     /**
      * Builds the body of API call
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    private function buildContent(LogRecord $record): string
+    private function buildContent(array $record): string
     {
         $dataArray = $this->prepareContentData($record);
 
@@ -122,14 +127,15 @@ class SlackHandler extends SocketHandler
     }
 
     /**
+     * @phpstan-param FormattedRecord $record
      * @return string[]
      */
-    protected function prepareContentData(LogRecord $record): array
+    protected function prepareContentData(array $record): array
     {
         $dataArray = $this->slackRecord->getSlackData($record);
         $dataArray['token'] = $this->token;
 
-        if (isset($dataArray['attachments']) && is_array($dataArray['attachments']) && \count($dataArray['attachments']) > 0) {
+        if (!empty($dataArray['attachments'])) {
             $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']);
         }
 
@@ -151,9 +157,9 @@ class SlackHandler extends SocketHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         parent::write($record);
         $this->finalizeWrite();
index 14ed6b1fb60dfc76df25dcbc6e348f2cb0b3feb2..8ae3c78829c86afb61224ca2de50e26d22f82405 100644 (file)
 namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
 use Monolog\Handler\Slack\SlackRecord;
-use Monolog\LogRecord;
 
 /**
  * Sends notifications through Slack Webhooks
@@ -27,13 +26,15 @@ class SlackWebhookHandler extends AbstractProcessingHandler
 {
     /**
      * Slack Webhook token
+     * @var string
      */
-    private string $webhookUrl;
+    private $webhookUrl;
 
     /**
      * Instance of the SlackRecord util class preparing data for Slack API.
+     * @var SlackRecord
      */
-    private SlackRecord $slackRecord;
+    private $slackRecord;
 
     /**
      * @param string      $webhookUrl             Slack Webhook URL
@@ -53,9 +54,9 @@ class SlackWebhookHandler extends AbstractProcessingHandler
         ?string $iconEmoji = null,
         bool $useShortAttachment = false,
         bool $includeContextAndExtra = false,
-        $level = Level::Critical,
+        $level = Logger::CRITICAL,
         bool $bubble = true,
-        array $excludeFields = []
+        array $excludeFields = array()
     ) {
         if (!extension_loaded('curl')) {
             throw new MissingExtensionException('The curl extension is needed to use the SlackWebhookHandler');
@@ -87,21 +88,21 @@ class SlackWebhookHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         $postData = $this->slackRecord->getSlackData($record);
         $postString = Utils::jsonEncode($postData);
 
         $ch = curl_init();
-        $options = [
+        $options = array(
             CURLOPT_URL => $this->webhookUrl,
             CURLOPT_POST => true,
             CURLOPT_RETURNTRANSFER => true,
-            CURLOPT_HTTPHEADER => ['Content-type: application/json'],
+            CURLOPT_HTTPHEADER => array('Content-type: application/json'),
             CURLOPT_POSTFIELDS => $postString,
-        ];
+        );
         if (defined('CURLOPT_SAFE_UPLOAD')) {
             $options[CURLOPT_SAFE_UPLOAD] = true;
         }
index c5f70888476a14baf459f498048d7a063fdaadd0..21701afa25719503b1bce37c8fa8e590a8d13491 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Stores to any socket - uses fsockopen() or pfsockopen().
  *
  * @author Pablo de Leon Belloc <pablolb@gmail.com>
  * @see    http://php.net/manual/en/function.fsockopen.php
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class SocketHandler extends AbstractProcessingHandler
 {
-    private string $connectionString;
-    private float $connectionTimeout;
+    /** @var string */
+    private $connectionString;
+    /** @var float */
+    private $connectionTimeout;
     /** @var resource|null */
     private $resource;
-    private float $timeout;
-    private float $writingTimeout;
-    private int|null $lastSentBytes = null;
-    private int|null $chunkSize;
-    private bool $persistent;
-    private int|null $errno = null;
-    private string|null $errstr = null;
-    private float|null $lastWritingAt = null;
+    /** @var float */
+    private $timeout;
+    /** @var float */
+    private $writingTimeout;
+    /** @var ?int */
+    private $lastSentBytes = null;
+    /** @var ?int */
+    private $chunkSize;
+    /** @var bool */
+    private $persistent;
+    /** @var ?int */
+    private $errno = null;
+    /** @var ?string */
+    private $errstr = null;
+    /** @var ?float */
+    private $lastWritingAt = null;
 
     /**
      * @param string     $connectionString  Socket connection string
@@ -44,11 +56,11 @@ class SocketHandler extends AbstractProcessingHandler
      *                                      established
      * @param int|null   $chunkSize         Sets the chunk size. Only has effect during connection in the writing cycle
      *
-     * @throws \InvalidArgumentException If an invalid timeout value (less than 0) is passed.
+     * @throws \InvalidArgumentException    If an invalid timeout value (less than 0) is passed.
      */
     public function __construct(
         string $connectionString,
-        $level = Level::Debug,
+        $level = Logger::DEBUG,
         bool $bubble = true,
         bool $persistent = false,
         float $timeout = 0.0,
@@ -75,12 +87,12 @@ class SocketHandler extends AbstractProcessingHandler
     /**
      * Connect (if necessary) and write to the socket
      *
-     * @inheritDoc
+     * {@inheritDoc}
      *
      * @throws \UnexpectedValueException
      * @throws \RuntimeException
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         $this->connectIfNotConnected();
         $data = $this->generateDataStream($record);
@@ -201,6 +213,8 @@ class SocketHandler extends AbstractProcessingHandler
 
     /**
      * Get current local writing timeout
+     *
+     * @return float
      */
     public function getWritingTimeout(): float
     {
@@ -250,8 +264,10 @@ class SocketHandler extends AbstractProcessingHandler
      * Wrapper to allow mocking
      *
      * @see http://php.net/manual/en/function.stream-set-timeout.php
+     *
+     * @return bool
      */
-    protected function streamSetTimeout(): bool
+    protected function streamSetTimeout()
     {
         $seconds = floor($this->timeout);
         $microseconds = round(($this->timeout - $seconds) * 1e6);
@@ -268,9 +284,9 @@ class SocketHandler extends AbstractProcessingHandler
      *
      * @see http://php.net/manual/en/function.stream-set-chunk-size.php
      *
-     * @return int|false
+     * @return int|bool
      */
-    protected function streamSetChunkSize(): int|bool
+    protected function streamSetChunkSize()
     {
         if (!is_resource($this->resource)) {
             throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource');
@@ -286,9 +302,9 @@ class SocketHandler extends AbstractProcessingHandler
     /**
      * Wrapper to allow mocking
      *
-     * @return int|false
+     * @return int|bool
      */
-    protected function fwrite(string $data): int|bool
+    protected function fwrite(string $data)
     {
         if (!is_resource($this->resource)) {
             throw new \LogicException('fwrite called but $this->resource is not a resource');
@@ -302,7 +318,7 @@ class SocketHandler extends AbstractProcessingHandler
      *
      * @return mixed[]|bool
      */
-    protected function streamGetMetadata(): array|bool
+    protected function streamGetMetadata()
     {
         if (!is_resource($this->resource)) {
             throw new \LogicException('streamGetMetadata called but $this->resource is not a resource');
@@ -326,9 +342,12 @@ class SocketHandler extends AbstractProcessingHandler
         $this->connect();
     }
 
-    protected function generateDataStream(LogRecord $record): string
+    /**
+     * @phpstan-param FormattedRecord $record
+     */
+    protected function generateDataStream(array $record): string
     {
-        return (string) $record->formatted;
+        return (string) $record['formatted'];
     }
 
     /**
@@ -368,7 +387,7 @@ class SocketHandler extends AbstractProcessingHandler
 
     private function setStreamChunkSize(): void
     {
-        if (null !== $this->chunkSize && false === $this->streamSetChunkSize()) {
+        if ($this->chunkSize && !$this->streamSetChunkSize()) {
             throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
         }
     }
@@ -389,7 +408,7 @@ class SocketHandler extends AbstractProcessingHandler
             }
             $sent += $chunk;
             $socketInfo = $this->streamGetMetadata();
-            if (is_array($socketInfo) && (bool) $socketInfo['timed_out']) {
+            if (is_array($socketInfo) && $socketInfo['timed_out']) {
                 throw new \RuntimeException("Write timed-out");
             }
 
@@ -418,7 +437,7 @@ class SocketHandler extends AbstractProcessingHandler
             usleep(100);
         }
 
-        if ((microtime(true) - (float) $this->lastWritingAt) >= $this->writingTimeout) {
+        if ((microtime(true) - $this->lastWritingAt) >= $this->writingTimeout) {
             $this->closeSocket();
 
             return true;
index b4512a601b0cd93994d639fe214dfba594496603..dcf282b454f6de418f0cd7543d104617267b255f 100644 (file)
@@ -12,9 +12,8 @@
 namespace Monolog\Handler;
 
 use Aws\Sqs\SqsClient;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Writes to any sqs queue.
@@ -28,10 +27,12 @@ class SqsHandler extends AbstractProcessingHandler
     /** 100 KB in bytes - head message size for new error log */
     protected const HEAD_MESSAGE_SIZE = 102400;
 
-    private SqsClient $client;
-    private string $queueUrl;
+    /** @var SqsClient */
+    private $client;
+    /** @var string */
+    private $queueUrl;
 
-    public function __construct(SqsClient $sqsClient, string $queueUrl, int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Logger::DEBUG, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
@@ -40,15 +41,15 @@ class SqsHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        if (!isset($record->formatted) || 'string' !== gettype($record->formatted)) {
+        if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) {
             throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string' . Utils::getRecordMessageForException($record));
         }
 
-        $messageBody = $record->formatted;
+        $messageBody = $record['formatted'];
         if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) {
             $messageBody = Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE);
         }
index 027a7217d5033fc9168348c00409e6b1a697363b..651835122ec253112090b6a00beeb4816329f393 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Stores to any stream resource
@@ -21,21 +20,29 @@ use Monolog\LogRecord;
  * Can be used to store into php://stderr, remote and local files, etc.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class StreamHandler extends AbstractProcessingHandler
 {
+    /** @const int */
     protected const MAX_CHUNK_SIZE = 2147483647;
-    /** 10MB */
+    /** @const int 10MB */
     protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024;
-    protected int $streamChunkSize;
+    /** @var int */
+    protected $streamChunkSize;
     /** @var resource|null */
     protected $stream;
-    protected string|null $url = null;
-    private string|null $errorMessage = null;
-    protected int|null $filePermission;
-    protected bool $useLocking;
+    /** @var ?string */
+    protected $url = null;
+    /** @var ?string */
+    private $errorMessage = null;
+    /** @var ?int */
+    protected $filePermission;
+    /** @var bool */
+    protected $useLocking;
     /** @var true|null */
-    private bool|null $dirCreated = null;
+    private $dirCreated = null;
 
     /**
      * @param resource|string $stream         If a missing path can't be created, an UnexpectedValueException will be thrown on first write
@@ -44,7 +51,7 @@ class StreamHandler extends AbstractProcessingHandler
      *
      * @throws \InvalidArgumentException If stream is not a resource or string
      */
-    public function __construct($stream, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false)
+    public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false)
     {
         parent::__construct($level, $bubble);
 
@@ -76,11 +83,11 @@ class StreamHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
-        if (null !== $this->url && is_resource($this->stream)) {
+        if ($this->url && is_resource($this->stream)) {
             fclose($this->stream);
         }
         $this->stream = null;
@@ -99,21 +106,26 @@ class StreamHandler extends AbstractProcessingHandler
 
     /**
      * Return the stream URL if it was configured with a URL and not an active resource
+     *
+     * @return string|null
      */
     public function getUrl(): ?string
     {
         return $this->url;
     }
 
+    /**
+     * @return int
+     */
     public function getStreamChunkSize(): int
     {
         return $this->streamChunkSize;
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!is_resource($this->stream)) {
             $url = $this->url;
@@ -138,6 +150,10 @@ class StreamHandler extends AbstractProcessingHandler
         }
 
         $stream = $this->stream;
+        if (!is_resource($stream)) {
+            throw new \LogicException('No stream was opened yet' . Utils::getRecordMessageForException($record));
+        }
+
         if ($this->useLocking) {
             // ignoring errors here, there's not much we can do about them
             flock($stream, LOCK_EX);
@@ -153,10 +169,13 @@ class StreamHandler extends AbstractProcessingHandler
     /**
      * Write to stream
      * @param resource $stream
+     * @param array    $record
+     *
+     * @phpstan-param FormattedRecord $record
      */
-    protected function streamWrite($stream, LogRecord $record): void
+    protected function streamWrite($stream, array $record): void
     {
-        fwrite($stream, (string) $record->formatted);
+        fwrite($stream, (string) $record['formatted']);
     }
 
     private function customErrorHandler(int $code, string $msg): bool
@@ -183,7 +202,7 @@ class StreamHandler extends AbstractProcessingHandler
     private function createDir(string $url): void
     {
         // Do not try to create dir if it has already been tried.
-        if (true === $this->dirCreated) {
+        if ($this->dirCreated) {
             return;
         }
 
index 842b6577fa489f25c9a6bab46ce239d059e03b08..130e6f1f36d3820c7cba660d8a6d55f78d2e10e3 100644 (file)
 
 namespace Monolog\Handler;
 
-use Closure;
-use Monolog\Level;
 use Monolog\Logger;
-use Monolog\LogRecord;
 use Monolog\Utils;
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\LineFormatter;
@@ -26,20 +23,23 @@ use Symfony\Component\Mime\Email;
  * SymfonyMailerHandler uses Symfony's Mailer component to send the emails
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class SymfonyMailerHandler extends MailHandler
 {
-    protected MailerInterface|TransportInterface $mailer;
-    /** @var Email|Closure(string, LogRecord[]): Email */
-    private Email|Closure $emailTemplate;
+    /** @var MailerInterface|TransportInterface */
+    protected $mailer;
+    /** @var Email|callable(string, Record[]): Email */
+    private $emailTemplate;
 
     /**
-     * @phpstan-param Email|Closure(string, LogRecord[]): Email $email
+     * @psalm-param Email|callable(string, Record[]): Email $email
      *
      * @param MailerInterface|TransportInterface $mailer The mailer to use
-     * @param Closure|Email                      $email  An email template, the subject/body will be replaced
+     * @param callable|Email                     $email  An email template, the subject/body will be replaced
      */
-    public function __construct($mailer, Email|Closure $email, int|string|Level $level = Level::Error, bool $bubble = true)
+    public function __construct($mailer, $email, $level = Logger::ERROR, bool $bubble = true)
     {
         parent::__construct($level, $bubble);
 
@@ -68,8 +68,10 @@ class SymfonyMailerHandler extends MailHandler
     /**
      * Creates instance of Email to be sent
      *
-     * @param  string      $content formatted email body to be sent
-     * @param  LogRecord[] $records Log records that formed the content
+     * @param  string        $content formatted email body to be sent
+     * @param  array         $records Log records that formed the content
+     *
+     * @phpstan-param Record[] $records
      */
     protected function buildMessage(string $content, array $records): Email
     {
@@ -82,10 +84,10 @@ class SymfonyMailerHandler extends MailHandler
 
         if (!$message instanceof Email) {
             $record = reset($records);
-            throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record instanceof LogRecord ? Utils::getRecordMessageForException($record) : ''));
+            throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : ''));
         }
 
-        if (\count($records) > 0) {
+        if ($records) {
             $subjectFormatter = $this->getSubjectFormatter($message->getSubject());
             $message->subject($subjectFormatter->format($this->getHighestRecord($records)));
         }
index 0816a01196c2875af9ed812a11384d4f0b97739b..1d543b7ecaaaa0703a7622f6fce96373f427726a 100644 (file)
@@ -11,9 +11,8 @@
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Logs to syslog service.
@@ -30,14 +29,17 @@ use Monolog\LogRecord;
  */
 class SyslogHandler extends AbstractSyslogHandler
 {
-    protected string $ident;
-    protected int $logopts;
+    /** @var string */
+    protected $ident;
+    /** @var int */
+    protected $logopts;
 
     /**
+     * @param string     $ident
      * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
      * @param int        $logopts  Option flags for the openlog() call, defaults to LOG_PID
      */
-    public function __construct(string $ident, string|int $facility = LOG_USER, int|string|Level $level = Level::Debug, bool $bubble = true, int $logopts = LOG_PID)
+    public function __construct(string $ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID)
     {
         parent::__construct($facility, $level, $bubble);
 
@@ -46,7 +48,7 @@ class SyslogHandler extends AbstractSyslogHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function close(): void
     {
@@ -54,13 +56,13 @@ class SyslogHandler extends AbstractSyslogHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         if (!openlog($this->ident, $this->logopts, $this->facility)) {
             throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"' . Utils::getRecordMessageForException($record));
         }
-        syslog($this->toSyslogPriority($record->level), (string) $record->formatted);
+        syslog($this->logLevels[$record['level']], (string) $record['formatted']);
     }
 }
index 6a4833450be133c0ad58fedddc2309be6cd8fd78..dbd8ef69d913947ed939a08a7935fd174d900def 100644 (file)
@@ -18,9 +18,12 @@ class UdpSocket
 {
     protected const DATAGRAM_MAX_LENGTH = 65023;
 
-    protected string $ip;
-    protected int $port;
-    protected ?Socket $socket = null;
+    /** @var string */
+    protected $ip;
+    /** @var int */
+    protected $port;
+    /** @var resource|Socket|null */
+    protected $socket = null;
 
     public function __construct(string $ip, int $port = 514)
     {
@@ -28,20 +31,28 @@ class UdpSocket
         $this->port = $port;
     }
 
-    public function write(string $line, string $header = ""): void
+    /**
+     * @param  string $line
+     * @param  string $header
+     * @return void
+     */
+    public function write($line, $header = "")
     {
         $this->send($this->assembleMessage($line, $header));
     }
 
     public function close(): void
     {
-        if ($this->socket instanceof Socket) {
+        if (is_resource($this->socket) || $this->socket instanceof Socket) {
             socket_close($this->socket);
             $this->socket = null;
         }
     }
 
-    protected function getSocket(): Socket
+    /**
+     * @return resource|Socket
+     */
+    protected function getSocket()
     {
         if (null !== $this->socket) {
             return $this->socket;
@@ -55,12 +66,12 @@ class UdpSocket
             $protocol = IPPROTO_IP;
         }
 
-        $socket = socket_create($domain, SOCK_DGRAM, $protocol);
-        if ($socket instanceof Socket) {
-            return $this->socket = $socket;
+        $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null;
+        if (null === $this->socket) {
+            throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' could not be opened via socket_create');
         }
 
-        throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' could not be opened via socket_create');
+        return $this->socket;
     }
 
     protected function send(string $chunk): void
index abb8be9b2317fe23bd3dd292c9a7f471673ec97e..deaa19f80ccdb3f90b330511a9ba6b10e19311ff 100644 (file)
@@ -12,9 +12,8 @@
 namespace Monolog\Handler;
 
 use DateTimeInterface;
+use Monolog\Logger;
 use Monolog\Handler\SyslogUdp\UdpSocket;
-use Monolog\Level;
-use Monolog\LogRecord;
 use Monolog\Utils;
 
 /**
@@ -30,29 +29,31 @@ class SyslogUdpHandler extends AbstractSyslogHandler
     const RFC5424e = 2;
 
     /** @var array<self::RFC*, string> */
-    private array $dateFormats = [
+    private $dateFormats = array(
         self::RFC3164 => 'M d H:i:s',
         self::RFC5424 => \DateTime::RFC3339,
         self::RFC5424e => \DateTime::RFC3339_EXTENDED,
-    ];
+    );
 
-    protected UdpSocket $socket;
-    protected string $ident;
+    /** @var UdpSocket */
+    protected $socket;
+    /** @var string */
+    protected $ident;
     /** @var self::RFC* */
-    protected int $rfc;
+    protected $rfc;
 
     /**
-     * @param  string                    $host     Either IP/hostname or a path to a unix socket (port must be 0 then)
-     * @param  int                       $port     Port number, or 0 if $host is a unix socket
-     * @param  string|int                $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
-     * @param  bool                      $bubble   Whether the messages that are handled can bubble up the stack or not
-     * @param  string                    $ident    Program name or tag for each log message.
-     * @param  int                       $rfc      RFC to format the message for.
+     * @param string     $host     Either IP/hostname or a path to a unix socket (port must be 0 then)
+     * @param int        $port     Port number, or 0 if $host is a unix socket
+     * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
+     * @param bool       $bubble   Whether the messages that are handled can bubble up the stack or not
+     * @param string     $ident    Program name or tag for each log message.
+     * @param int        $rfc      RFC to format the message for.
      * @throws MissingExtensionException
      *
      * @phpstan-param self::RFC* $rfc
      */
-    public function __construct(string $host, int $port = 514, string|int $facility = LOG_USER, int|string|Level $level = Level::Debug, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424)
+    public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424)
     {
         if (!extension_loaded('sockets')) {
             throw new MissingExtensionException('The sockets extension is required to use the SyslogUdpHandler');
@@ -66,11 +67,11 @@ class SyslogUdpHandler extends AbstractSyslogHandler
         $this->socket = new UdpSocket($host, $port);
     }
 
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $lines = $this->splitMessageIntoLines($record->formatted);
+        $lines = $this->splitMessageIntoLines($record['formatted']);
 
-        $header = $this->makeCommonSyslogHeader($this->toSyslogPriority($record->level), $record->datetime);
+        $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']], $record['datetime']);
 
         foreach ($lines as $line) {
             $this->socket->write($line, $header);
@@ -95,7 +96,6 @@ class SyslogUdpHandler extends AbstractSyslogHandler
         $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY);
         if (false === $lines) {
             $pcreErrorCode = preg_last_error();
-
             throw new \RuntimeException('Could not preg_split: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
         }
 
@@ -109,13 +109,11 @@ class SyslogUdpHandler extends AbstractSyslogHandler
     {
         $priority = $severity + $this->facility;
 
-        $pid = getmypid();
-        if (false === $pid) {
+        if (!$pid = getmypid()) {
             $pid = '-';
         }
 
-        $hostname = gethostname();
-        if (false === $hostname) {
+        if (!$hostname = gethostname()) {
             $hostname = '-';
         }
 
index 2e1be9f6b060a9cc840bf29fe602b37d69ed3559..8912eba510aaa391b06e262ea5e3ac91f02dabed 100644 (file)
@@ -12,9 +12,8 @@
 namespace Monolog\Handler;
 
 use RuntimeException;
-use Monolog\Level;
+use Monolog\Logger;
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Handler send logs to Telegram using Telegram Bot API.
@@ -29,6 +28,8 @@ use Monolog\LogRecord;
  * @link https://core.telegram.org/bots/api
  *
  * @author Mazur Alexandr <alexandrmazur96@gmail.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class TelegramBotHandler extends AbstractProcessingHandler
 {
@@ -51,61 +52,69 @@ class TelegramBotHandler extends AbstractProcessingHandler
     /**
      * Telegram bot access token provided by BotFather.
      * Create telegram bot with https://telegram.me/BotFather and use access token from it.
+     * @var string
      */
-    private string $apiKey;
+    private $apiKey;
 
     /**
      * Telegram channel name.
      * Since to start with '@' symbol as prefix.
+     * @var string
      */
-    private string $channel;
+    private $channel;
 
     /**
      * The kind of formatting that is used for the message.
      * See available options at https://core.telegram.org/bots/api#formatting-options
      * or in AVAILABLE_PARSE_MODES
+     * @var ?string
      */
-    private string|null $parseMode;
+    private $parseMode;
 
     /**
      * Disables link previews for links in the message.
+     * @var ?bool
      */
-    private bool|null $disableWebPagePreview;
+    private $disableWebPagePreview;
 
     /**
      * Sends the message silently. Users will receive a notification with no sound.
+     * @var ?bool
      */
-    private bool|null $disableNotification;
+    private $disableNotification;
 
     /**
      * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages.
      * False - truncates a message that is too long.
+     * @var bool
      */
-    private bool $splitLongMessages;
+    private $splitLongMessages;
 
     /**
      * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests).
+     * @var bool
      */
-    private bool $delayBetweenMessages;
+    private $delayBetweenMessages;
 
     /**
-     * @param  string                    $apiKey               Telegram bot access token provided by BotFather
-     * @param  string                    $channel              Telegram channel name
-     * @param  bool                      $splitLongMessages    Split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages
-     * @param  bool                      $delayBetweenMessages Adds delay between sending a split message according to Telegram API
+     * @param string $apiKey Telegram bot access token provided by BotFather
+     * @param string $channel Telegram channel name
+     * @param bool $splitLongMessages Split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages
+     * @param bool $delayBetweenMessages Adds delay between sending a split message according to Telegram API
      * @throws MissingExtensionException
      */
     public function __construct(
         string $apiKey,
         string $channel,
-        $level = Level::Debug,
+               $level = Logger::DEBUG,
         bool   $bubble = true,
         string $parseMode = null,
         bool   $disableWebPagePreview = null,
         bool   $disableNotification = null,
         bool   $splitLongMessages = false,
         bool   $delayBetweenMessages = false
-    ) {
+    )
+    {
         if (!extension_loaded('curl')) {
             throw new MissingExtensionException('The curl extension is needed to use the TelegramBotHandler');
         }
@@ -123,7 +132,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
 
     public function setParseMode(string $parseMode = null): self
     {
-        if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES, true)) {
+        if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES)) {
             throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . implode(', ', self::AVAILABLE_PARSE_MODES) . '.');
         }
 
@@ -149,6 +158,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
     /**
      * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages.
      * False - truncates a message that is too long.
+     * @param bool $splitLongMessages
      * @return $this
      */
     public function splitLongMessages(bool $splitLongMessages = false): self
@@ -160,6 +170,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
 
     /**
      * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests).
+     * @param bool $delayBetweenMessages
      * @return $this
      */
     public function delayBetweenMessages(bool $delayBetweenMessages = false): self
@@ -170,10 +181,11 @@ class TelegramBotHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
+        /** @var Record[] $messages */
         $messages = [];
 
         foreach ($records as $record) {
@@ -181,28 +193,30 @@ class TelegramBotHandler extends AbstractProcessingHandler
                 continue;
             }
 
-            if (\count($this->processors) > 0) {
+            if ($this->processors) {
+                /** @var Record $record */
                 $record = $this->processRecord($record);
             }
 
             $messages[] = $record;
         }
 
-        if (\count($messages) > 0) {
-            $this->send((string) $this->getFormatter()->formatBatch($messages));
+        if (!empty($messages)) {
+            $this->send((string)$this->getFormatter()->formatBatch($messages));
         }
     }
 
     /**
      * @inheritDoc
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->send($record->formatted);
+        $this->send($record['formatted']);
     }
 
     /**
      * Send request to @link https://api.telegram.org/bot on SendMessage action.
+     * @param string $message
      */
     protected function send(string $message): void
     {
@@ -245,6 +259,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
 
     /**
      * Handle a message that is too long: truncates or splits into several
+     * @param string $message
      * @return string[]
      */
     private function handleMessageLength(string $message): array
index 1884f83fcccaeec349476eb248c9c821a3133b99..0986da2708c6f0261328dde1e612718a3a43ad9d 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Used for testing purposes.
@@ -67,67 +65,85 @@ use Monolog\LogRecord;
  * @method bool hasNoticeThatPasses($message)
  * @method bool hasInfoThatPasses($message)
  * @method bool hasDebugThatPasses($message)
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class TestHandler extends AbstractProcessingHandler
 {
-    /** @var LogRecord[] */
-    protected array $records = [];
-    /** @phpstan-var array<value-of<Level::VALUES>, LogRecord[]> */
-    protected array $recordsByLevel = [];
-    private bool $skipReset = false;
+    /** @var Record[] */
+    protected $records = [];
+    /** @var array<Level, Record[]> */
+    protected $recordsByLevel = [];
+    /** @var bool */
+    private $skipReset = false;
 
     /**
-     * @return array<LogRecord>
+     * @return array
+     *
+     * @phpstan-return Record[]
      */
-    public function getRecords(): array
+    public function getRecords()
     {
         return $this->records;
     }
 
-    public function clear(): void
+    /**
+     * @return void
+     */
+    public function clear()
     {
         $this->records = [];
         $this->recordsByLevel = [];
     }
 
-    public function reset(): void
+    /**
+     * @return void
+     */
+    public function reset()
     {
         if (!$this->skipReset) {
             $this->clear();
         }
     }
 
-    public function setSkipReset(bool $skipReset): void
+    /**
+     * @return void
+     */
+    public function setSkipReset(bool $skipReset)
     {
         $this->skipReset = $skipReset;
     }
 
     /**
-     * @param int|string|Level|LogLevel::* $level Logging level value or name
+     * @param string|int $level Logging level value or name
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function hasRecords(int|string|Level $level): bool
+    public function hasRecords($level): bool
     {
-        return isset($this->recordsByLevel[Logger::toMonologLevel($level)->value]);
+        return isset($this->recordsByLevel[Logger::toMonologLevel($level)]);
     }
 
     /**
-     * @param string|array $recordAssertions Either a message string or an array containing message and optionally context keys that will be checked against all records
+     * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records
+     * @param string|int   $level  Logging level value or name
      *
-     * @phpstan-param array{message: string, context?: mixed[]}|string $recordAssertions
+     * @phpstan-param array{message: string, context?: mixed[]}|string $record
+     * @phpstan-param Level|LevelName|LogLevel::*                      $level
      */
-    public function hasRecord(string|array $recordAssertions, Level $level): bool
+    public function hasRecord($record, $level): bool
     {
-        if (is_string($recordAssertions)) {
-            $recordAssertions = ['message' => $recordAssertions];
+        if (is_string($record)) {
+            $record = array('message' => $record);
         }
 
-        return $this->hasRecordThatPasses(function (LogRecord $rec) use ($recordAssertions) {
-            if ($rec->message !== $recordAssertions['message']) {
+        return $this->hasRecordThatPasses(function ($rec) use ($record) {
+            if ($rec['message'] !== $record['message']) {
                 return false;
             }
-            if (isset($recordAssertions['context']) && $rec->context !== $recordAssertions['context']) {
+            if (isset($record['context']) && $rec['context'] !== $record['context']) {
                 return false;
             }
 
@@ -135,29 +151,47 @@ class TestHandler extends AbstractProcessingHandler
         }, $level);
     }
 
-    public function hasRecordThatContains(string $message, Level $level): bool
+    /**
+     * @param string|int $level Logging level value or name
+     *
+     * @phpstan-param Level|LevelName|LogLevel::* $level
+     */
+    public function hasRecordThatContains(string $message, $level): bool
     {
-        return $this->hasRecordThatPasses(fn (LogRecord $rec) => str_contains($rec->message, $message), $level);
+        return $this->hasRecordThatPasses(function ($rec) use ($message) {
+            return strpos($rec['message'], $message) !== false;
+        }, $level);
     }
 
-    public function hasRecordThatMatches(string $regex, Level $level): bool
+    /**
+     * @param string|int $level Logging level value or name
+     *
+     * @phpstan-param Level|LevelName|LogLevel::* $level
+     */
+    public function hasRecordThatMatches(string $regex, $level): bool
     {
-        return $this->hasRecordThatPasses(fn (LogRecord $rec) => preg_match($regex, $rec->message) > 0, $level);
+        return $this->hasRecordThatPasses(function (array $rec) use ($regex): bool {
+            return preg_match($regex, $rec['message']) > 0;
+        }, $level);
     }
 
     /**
-     * @phpstan-param callable(LogRecord, int): mixed $predicate
+     * @param  string|int $level Logging level value or name
+     * @return bool
+     *
+     * @psalm-param callable(Record, int): mixed $predicate
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function hasRecordThatPasses(callable $predicate, Level $level): bool
+    public function hasRecordThatPasses(callable $predicate, $level)
     {
         $level = Logger::toMonologLevel($level);
 
-        if (!isset($this->recordsByLevel[$level->value])) {
+        if (!isset($this->recordsByLevel[$level])) {
             return false;
         }
 
-        foreach ($this->recordsByLevel[$level->value] as $i => $rec) {
-            if ((bool) $predicate($rec, $i)) {
+        foreach ($this->recordsByLevel[$level] as $i => $rec) {
+            if ($predicate($rec, $i)) {
                 return true;
             }
         }
@@ -166,22 +200,24 @@ class TestHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
-        $this->recordsByLevel[$record->level->value][] = $record;
+        $this->recordsByLevel[$record['level']][] = $record;
         $this->records[] = $record;
     }
 
     /**
-     * @param mixed[] $args
+     * @param  string  $method
+     * @param  mixed[] $args
+     * @return bool
      */
-    public function __call(string $method, array $args): bool
+    public function __call($method, $args)
     {
         if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
             $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
-            $level = constant(Level::class.'::' . $matches[2]);
+            $level = constant('Monolog\Logger::' . strtoupper($matches[2]));
             $callback = [$this, $genericMethod];
             if (is_callable($callback)) {
                 $args[] = $level;
index 9c12c3d5698e6a816e09327c38200e4b84dbba83..c81835288ed57a631078a7b2f3992de7054be67b 100644 (file)
@@ -15,6 +15,7 @@ trait WebRequestRecognizerTrait
 {
     /**
      * Checks if PHP's serving a web request
+     * @return bool
      */
     protected function isWebRequest(): bool
     {
index 2dbc5fe8de59188d2c756eae653b90f64cab9563..b6d3d3b197e1750d518ea9daaad987d38aabd225 100644 (file)
 
 namespace Monolog\Handler;
 
-use Monolog\LogRecord;
-use Throwable;
-
 /**
  * Forwards records to multiple handlers suppressing failures of each handler
  * and continuing through to give every handler a chance to succeed.
  *
  * @author Craig D'Amelio <craig@damelio.ca>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 class WhatFailureGroupHandler extends GroupHandler
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function handle(LogRecord $record): bool
+    public function handle(array $record): bool
     {
-        if (\count($this->processors) > 0) {
+        if ($this->processors) {
+            /** @var Record $record */
             $record = $this->processRecord($record);
         }
 
         foreach ($this->handlers as $handler) {
             try {
                 $handler->handle($record);
-            } catch (Throwable) {
+            } catch (\Throwable $e) {
                 // What failure?
             }
         }
@@ -43,22 +43,37 @@ class WhatFailureGroupHandler extends GroupHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function handleBatch(array $records): void
     {
-        if (\count($this->processors) > 0) {
-            $processed = [];
+        if ($this->processors) {
+            $processed = array();
             foreach ($records as $record) {
                 $processed[] = $this->processRecord($record);
             }
+            /** @var Record[] $records */
             $records = $processed;
         }
 
         foreach ($this->handlers as $handler) {
             try {
                 $handler->handleBatch($records);
-            } catch (Throwable) {
+            } catch (\Throwable $e) {
+                // What failure?
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function close(): void
+    {
+        foreach ($this->handlers as $handler) {
+            try {
+                $handler->close();
+            } catch (\Throwable $e) {
                 // What failure?
             }
         }
index 1e71194bc08630c3fc92bfd708499f4bc1923ee7..ddd46d8c5c9135a2aeef348a6779fd1c59e11409 100644 (file)
@@ -13,67 +13,70 @@ namespace Monolog\Handler;
 
 use Monolog\Formatter\FormatterInterface;
 use Monolog\Formatter\NormalizerFormatter;
-use Monolog\Level;
-use Monolog\LogRecord;
+use Monolog\Logger;
 
 /**
  * Handler sending logs to Zend Monitor
  *
  * @author  Christian Bergau <cbergau86@gmail.com>
  * @author  Jason Davis <happydude@jasondavis.net>
+ *
+ * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
  */
 class ZendMonitorHandler extends AbstractProcessingHandler
 {
+    /**
+     * Monolog level / ZendMonitor Custom Event priority map
+     *
+     * @var array<int, int>
+     */
+    protected $levelMap = [];
+
     /**
      * @throws MissingExtensionException
      */
-    public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true)
+    public function __construct($level = Logger::DEBUG, bool $bubble = true)
     {
         if (!function_exists('zend_monitor_custom_event')) {
             throw new MissingExtensionException(
                 'You must have Zend Server installed with Zend Monitor enabled in order to use this handler'
             );
         }
-
+        //zend monitor constants are not defined if zend monitor is not enabled.
+        $this->levelMap = [
+            Logger::DEBUG     => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::INFO      => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::NOTICE    => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+            Logger::WARNING   => \ZEND_MONITOR_EVENT_SEVERITY_WARNING,
+            Logger::ERROR     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::CRITICAL  => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::ALERT     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+            Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+        ];
         parent::__construct($level, $bubble);
     }
 
     /**
-     * Translates Monolog log levels to ZendMonitor levels.
+     * {@inheritDoc}
      */
-    protected function toZendMonitorLevel(Level $level): int
-    {
-        return match ($level) {
-            Level::Debug     => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
-            Level::Info      => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
-            Level::Notice    => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
-            Level::Warning   => \ZEND_MONITOR_EVENT_SEVERITY_WARNING,
-            Level::Error     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
-            Level::Critical  => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
-            Level::Alert     => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
-            Level::Emergency => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
-        };
-    }
-
-    /**
-     * @inheritDoc
-     */
-    protected function write(LogRecord $record): void
+    protected function write(array $record): void
     {
         $this->writeZendMonitorCustomEvent(
-            $record->level->getName(),
-            $record->message,
-            $record->formatted,
-            $this->toZendMonitorLevel($record->level)
+            Logger::getLevelName($record['level']),
+            $record['message'],
+            $record['formatted'],
+            $this->levelMap[$record['level']]
         );
     }
 
     /**
      * Write to Zend Monitor Events
-     * @param string       $type      Text displayed in "Class Name (custom)" field
-     * @param string       $message   Text displayed in "Error String"
-     * @param array<mixed> $formatted Displayed in Custom Variables tab
-     * @param int          $severity  Set the event severity level (-1,0,1)
+     * @param string $type      Text displayed in "Class Name (custom)" field
+     * @param string $message   Text displayed in "Error String"
+     * @param array  $formatted Displayed in Custom Variables tab
+     * @param int    $severity  Set the event severity level (-1,0,1)
+     *
+     * @phpstan-param FormattedRecord $formatted
      */
     protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void
     {
@@ -81,10 +84,18 @@ class ZendMonitorHandler extends AbstractProcessingHandler
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
     public function getDefaultFormatter(): FormatterInterface
     {
         return new NormalizerFormatter();
     }
+
+    /**
+     * @return array<int, int>
+     */
+    public function getLevelMap(): array
+    {
+        return $this->levelMap;
+    }
 }
diff --git a/monolog/vendor/monolog/monolog/src/Monolog/Level.php b/monolog/vendor/monolog/monolog/src/Monolog/Level.php
deleted file mode 100644 (file)
index ab04cf4..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php declare(strict_types=1);
-
-/*
- * This file is part of the Monolog package.
- *
- * (c) Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Monolog;
-
-use Psr\Log\LogLevel;
-
-/**
- * Represents the log levels
- *
- * Monolog supports the logging levels described by RFC 5424 {@see https://datatracker.ietf.org/doc/html/rfc5424}
- * but due to BC the severity values used internally are not 0-7.
- *
- * To get the level name out of a Level there are three options:
- *
- * - Use ->getName() to get the standard Monolog name which is full uppercased (e.g. "DEBUG")
- * - Use ->toPsrLogLevel() to get the standard PSR-3 name which is full lowercased (e.g. "debug")
- * - Use ->toRFC5424Level() to get the standard RFC 5424 value (e.g. 7 for debug, 0 for emergency)
- * - Use ->name to get the enum case's name which is capitalized (e.g. "Debug")
- *
- * To get the value for filtering, if the includes/isLowerThan/isHigherThan methods are
- * not enough, you can use ->value to get the enum case's integer value.
- */
-enum Level: int
-{
-    /**
-     * Detailed debug information
-     */
-    case Debug = 100;
-
-    /**
-     * Interesting events
-     *
-     * Examples: User logs in, SQL logs.
-     */
-    case Info = 200;
-
-    /**
-     * Uncommon events
-     */
-    case Notice = 250;
-
-    /**
-     * Exceptional occurrences that are not errors
-     *
-     * Examples: Use of deprecated APIs, poor use of an API,
-     * undesirable things that are not necessarily wrong.
-     */
-    case Warning = 300;
-
-    /**
-     * Runtime errors
-     */
-    case Error = 400;
-
-    /**
-     * Critical conditions
-     *
-     * Example: Application component unavailable, unexpected exception.
-     */
-    case Critical = 500;
-
-    /**
-     * Action must be taken immediately
-     *
-     * Example: Entire website down, database unavailable, etc.
-     * This should trigger the SMS alerts and wake you up.
-     */
-    case Alert = 550;
-
-    /**
-     * Urgent alert.
-     */
-    case Emergency = 600;
-
-    /**
-     * @param value-of<self::NAMES>|LogLevel::*|'Debug'|'Info'|'Notice'|'Warning'|'Error'|'Critical'|'Alert'|'Emergency' $name
-     * @return static
-     */
-    public static function fromName(string $name): self
-    {
-        return match ($name) {
-            'debug', 'Debug', 'DEBUG' => self::Debug,
-            'info', 'Info', 'INFO' => self::Info,
-            'notice', 'Notice', 'NOTICE' => self::Notice,
-            'warning', 'Warning', 'WARNING' => self::Warning,
-            'error', 'Error', 'ERROR' => self::Error,
-            'critical', 'Critical', 'CRITICAL' => self::Critical,
-            'alert', 'Alert', 'ALERT' => self::Alert,
-            'emergency', 'Emergency', 'EMERGENCY' => self::Emergency,
-        };
-    }
-
-    /**
-     * @param value-of<self::VALUES> $value
-     * @return static
-     */
-    public static function fromValue(int $value): self
-    {
-        return self::from($value);
-    }
-
-    /**
-     * Returns true if the passed $level is higher or equal to $this
-     */
-    public function includes(Level $level): bool
-    {
-        return $this->value <= $level->value;
-    }
-
-    public function isHigherThan(Level $level): bool
-    {
-        return $this->value > $level->value;
-    }
-
-    public function isLowerThan(Level $level): bool
-    {
-        return $this->value < $level->value;
-    }
-
-    /**
-     * Returns the monolog standardized all-capitals name of the level
-     *
-     * Use this instead of $level->name which returns the enum case name (e.g. Debug vs DEBUG if you use getName())
-     *
-     * @return value-of<self::NAMES>
-     */
-    public function getName(): string
-    {
-        return match ($this) {
-            self::Debug => 'DEBUG',
-            self::Info => 'INFO',
-            self::Notice => 'NOTICE',
-            self::Warning => 'WARNING',
-            self::Error => 'ERROR',
-            self::Critical => 'CRITICAL',
-            self::Alert => 'ALERT',
-            self::Emergency => 'EMERGENCY',
-        };
-    }
-
-    /**
-     * Returns the PSR-3 level matching this instance
-     *
-     * @phpstan-return \Psr\Log\LogLevel::*
-     */
-    public function toPsrLogLevel(): string
-    {
-        return match ($this) {
-            self::Debug => LogLevel::DEBUG,
-            self::Info => LogLevel::INFO,
-            self::Notice => LogLevel::NOTICE,
-            self::Warning => LogLevel::WARNING,
-            self::Error => LogLevel::ERROR,
-            self::Critical => LogLevel::CRITICAL,
-            self::Alert => LogLevel::ALERT,
-            self::Emergency => LogLevel::EMERGENCY,
-        };
-    }
-
-    /**
-     * Returns the RFC 5424 level matching this instance
-     *
-     * @phpstan-return int<0, 7>
-     */
-    public function toRFC5424Level(): int
-    {
-        return match ($this) {
-            self::Debug => 7,
-            self::Info => 6,
-            self::Notice => 5,
-            self::Warning => 4,
-            self::Error => 3,
-            self::Critical => 2,
-            self::Alert => 1,
-            self::Emergency => 0,
-        };
-    }
-
-    public const VALUES = [
-        100,
-        200,
-        250,
-        300,
-        400,
-        500,
-        550,
-        600,
-    ];
-
-    public const NAMES = [
-        'DEBUG',
-        'INFO',
-        'NOTICE',
-        'WARNING',
-        'ERROR',
-        'CRITICAL',
-        'ALERT',
-        'EMERGENCY',
-    ];
-}
index df758c58bf9cac91050bb6da0da745772974143b..702807d7181e68da1ecc6d808959c19f3d302749 100644 (file)
@@ -14,111 +14,21 @@ namespace Monolog;
 use ArrayAccess;
 
 /**
- * Monolog log record
+ * Monolog log record interface for forward compatibility with Monolog 3.0
+ *
+ * This is just present in Monolog 2.4+ to allow interoperable code to be written against
+ * both versions by type-hinting arguments as `array|\Monolog\LogRecord $record`
+ *
+ * Do not rely on this interface for other purposes, and do not implement it.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
- * @template-implements ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra', int|string|\DateTimeImmutable|array<mixed>>
+ * @template-extends \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed>
+ * @phpstan-import-type Record from Logger
  */
-class LogRecord implements ArrayAccess
+interface LogRecord extends \ArrayAccess
 {
-    private const MODIFIABLE_FIELDS = [
-        'extra' => true,
-        'formatted' => true,
-    ];
-
-    public function __construct(
-        public readonly \DateTimeImmutable $datetime,
-        public readonly string $channel,
-        public readonly Level $level,
-        public readonly string $message,
-        /** @var array<mixed> */
-        public readonly array $context = [],
-        /** @var array<mixed> */
-        public array $extra = [],
-        public mixed $formatted = null,
-    ) {
-    }
-
-    public function offsetSet(mixed $offset, mixed $value): void
-    {
-        if ($offset === 'extra') {
-            if (!is_array($value)) {
-                throw new \InvalidArgumentException('extra must be an array');
-            }
-
-            $this->extra = $value;
-
-            return;
-        }
-
-        if ($offset === 'formatted') {
-            $this->formatted = $value;
-
-            return;
-        }
-
-        throw new \LogicException('Unsupported operation: setting '.$offset);
-    }
-
-    public function offsetExists(mixed $offset): bool
-    {
-        if ($offset === 'level_name') {
-            return true;
-        }
-
-        return isset($this->{$offset});
-    }
-
-    public function offsetUnset(mixed $offset): void
-    {
-        throw new \LogicException('Unsupported operation');
-    }
-
-    public function &offsetGet(mixed $offset): mixed
-    {
-        if ($offset === 'level_name' || $offset === 'level') {
-            // avoid returning readonly props by ref as this is illegal
-            if ($offset === 'level_name') {
-                $copy = $this->level->getName();
-            } else {
-                $copy = $this->level->value;
-            }
-
-            return $copy;
-        }
-
-        if (isset(self::MODIFIABLE_FIELDS[$offset])) {
-            return $this->{$offset};
-        }
-
-        // avoid returning readonly props by ref as this is illegal
-        $copy = $this->{$offset};
-
-        return $copy;
-    }
-
     /**
-     * @phpstan-return array{message: string, context: mixed[], level: value-of<Level::VALUES>, level_name: value-of<Level::NAMES>, channel: string, datetime: \DateTimeImmutable, extra: mixed[]}
+     * @phpstan-return Record
      */
-    public function toArray(): array
-    {
-        return [
-            'message' => $this->message,
-            'context' => $this->context,
-            'level' => $this->level->value,
-            'level_name' => $this->level->getName(),
-            'channel' => $this->channel,
-            'datetime' => $this->datetime,
-            'extra' => $this->extra,
-        ];
-    }
-
-    public function with(mixed ...$args): self
-    {
-        foreach (['message', 'context', 'level', 'channel', 'datetime', 'extra'] as $prop) {
-            $args[$prop] ??= $this->{$prop};
-        }
-
-        return new self(...$args);
-    }
+    public function toArray(): array;
 }
index 5aacc6f8735c813b1e0f3ebc54d8be00f9b877ef..84a2f551020e7f0795ad7c01bd907389cfc1978a 100644 (file)
 
 namespace Monolog;
 
-use Closure;
 use DateTimeZone;
 use Monolog\Handler\HandlerInterface;
-use Monolog\Processor\ProcessorInterface;
 use Psr\Log\LoggerInterface;
 use Psr\Log\InvalidArgumentException;
 use Psr\Log\LogLevel;
@@ -28,14 +26,15 @@ use Stringable;
  * and uses them to store records that are added to it.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
- * @final
+ *
+ * @phpstan-type Level Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY
+ * @phpstan-type LevelName 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY'
+ * @phpstan-type Record array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]}
  */
 class Logger implements LoggerInterface, ResettableInterface
 {
     /**
      * Detailed debug information
-     *
-     * @deprecated Use \Monolog\Level::Debug
      */
     public const DEBUG = 100;
 
@@ -43,15 +42,11 @@ class Logger implements LoggerInterface, ResettableInterface
      * Interesting events
      *
      * Examples: User logs in, SQL logs.
-     *
-     * @deprecated Use \Monolog\Level::Info
      */
     public const INFO = 200;
 
     /**
      * Uncommon events
-     *
-     * @deprecated Use \Monolog\Level::Notice
      */
     public const NOTICE = 250;
 
@@ -60,15 +55,11 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * Examples: Use of deprecated APIs, poor use of an API,
      * undesirable things that are not necessarily wrong.
-     *
-     * @deprecated Use \Monolog\Level::Warning
      */
     public const WARNING = 300;
 
     /**
      * Runtime errors
-     *
-     * @deprecated Use \Monolog\Level::Error
      */
     public const ERROR = 400;
 
@@ -76,8 +67,6 @@ class Logger implements LoggerInterface, ResettableInterface
      * Critical conditions
      *
      * Example: Application component unavailable, unexpected exception.
-     *
-     * @deprecated Use \Monolog\Level::Critical
      */
     public const CRITICAL = 500;
 
@@ -86,15 +75,11 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * Example: Entire website down, database unavailable, etc.
      * This should trigger the SMS alerts and wake you up.
-     *
-     * @deprecated Use \Monolog\Level::Alert
      */
     public const ALERT = 550;
 
     /**
      * Urgent alert.
-     *
-     * @deprecated Use \Monolog\Level::Emergency
      */
     public const EMERGENCY = 600;
 
@@ -103,8 +88,28 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * This is only bumped when API breaks are done and should
      * follow the major version of the library
+     *
+     * @var int
      */
-    public const API = 3;
+    public const API = 2;
+
+    /**
+     * This is a static variable and not a constant to serve as an extension point for custom levels
+     *
+     * @var array<int, string> $levels Logging levels with the levels as key
+     *
+     * @phpstan-var array<Level, LevelName> $levels Logging levels with the levels as key
+     */
+    protected static $levels = [
+        self::DEBUG     => 'DEBUG',
+        self::INFO      => 'INFO',
+        self::NOTICE    => 'NOTICE',
+        self::WARNING   => 'WARNING',
+        self::ERROR     => 'ERROR',
+        self::CRITICAL  => 'CRITICAL',
+        self::ALERT     => 'ALERT',
+        self::EMERGENCY => 'EMERGENCY',
+    ];
 
     /**
      * Mapping between levels numbers defined in RFC 5424 and Monolog ones
@@ -112,66 +117,90 @@ class Logger implements LoggerInterface, ResettableInterface
      * @phpstan-var array<int, Level> $rfc_5424_levels
      */
     private const RFC_5424_LEVELS = [
-        7 => Level::Debug,
-        6 => Level::Info,
-        5 => Level::Notice,
-        4 => Level::Warning,
-        3 => Level::Error,
-        2 => Level::Critical,
-        1 => Level::Alert,
-        0 => Level::Emergency,
+        7 => self::DEBUG,
+        6 => self::INFO,
+        5 => self::NOTICE,
+        4 => self::WARNING,
+        3 => self::ERROR,
+        2 => self::CRITICAL,
+        1 => self::ALERT,
+        0 => self::EMERGENCY,
     ];
 
-    protected string $name;
+    /**
+     * @var string
+     */
+    protected $name;
 
     /**
      * The handler stack
      *
-     * @var list<HandlerInterface>
+     * @var HandlerInterface[]
      */
-    protected array $handlers;
+    protected $handlers;
 
     /**
      * Processors that will process all log records
      *
      * To process records of a single handler instead, add the processor on that specific handler
      *
-     * @var array<(callable(LogRecord): LogRecord)|ProcessorInterface>
+     * @var callable[]
      */
-    protected array $processors;
+    protected $processors;
 
-    protected bool $microsecondTimestamps = true;
+    /**
+     * @var bool
+     */
+    protected $microsecondTimestamps = true;
 
-    protected DateTimeZone $timezone;
+    /**
+     * @var DateTimeZone
+     */
+    protected $timezone;
 
-    protected Closure|null $exceptionHandler = null;
+    /**
+     * @var callable|null
+     */
+    protected $exceptionHandler;
 
     /**
-     * Keeps track of depth to prevent infinite logging loops
+     * @var int Keeps track of depth to prevent infinite logging loops
      */
-    private int $logDepth = 0;
+    private $logDepth = 0;
 
     /**
-     * Whether to detect infinite logging loops
+     * @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops
+     */
+    private $fiberLogDepth;
+
+    /**
+     * @var bool Whether to detect infinite logging loops
      *
      * This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this
      */
-    private bool $detectCycles = true;
+    private $detectCycles = true;
 
     /**
+     * @psalm-param array<callable(array): array> $processors
+     *
      * @param string             $name       The logging channel, a simple descriptive name that is attached to all log records
      * @param HandlerInterface[] $handlers   Optional stack of handlers, the first one in the array is called first, etc.
      * @param callable[]         $processors Optional array of processors
      * @param DateTimeZone|null  $timezone   Optional timezone, if not provided date_default_timezone_get() will be used
-     *
-     * @phpstan-param array<(callable(LogRecord): LogRecord)|ProcessorInterface> $processors
      */
-    public function __construct(string $name, array $handlers = [], array $processors = [], DateTimeZone|null $timezone = null)
+    public function __construct(string $name, array $handlers = [], array $processors = [], ?DateTimeZone $timezone = null)
     {
         $this->name = $name;
         $this->setHandlers($handlers);
         $this->processors = $processors;
-        $this->timezone = $timezone ?? new DateTimeZone(date_default_timezone_get());
+        $this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get() ?: 'UTC');
+
+        if (\PHP_VERSION_ID >= 80100) {
+            // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
+            /** @var \WeakMap<\Fiber, int> $fiberLogDepth */
+            $fiberLogDepth = new \WeakMap();
+            $this->fiberLogDepth = $fiberLogDepth;
+        }
     }
 
     public function getName(): string
@@ -207,7 +236,7 @@ class Logger implements LoggerInterface, ResettableInterface
      */
     public function popHandler(): HandlerInterface
     {
-        if (0 === \count($this->handlers)) {
+        if (!$this->handlers) {
             throw new \LogicException('You tried to pop from an empty handler stack.');
         }
 
@@ -219,7 +248,7 @@ class Logger implements LoggerInterface, ResettableInterface
      *
      * If a map is passed, keys will be ignored.
      *
-     * @param list<HandlerInterface> $handlers
+     * @param HandlerInterface[] $handlers
      */
     public function setHandlers(array $handlers): self
     {
@@ -232,7 +261,7 @@ class Logger implements LoggerInterface, ResettableInterface
     }
 
     /**
-     * @return list<HandlerInterface>
+     * @return HandlerInterface[]
      */
     public function getHandlers(): array
     {
@@ -241,10 +270,8 @@ class Logger implements LoggerInterface, ResettableInterface
 
     /**
      * Adds a processor on to the stack.
-     *
-     * @phpstan-param ProcessorInterface|(callable(LogRecord): LogRecord) $callback
      */
-    public function pushProcessor(ProcessorInterface|callable $callback): self
+    public function pushProcessor(callable $callback): self
     {
         array_unshift($this->processors, $callback);
 
@@ -254,12 +281,12 @@ class Logger implements LoggerInterface, ResettableInterface
     /**
      * Removes the processor on top of the stack and returns it.
      *
-     * @phpstan-return ProcessorInterface|(callable(LogRecord): LogRecord)
      * @throws \LogicException If empty processor stack
+     * @return callable
      */
     public function popProcessor(): callable
     {
-        if (0 === \count($this->processors)) {
+        if (!$this->processors) {
             throw new \LogicException('You tried to pop from an empty processor stack.');
         }
 
@@ -268,7 +295,6 @@ class Logger implements LoggerInterface, ResettableInterface
 
     /**
      * @return callable[]
-     * @phpstan-return array<ProcessorInterface|(callable(LogRecord): LogRecord)>
      */
     public function getProcessors(): array
     {
@@ -309,49 +335,58 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param  DateTimeImmutable $datetime Optional log date to log into the past or future
      * @return bool              Whether the record has been processed
      *
-     * @phpstan-param value-of<Level::VALUES>|Level $level
+     * @phpstan-param Level $level
      */
-    public function addRecord(int|Level $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool
+    public function addRecord(int $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool
     {
-        if (is_int($level) && isset(self::RFC_5424_LEVELS[$level])) {
+        if (isset(self::RFC_5424_LEVELS[$level])) {
             $level = self::RFC_5424_LEVELS[$level];
         }
 
         if ($this->detectCycles) {
-            $this->logDepth += 1;
+            if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber::getCurrent()) {
+                $this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0;
+                $logDepth = ++$this->fiberLogDepth[$fiber];
+            } else {
+                $logDepth = ++$this->logDepth;
+            }
+        } else {
+            $logDepth = 0;
         }
-        if ($this->logDepth === 3) {
+
+        if ($logDepth === 3) {
             $this->warning('A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.');
             return false;
-        } elseif ($this->logDepth >= 5) { // log depth 4 is let through so we can log the warning above
+        } elseif ($logDepth >= 5) { // log depth 4 is let through, so we can log the warning above
             return false;
         }
 
         try {
-            $recordInitialized = count($this->processors) === 0;
-
-            $record = new LogRecord(
-                message: $message,
-                context: $context,
-                level: self::toMonologLevel($level),
-                channel: $this->name,
-                datetime: $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
-                extra: [],
-            );
-            $handled = false;
+            $record = null;
 
             foreach ($this->handlers as $handler) {
-                if (false === $recordInitialized) {
-                    // skip initializing the record as long as no handler is going to handle it
-                    if (!$handler->isHandling($record)) {
+                if (null === $record) {
+                    // skip creating the record as long as no handler is going to handle it
+                    if (!$handler->isHandling(['level' => $level])) {
                         continue;
                     }
 
+                    $levelName = static::getLevelName($level);
+
+                    $record = [
+                        'message' => $message,
+                        'context' => $context,
+                        'level' => $level,
+                        'level_name' => $levelName,
+                        'channel' => $this->name,
+                        'datetime' => $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
+                        'extra' => [],
+                    ];
+
                     try {
                         foreach ($this->processors as $processor) {
                             $record = $processor($record);
                         }
-                        $recordInitialized = true;
                     } catch (Throwable $e) {
                         $this->handleException($e, $record);
 
@@ -359,9 +394,8 @@ class Logger implements LoggerInterface, ResettableInterface
                     }
                 }
 
-                // once the record is initialized, send it to all handlers as long as the bubbling chain is not interrupted
+                // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
                 try {
-                    $handled = true;
                     if (true === $handler->handle($record)) {
                         break;
                     }
@@ -371,13 +405,17 @@ class Logger implements LoggerInterface, ResettableInterface
                     return true;
                 }
             }
-
-            return $handled;
         } finally {
             if ($this->detectCycles) {
-                $this->logDepth--;
+                if (isset($fiber)) {
+                    $this->fiberLogDepth[$fiber]--;
+                } else {
+                    $this->logDepth--;
+                }
             }
         }
+
+        return null !== $record;
     }
 
     /**
@@ -423,77 +461,77 @@ class Logger implements LoggerInterface, ResettableInterface
     }
 
     /**
-     * Gets the name of the logging level as a string.
+     * Gets all supported logging levels.
      *
-     * This still returns a string instead of a Level for BC, but new code should not rely on this method.
+     * @return array<string, int> Assoc array with human-readable level names => level codes.
+     * @phpstan-return array<LevelName, Level>
+     */
+    public static function getLevels(): array
+    {
+        return array_flip(static::$levels);
+    }
+
+    /**
+     * Gets the name of the logging level.
      *
      * @throws \Psr\Log\InvalidArgumentException If level is not defined
      *
-     * @phpstan-param  value-of<Level::VALUES>|Level $level
-     * @phpstan-return value-of<Level::NAMES>
-     *
-     * @deprecated Since 3.0, use {@see toMonologLevel} or {@see \Monolog\Level->getName()} instead
+     * @phpstan-param  Level     $level
+     * @phpstan-return LevelName
      */
-    public static function getLevelName(int|Level $level): string
+    public static function getLevelName(int $level): string
     {
-        return self::toMonologLevel($level)->getName();
+        if (!isset(static::$levels[$level])) {
+            throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
+        }
+
+        return static::$levels[$level];
     }
 
     /**
      * Converts PSR-3 levels to Monolog ones if necessary
      *
-     * @param  int|string|Level|LogLevel::* $level Level number (monolog) or name (PSR-3)
-     * @throws \Psr\Log\InvalidArgumentException      If level is not defined
+     * @param  string|int                        $level Level number (monolog) or name (PSR-3)
+     * @throws \Psr\Log\InvalidArgumentException If level is not defined
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param  Level|LevelName|LogLevel::* $level
+     * @phpstan-return Level
      */
-    public static function toMonologLevel(string|int|Level $level): Level
+    public static function toMonologLevel($level): int
     {
-        if ($level instanceof Level) {
-            return $level;
-        }
-
-        if (\is_string($level)) {
-            if (\is_numeric($level)) {
-                $levelEnum = Level::tryFrom((int) $level);
-                if ($levelEnum === null) {
-                    throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES));
-                }
-
-                return $levelEnum;
+        if (is_string($level)) {
+            if (is_numeric($level)) {
+                /** @phpstan-ignore-next-line */
+                return intval($level);
             }
 
-            // Contains first char of all log levels and avoids using strtoupper() which may have
+            // Contains chars of all log levels and avoids using strtoupper() which may have
             // strange results depending on locale (for example, "i" will become "Ä°" in Turkish locale)
-            $upper = strtr(substr($level, 0, 1), 'dinweca', 'DINWECA') . strtolower(substr($level, 1));
-            if (defined(Level::class.'::'.$upper)) {
-                return constant(Level::class . '::' . $upper);
+            $upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY');
+            if (defined(__CLASS__.'::'.$upper)) {
+                return constant(__CLASS__ . '::' . $upper);
             }
 
-            throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES));
+            throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels));
         }
 
-        $levelEnum = Level::tryFrom($level);
-        if ($levelEnum === null) {
-            throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES));
+        if (!is_int($level)) {
+            throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels));
         }
 
-        return $levelEnum;
+        return $level;
     }
 
     /**
      * Checks whether the Logger has a handler that listens on the given level
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level $level
      */
-    public function isHandling(int|string|Level $level): bool
+    public function isHandling(int $level): bool
     {
-        $record = new LogRecord(
-            datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
-            channel: $this->name,
-            message: '',
-            level: self::toMonologLevel($level),
-        );
+        $record = [
+            'level' => $level,
+        ];
 
         foreach ($this->handlers as $handler) {
             if ($handler->isHandling($record)) {
@@ -507,16 +545,16 @@ class Logger implements LoggerInterface, ResettableInterface
     /**
      * Set a custom exception handler that will be called if adding a new record fails
      *
-     * The Closure will receive an exception object and the record that failed to be logged
+     * The callable will receive an exception object and the record that failed to be logged
      */
-    public function setExceptionHandler(Closure|null $callback): self
+    public function setExceptionHandler(?callable $callback): self
     {
         $this->exceptionHandler = $callback;
 
         return $this;
     }
 
-    public function getExceptionHandler(): Closure|null
+    public function getExceptionHandler(): ?callable
     {
         return $this->exceptionHandler;
     }
@@ -530,22 +568,20 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      *
-     * @phpstan-param Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function log($level, string|\Stringable $message, array $context = []): void
+    public function log($level, $message, array $context = []): void
     {
-        if (!$level instanceof Level) {
-            if (!is_string($level) && !is_int($level)) {
-                throw new \InvalidArgumentException('$level is expected to be a string, int or '.Level::class.' instance');
-            }
-
-            if (isset(self::RFC_5424_LEVELS[$level])) {
-                $level = self::RFC_5424_LEVELS[$level];
-            }
+        if (!is_int($level) && !is_string($level)) {
+            throw new \InvalidArgumentException('$level is expected to be a string or int');
+        }
 
-            $level = static::toMonologLevel($level);
+        if (isset(self::RFC_5424_LEVELS[$level])) {
+            $level = self::RFC_5424_LEVELS[$level];
         }
 
+        $level = static::toMonologLevel($level);
+
         $this->addRecord($level, (string) $message, $context);
     }
 
@@ -557,9 +593,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function debug(string|\Stringable $message, array $context = []): void
+    public function debug($message, array $context = []): void
     {
-        $this->addRecord(Level::Debug, (string) $message, $context);
+        $this->addRecord(static::DEBUG, (string) $message, $context);
     }
 
     /**
@@ -570,9 +606,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function info(string|\Stringable $message, array $context = []): void
+    public function info($message, array $context = []): void
     {
-        $this->addRecord(Level::Info, (string) $message, $context);
+        $this->addRecord(static::INFO, (string) $message, $context);
     }
 
     /**
@@ -583,9 +619,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function notice(string|\Stringable $message, array $context = []): void
+    public function notice($message, array $context = []): void
     {
-        $this->addRecord(Level::Notice, (string) $message, $context);
+        $this->addRecord(static::NOTICE, (string) $message, $context);
     }
 
     /**
@@ -596,9 +632,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function warning(string|\Stringable $message, array $context = []): void
+    public function warning($message, array $context = []): void
     {
-        $this->addRecord(Level::Warning, (string) $message, $context);
+        $this->addRecord(static::WARNING, (string) $message, $context);
     }
 
     /**
@@ -609,9 +645,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function error(string|\Stringable $message, array $context = []): void
+    public function error($message, array $context = []): void
     {
-        $this->addRecord(Level::Error, (string) $message, $context);
+        $this->addRecord(static::ERROR, (string) $message, $context);
     }
 
     /**
@@ -622,9 +658,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function critical(string|\Stringable $message, array $context = []): void
+    public function critical($message, array $context = []): void
     {
-        $this->addRecord(Level::Critical, (string) $message, $context);
+        $this->addRecord(static::CRITICAL, (string) $message, $context);
     }
 
     /**
@@ -635,9 +671,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function alert(string|\Stringable $message, array $context = []): void
+    public function alert($message, array $context = []): void
     {
-        $this->addRecord(Level::Alert, (string) $message, $context);
+        $this->addRecord(static::ALERT, (string) $message, $context);
     }
 
     /**
@@ -648,9 +684,9 @@ class Logger implements LoggerInterface, ResettableInterface
      * @param string|Stringable $message The log message
      * @param mixed[]           $context The log context
      */
-    public function emergency(string|\Stringable $message, array $context = []): void
+    public function emergency($message, array $context = []): void
     {
-        $this->addRecord(Level::Emergency, (string) $message, $context);
+        $this->addRecord(static::EMERGENCY, (string) $message, $context);
     }
 
     /**
@@ -674,13 +710,52 @@ class Logger implements LoggerInterface, ResettableInterface
     /**
      * Delegates exception management to the custom exception handler,
      * or throws the exception if no custom handler is set.
+     *
+     * @param array $record
+     * @phpstan-param Record $record
      */
-    protected function handleException(Throwable $e, LogRecord $record): void
+    protected function handleException(Throwable $e, array $record): void
     {
-        if (null === $this->exceptionHandler) {
+        if (!$this->exceptionHandler) {
             throw $e;
         }
 
         ($this->exceptionHandler)($e, $record);
     }
+
+    /**
+     * @return array<string, mixed>
+     */
+    public function __serialize(): array
+    {
+        return [
+            'name' => $this->name,
+            'handlers' => $this->handlers,
+            'processors' => $this->processors,
+            'microsecondTimestamps' => $this->microsecondTimestamps,
+            'timezone' => $this->timezone,
+            'exceptionHandler' => $this->exceptionHandler,
+            'logDepth' => $this->logDepth,
+            'detectCycles' => $this->detectCycles,
+        ];
+    }
+
+    /**
+     * @param array<string, mixed> $data
+     */
+    public function __unserialize(array $data): void
+    {
+        foreach (['name', 'handlers', 'processors', 'microsecondTimestamps', 'timezone', 'exceptionHandler', 'logDepth', 'detectCycles'] as $property) {
+            if (isset($data[$property])) {
+                $this->$property = $data[$property];
+            }
+        }
+
+        if (\PHP_VERSION_ID >= 80100) {
+            // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
+            /** @var \WeakMap<\Fiber, int> $fiberLogDepth */
+            $fiberLogDepth = new \WeakMap();
+            $this->fiberLogDepth = $fiberLogDepth;
+        }
+    }
 }
index 4cbd9c84e4dfb2e40285cfb896e7d1a53f4b0d0f..8166bdca29f85b7a95a939b58401a9f31a0200d7 100644 (file)
 
 namespace Monolog\Processor;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Injects Git branch and Git commit SHA in all records
  *
  * @author Nick Otter
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class GitProcessor implements ProcessorInterface
 {
-    private Level $level;
+    /** @var int */
+    private $level;
     /** @var array{branch: string, commit: string}|array<never>|null */
     private static $cache = null;
 
     /**
-     * @param int|string|Level|LogLevel::* $level The minimum logging level at which this Processor will be triggered
+     * @param string|int $level The minimum logging level at which this Processor will be triggered
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function __construct(int|string|Level $level = Level::Debug)
+    public function __construct($level = Logger::DEBUG)
     {
         $this->level = Logger::toMonologLevel($level);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         // return if the level is not high enough
-        if ($record->level < $this->level) {
+        if ($record['level'] < $this->level) {
             return $record;
         }
 
-        $record->extra['git'] = self::getGitInfo();
+        $record['extra']['git'] = self::getGitInfo();
 
         return $record;
     }
@@ -58,12 +60,12 @@ class GitProcessor implements ProcessorInterface
      */
     private static function getGitInfo(): array
     {
-        if (self::$cache !== null) {
+        if (self::$cache) {
             return self::$cache;
         }
 
-        $branches = shell_exec('git branch -v --no-abbrev');
-        if (is_string($branches) && 1 === preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
+        $branches = `git branch -v --no-abbrev`;
+        if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
             return self::$cache = [
                 'branch' => $matches[1],
                 'commit' => $matches[2],
index cba6e0963637f679d7d8e0e164a5e8867f5e915a..91fda7d6daef9b2cfa7dda3afe1210db722e1e8e 100644 (file)
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * Injects value of gethostname in all records
  */
 class HostnameProcessor implements ProcessorInterface
 {
-    private static string $host;
+    /** @var string */
+    private static $host;
 
     public function __construct()
     {
@@ -26,11 +25,11 @@ class HostnameProcessor implements ProcessorInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
-        $record->extra['hostname'] = self::$host;
+        $record['extra']['hostname'] = self::$host;
 
         return $record;
     }
index 30e7dfed85dca08c50f48ae076c04a96b319b7c0..a32e76b21a32fe5a7c66d0f60ac90b4ad02d528c 100644 (file)
 
 namespace Monolog\Processor;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Injects line/file:class/function where the log message came from
@@ -26,28 +24,31 @@ use Monolog\LogRecord;
  * triggered the FingersCrossedHandler.
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class IntrospectionProcessor implements ProcessorInterface
 {
-    private Level $level;
-
+    /** @var int */
+    private $level;
     /** @var string[] */
-    private array $skipClassesPartials;
-
-    private int $skipStackFramesCount;
-
-    private const SKIP_FUNCTIONS = [
+    private $skipClassesPartials;
+    /** @var int */
+    private $skipStackFramesCount;
+    /** @var string[] */
+    private $skipFunctions = [
         'call_user_func',
         'call_user_func_array',
     ];
 
     /**
-     * @param string|int|Level $level               The minimum logging level at which this Processor will be triggered
-     * @param string[]                   $skipClassesPartials
+     * @param string|int $level               The minimum logging level at which this Processor will be triggered
+     * @param string[]   $skipClassesPartials
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function __construct(int|string|Level $level = Level::Debug, array $skipClassesPartials = [], int $skipStackFramesCount = 0)
+    public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0)
     {
         $this->level = Logger::toMonologLevel($level);
         $this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials);
@@ -55,12 +56,12 @@ class IntrospectionProcessor implements ProcessorInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         // return if the level is not high enough
-        if ($record->level->isLowerThan($this->level)) {
+        if ($record['level'] < $this->level) {
             return $record;
         }
 
@@ -82,7 +83,7 @@ class IntrospectionProcessor implements ProcessorInterface
                         continue 2;
                     }
                 }
-            } elseif (in_array($trace[$i]['function'], self::SKIP_FUNCTIONS, true)) {
+            } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
                 $i++;
 
                 continue;
@@ -94,8 +95,8 @@ class IntrospectionProcessor implements ProcessorInterface
         $i += $this->skipStackFramesCount;
 
         // we should have the call source now
-        $record->extra = array_merge(
-            $record->extra,
+        $record['extra'] = array_merge(
+            $record['extra'],
             [
                 'file'      => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
                 'line'      => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
@@ -109,7 +110,7 @@ class IntrospectionProcessor implements ProcessorInterface
     }
 
     /**
-     * @param array<mixed> $trace
+     * @param array[] $trace
      */
     private function isTraceClassOrSkippedFunction(array $trace, int $index): bool
     {
@@ -117,6 +118,6 @@ class IntrospectionProcessor implements ProcessorInterface
             return false;
         }
 
-        return isset($trace[$index]['class']) || in_array($trace[$index]['function'], self::SKIP_FUNCTIONS, true);
+        return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
     }
 }
index adc32c65d4ea25ef6820e75de5c945d50a99063b..37c756fcb34baea99b9067f1773b20ab62c0ad31 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * Injects memory_get_peak_usage in all records
  *
@@ -22,9 +20,9 @@ use Monolog\LogRecord;
 class MemoryPeakUsageProcessor extends MemoryProcessor
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         $usage = memory_get_peak_usage($this->realUsage);
 
@@ -32,7 +30,7 @@ class MemoryPeakUsageProcessor extends MemoryProcessor
             $usage = $this->formatBytes($usage);
         }
 
-        $record->extra['memory_peak_usage'] = $usage;
+        $record['extra']['memory_peak_usage'] = $usage;
 
         return $record;
     }
index f808e51b4a4909594e2243fcb41c7da7fb65fc0b..227deb7c86947235412e68fac6f6bb463fe184e0 100644 (file)
@@ -21,12 +21,12 @@ abstract class MemoryProcessor implements ProcessorInterface
     /**
      * @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
      */
-    protected bool $realUsage;
+    protected $realUsage;
 
     /**
      * @var bool If true, then format memory size to human readable string (MB, KB, B depending on size)
      */
-    protected bool $useFormatting;
+    protected $useFormatting;
 
     /**
      * @param bool $realUsage     Set this to true to get the real size of memory allocated from system.
@@ -41,6 +41,7 @@ abstract class MemoryProcessor implements ProcessorInterface
     /**
      * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is
      *
+     * @param  int        $bytes
      * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as int
      */
     protected function formatBytes(int $bytes)
index a814b1df34b8fd54ef1802009b849340086cedb0..e141921e95a968f28f78712bd31b2499641e5079 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * Injects memory_get_usage in all records
  *
@@ -22,9 +20,9 @@ use Monolog\LogRecord;
 class MemoryUsageProcessor extends MemoryProcessor
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         $usage = memory_get_usage($this->realUsage);
 
@@ -32,7 +30,7 @@ class MemoryUsageProcessor extends MemoryProcessor
             $usage = $this->formatBytes($usage);
         }
 
-        $record->extra['memory_usage'] = $usage;
+        $record['extra']['memory_usage'] = $usage;
 
         return $record;
     }
index 47b1e64ff90ee1184ba5c1f9c61bbd752b42dd24..d4a628f552c0cf4e1febe23ec50f77ae8f5dce57 100644 (file)
 
 namespace Monolog\Processor;
 
-use Monolog\Level;
 use Monolog\Logger;
 use Psr\Log\LogLevel;
-use Monolog\LogRecord;
 
 /**
  * Injects Hg branch and Hg revision number in all records
  *
  * @author Jonathan A. Schweder <jonathanschweder@gmail.com>
+ *
+ * @phpstan-import-type LevelName from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
  */
 class MercurialProcessor implements ProcessorInterface
 {
-    private Level $level;
+    /** @var Level */
+    private $level;
     /** @var array{branch: string, revision: string}|array<never>|null */
     private static $cache = null;
 
     /**
-     * @param int|string|Level $level The minimum logging level at which this Processor will be triggered
+     * @param int|string $level The minimum logging level at which this Processor will be triggered
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function __construct(int|string|Level $level = Level::Debug)
+    public function __construct($level = Logger::DEBUG)
     {
         $this->level = Logger::toMonologLevel($level);
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         // return if the level is not high enough
-        if ($record->level->isLowerThan($this->level)) {
+        if ($record['level'] < $this->level) {
             return $record;
         }
 
-        $record->extra['hg'] = self::getMercurialInfo();
+        $record['extra']['hg'] = self::getMercurialInfo();
 
         return $record;
     }
@@ -57,11 +59,11 @@ class MercurialProcessor implements ProcessorInterface
      */
     private static function getMercurialInfo(): array
     {
-        if (self::$cache !== null) {
+        if (self::$cache) {
             return self::$cache;
         }
 
-        $result = explode(' ', trim((string) shell_exec('hg id -nb')));
+        $result = explode(' ', trim(`hg id -nb`));
 
         if (count($result) >= 3) {
             return self::$cache = [
index bb9a5224343d647a5844ebffae10ee97a9815a40..3b939a951be7f8ce6ca060619c756e68f08cd525 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * Adds value of getmypid into records
  *
@@ -21,11 +19,11 @@ use Monolog\LogRecord;
 class ProcessIdProcessor implements ProcessorInterface
 {
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
-        $record->extra['process_id'] = getmypid();
+        $record['extra']['process_id'] = getmypid();
 
         return $record;
     }
index ebe41fc20604a2137474f573afad7d23f22b8b55..5defb7eb4fa688f8dfddf46e5f824a6c65215112 100644 (file)
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * An optional interface to allow labelling Monolog processors.
  *
  * @author Nicolas Grekas <p@tchwork.com>
+ *
+ * @phpstan-import-type Record from \Monolog\Logger
  */
 interface ProcessorInterface
 {
     /**
-     * @return LogRecord The processed record
+     * @return array The processed record
+     *
+     * @phpstan-param  Record $record
+     * @phpstan-return Record
      */
-    public function __invoke(LogRecord $record);
+    public function __invoke(array $record);
 }
index f2407d56351e0709b405cba48a323e27011f8df1..e7c12176a7b248f67bf534bc3cc8933f5a3d5e38 100644 (file)
@@ -12,7 +12,6 @@
 namespace Monolog\Processor;
 
 use Monolog\Utils;
-use Monolog\LogRecord;
 
 /**
  * Processes a record's message according to PSR-3 rules
@@ -25,9 +24,11 @@ class PsrLogMessageProcessor implements ProcessorInterface
 {
     public const SIMPLE_DATE = "Y-m-d\TH:i:s.uP";
 
-    private ?string $dateFormat;
+    /** @var string|null */
+    private $dateFormat;
 
-    private bool $removeUsedContextFields;
+    /** @var bool */
+    private $removeUsedContextFields;
 
     /**
      * @param string|null $dateFormat              The format of the timestamp: one supported by DateTime::format
@@ -40,33 +41,33 @@ class PsrLogMessageProcessor implements ProcessorInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
-        if (false === strpos($record->message, '{')) {
+        if (false === strpos($record['message'], '{')) {
             return $record;
         }
 
         $replacements = [];
-        $context = $record->context;
-
-        foreach ($context as $key => $val) {
+        foreach ($record['context'] as $key => $val) {
             $placeholder = '{' . $key . '}';
-            if (strpos($record->message, $placeholder) === false) {
+            if (strpos($record['message'], $placeholder) === false) {
                 continue;
             }
 
-            if (null === $val || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
+            if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
                 $replacements[$placeholder] = $val;
             } elseif ($val instanceof \DateTimeInterface) {
-                if (null === $this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) {
+                if (!$this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) {
                     // handle monolog dates using __toString if no specific dateFormat was asked for
                     // so that it follows the useMicroseconds flag
                     $replacements[$placeholder] = (string) $val;
                 } else {
-                    $replacements[$placeholder] = $val->format($this->dateFormat ?? static::SIMPLE_DATE);
+                    $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
                 }
+            } elseif ($val instanceof \UnitEnum) {
+                $replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name;
             } elseif (is_object($val)) {
                 $replacements[$placeholder] = '[object '.Utils::getClass($val).']';
             } elseif (is_array($val)) {
@@ -76,10 +77,12 @@ class PsrLogMessageProcessor implements ProcessorInterface
             }
 
             if ($this->removeUsedContextFields) {
-                unset($context[$key]);
+                unset($record['context'][$key]);
             }
         }
 
-        return $record->with(message: strtr($record->message, $replacements), context: $context);
+        $record['message'] = strtr($record['message'], $replacements);
+
+        return $record;
     }
 }
index 4543ccf6112cc2b44166d406d16033a75129dc51..80f18747aa3dbcec10825a418809bd42859e17e6 100644 (file)
@@ -11,8 +11,6 @@
 
 namespace Monolog\Processor;
 
-use Monolog\LogRecord;
-
 /**
  * Adds a tags array into record
  *
@@ -21,7 +19,7 @@ use Monolog\LogRecord;
 class TagProcessor implements ProcessorInterface
 {
     /** @var string[] */
-    private array $tags;
+    private $tags;
 
     /**
      * @param string[] $tags
@@ -52,11 +50,11 @@ class TagProcessor implements ProcessorInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
-        $record->extra['tags'] = $this->tags;
+        $record['extra']['tags'] = $this->tags;
 
         return $record;
     }
index 3a0c128c2b6a22474238b61a4b63aa4f1b22c692..a27b74dbf2a400ca023b3315cdd65014da5585d4 100644 (file)
@@ -12,7 +12,6 @@
 namespace Monolog\Processor;
 
 use Monolog\ResettableInterface;
-use Monolog\LogRecord;
 
 /**
  * Adds a unique identifier into records
@@ -21,12 +20,9 @@ use Monolog\LogRecord;
  */
 class UidProcessor implements ProcessorInterface, ResettableInterface
 {
-    /** @var non-empty-string */
-    private string $uid;
+    /** @var string */
+    private $uid;
 
-    /**
-     * @param int<1, 32> $length
-     */
     public function __construct(int $length = 7)
     {
         if ($length > 32 || $length < 1) {
@@ -37,11 +33,11 @@ class UidProcessor implements ProcessorInterface, ResettableInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
-        $record->extra['uid'] = $this->uid;
+        $record['extra']['uid'] = $this->uid;
 
         return $record;
     }
@@ -51,15 +47,11 @@ class UidProcessor implements ProcessorInterface, ResettableInterface
         return $this->uid;
     }
 
-    public function reset(): void
+    public function reset()
     {
         $this->uid = $this->generateUid(strlen($this->uid));
     }
 
-    /**
-     * @param  positive-int     $length
-     * @return non-empty-string
-     */
     private function generateUid(int $length): string
     {
         return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length);
index 2088b180b7950d1655a1b9f0ffa5834c07a1b92e..51850e17f7b14b715182097c5163052ee09e0685 100644 (file)
@@ -11,9 +11,6 @@
 
 namespace Monolog\Processor;
 
-use ArrayAccess;
-use Monolog\LogRecord;
-
 /**
  * Injects url/method and remote IP of the current web request in all records
  *
@@ -22,9 +19,9 @@ use Monolog\LogRecord;
 class WebProcessor implements ProcessorInterface
 {
     /**
-     * @var array<string, mixed>|ArrayAccess<string, mixed>
+     * @var array<string, mixed>|\ArrayAccess<string, mixed>
      */
-    protected array|ArrayAccess $serverData;
+    protected $serverData;
 
     /**
      * Default fields
@@ -33,7 +30,7 @@ class WebProcessor implements ProcessorInterface
      *
      * @var array<string, string>
      */
-    protected array $extraFields = [
+    protected $extraFields = [
         'url'         => 'REQUEST_URI',
         'ip'          => 'REMOTE_ADDR',
         'http_method' => 'REQUEST_METHOD',
@@ -43,15 +40,17 @@ class WebProcessor implements ProcessorInterface
     ];
 
     /**
-     * @param array<string, mixed>|ArrayAccess<string, mixed>|null $serverData  Array or object w/ ArrayAccess that provides access to the $_SERVER data
-     * @param array<string, string>|array<string>|null             $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
+     * @param array<string, mixed>|\ArrayAccess<string, mixed>|null $serverData  Array or object w/ ArrayAccess that provides access to the $_SERVER data
+     * @param array<string, string>|array<string>|null              $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
      */
-    public function __construct(array|ArrayAccess|null $serverData = null, array|null $extraFields = null)
+    public function __construct($serverData = null, array $extraFields = null)
     {
         if (null === $serverData) {
             $this->serverData = &$_SERVER;
-        } else {
+        } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
             $this->serverData = $serverData;
+        } else {
+            throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
         }
 
         $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer'];
@@ -65,7 +64,7 @@ class WebProcessor implements ProcessorInterface
         }
         if (isset($extraFields[0])) {
             foreach (array_keys($this->extraFields) as $fieldName) {
-                if (!in_array($fieldName, $extraFields, true)) {
+                if (!in_array($fieldName, $extraFields)) {
                     unset($this->extraFields[$fieldName]);
                 }
             }
@@ -75,9 +74,9 @@ class WebProcessor implements ProcessorInterface
     }
 
     /**
-     * @inheritDoc
+     * {@inheritDoc}
      */
-    public function __invoke(LogRecord $record): LogRecord
+    public function __invoke(array $record): array
     {
         // skip processing if for some reason request data
         // is not present (CLI or wonky SAPIs)
@@ -85,7 +84,7 @@ class WebProcessor implements ProcessorInterface
             return $record;
         }
 
-        $record->extra = $this->appendExtraFields($record->extra);
+        $record['extra'] = $this->appendExtraFields($record['extra']);
 
         return $record;
     }
index 2ef2edceb4d38a7f3f2bda487713372dc7ec61c9..ae94ae6cc307e6f8cf230214fbe93999d4ac9a13 100644 (file)
@@ -42,7 +42,7 @@ class Registry
      *
      * @var Logger[]
      */
-    private static array $loggers = [];
+    private static $loggers = [];
 
     /**
      * Adds new logging channel to the registry
@@ -51,10 +51,11 @@ class Registry
      * @param  string|null               $name      Name of the logging channel ($logger->getName() by default)
      * @param  bool                      $overwrite Overwrite instance in the registry if the given name already exists?
      * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
+     * @return void
      */
-    public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false): void
+    public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false)
     {
-        $name = $name ?? $logger->getName();
+        $name = $name ?: $logger->getName();
 
         if (isset(self::$loggers[$name]) && !$overwrite) {
             throw new InvalidArgumentException('Logger with the given name already exists');
@@ -109,7 +110,7 @@ class Registry
      * @param  string                    $name Name of the requested Logger instance
      * @throws \InvalidArgumentException If named Logger instance is not in the registry
      */
-    public static function getInstance(string $name): Logger
+    public static function getInstance($name): Logger
     {
         if (!isset(self::$loggers[$name])) {
             throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
@@ -126,7 +127,7 @@ class Registry
      * @throws \InvalidArgumentException If named Logger instance is not in the registry
      * @return Logger                    Requested instance of Logger
      */
-    public static function __callStatic(string $name, array $arguments): Logger
+    public static function __callStatic($name, $arguments)
     {
         return self::getInstance($name);
     }
index 4983a6b3553ae3b2469138d2497bfca189462438..2c5fd78511f058dbe61ac79a2adadeb58cbc600e 100644 (file)
@@ -27,5 +27,8 @@ namespace Monolog;
  */
 interface ResettableInterface
 {
-    public function reset(): void;
+    /**
+     * @return void
+     */
+    public function reset();
 }
index e6b02b083727612327850c34e85426cf8f5bea5d..d730eea3ada18780b4d40642f16cc3da5321fa8f 100644 (file)
@@ -19,17 +19,21 @@ use ReflectionExtension;
  * Monolog POSIX signal handler
  *
  * @author Robert Gust-Bardon <robert@gust-bardon.org>
+ *
+ * @phpstan-import-type Level from \Monolog\Logger
+ * @phpstan-import-type LevelName from \Monolog\Logger
  */
 class SignalHandler
 {
-    private LoggerInterface $logger;
+    /** @var LoggerInterface */
+    private $logger;
 
     /** @var array<int, callable|string|int> SIG_DFL, SIG_IGN or previous callable */
-    private array $previousSignalHandler = [];
-    /** @var array<int, \Psr\Log\LogLevel::*> */
-    private array $signalLevelMap = [];
+    private $previousSignalHandler = [];
+    /** @var array<int, int> */
+    private $signalLevelMap = [];
     /** @var array<int, bool> */
-    private array $signalRestartSyscalls = [];
+    private $signalRestartSyscalls = [];
 
     public function __construct(LoggerInterface $logger)
     {
@@ -37,18 +41,21 @@ class SignalHandler
     }
 
     /**
-     * @param  int|string|Level $level Level or level name
+     * @param  int|string $level           Level or level name
+     * @param  bool       $callPrevious
+     * @param  bool       $restartSyscalls
+     * @param  bool|null  $async
      * @return $this
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param Level|LevelName|LogLevel::* $level
      */
-    public function registerSignalHandler(int $signo, int|string|Level $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self
+    public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self
     {
         if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
             return $this;
         }
 
-        $level = Logger::toMonologLevel($level)->toPsrLogLevel();
+        $level = Logger::toMonologLevel($level);
 
         if ($callPrevious) {
             $handler = pcntl_signal_get_handler($signo);
@@ -77,7 +84,8 @@ class SignalHandler
 
         if (!$signals && extension_loaded('pcntl')) {
             $pcntl = new ReflectionExtension('pcntl');
-            foreach ($pcntl->getConstants() as $name => $value) {
+            // HHVM 3.24.2 returns an empty array.
+            foreach ($pcntl->getConstants() ?: get_defined_constants(true)['Core'] as $name => $value) {
                 if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {
                     $signals[$value] = $name;
                 }
index 98204a95ca5f3be91380adb1d9cff91127ccacc7..bc0b425ea498e3108825ca3ab5e1fca22b230adc 100644 (file)
 
 namespace Monolog\Test;
 
-use Monolog\Level;
 use Monolog\Logger;
-use Monolog\LogRecord;
 use Monolog\DateTimeImmutable;
 use Monolog\Formatter\FormatterInterface;
-use Psr\Log\LogLevel;
 
 /**
  * Lets you easily generate log records and a dummy formatter for testing purposes
  *
  * @author Jordi Boggiano <j.boggiano@seld.be>
  *
+ * @phpstan-import-type Record from \Monolog\Logger
+ * @phpstan-import-type Level from \Monolog\Logger
+ *
  * @internal feel free to reuse this to test your own handlers, this is marked internal to avoid issues with PHPStorm https://github.com/Seldaek/monolog/issues/1677
  */
 class TestCase extends \PHPUnit\Framework\TestCase
@@ -37,44 +37,47 @@ class TestCase extends \PHPUnit\Framework\TestCase
     }
 
     /**
-     * @param array<mixed> $context
-     * @param array<mixed> $extra
+     * @param mixed[] $context
+     *
+     * @return array Record
      *
-     * @phpstan-param value-of<Level::VALUES>|value-of<Level::NAMES>|Level|LogLevel::* $level
+     * @phpstan-param  Level $level
+     * @phpstan-return Record
      */
-    protected function getRecord(int|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord
+    protected function getRecord(int $level = Logger::WARNING, string $message = 'test', array $context = []): array
     {
-        return new LogRecord(
-            message: (string) $message,
-            context: $context,
-            level: Logger::toMonologLevel($level),
-            channel: $channel,
-            datetime: $datetime,
-            extra: $extra,
-        );
+        return [
+            'message' => (string) $message,
+            'context' => $context,
+            'level' => $level,
+            'level_name' => Logger::getLevelName($level),
+            'channel' => 'test',
+            'datetime' => new DateTimeImmutable(true),
+            'extra' => [],
+        ];
     }
 
     /**
-     * @phpstan-return list<LogRecord>
+     * @phpstan-return Record[]
      */
     protected function getMultipleRecords(): array
     {
         return [
-            $this->getRecord(Level::Debug, 'debug message 1'),
-            $this->getRecord(Level::Debug, 'debug message 2'),
-            $this->getRecord(Level::Info, 'information'),
-            $this->getRecord(Level::Warning, 'warning'),
-            $this->getRecord(Level::Error, 'error'),
+            $this->getRecord(Logger::DEBUG, 'debug message 1'),
+            $this->getRecord(Logger::DEBUG, 'debug message 2'),
+            $this->getRecord(Logger::INFO, 'information'),
+            $this->getRecord(Logger::WARNING, 'warning'),
+            $this->getRecord(Logger::ERROR, 'error'),
         ];
     }
 
     protected function getIdentityFormatter(): FormatterInterface
     {
         $formatter = $this->createMock(FormatterInterface::class);
-        $formatter->expects(self::any())
+        $formatter->expects($this->any())
             ->method('format')
-            ->will(self::returnCallback(function ($record) {
-                return $record->message;
+            ->will($this->returnCallback(function ($record) {
+                return $record['message'];
             }));
 
         return $formatter;
index 9dae2535f2ead052b6f7375d5e70516890db9a66..360c42199c1741a2078d497aa2f18218de95027d 100644 (file)
@@ -122,7 +122,7 @@ final class Utils
         if (is_string($data)) {
             self::detectAndCleanUtf8($data);
         } elseif (is_array($data)) {
-            array_walk_recursive($data, ['Monolog\Utils', 'detectAndCleanUtf8']);
+            array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8'));
         } else {
             self::throwEncodeError($code, $data);
         }
@@ -165,16 +165,27 @@ final class Utils
      * @param  int               $code return code of json_last_error function
      * @param  mixed             $data data that was meant to be encoded
      * @throws \RuntimeException
+     *
+     * @return never
      */
-    private static function throwEncodeError(int $code, $data): never
+    private static function throwEncodeError(int $code, $data): void
     {
-        $msg = match ($code) {
-            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
-            JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
-            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
-            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
-            default => 'Unknown error',
-        };
+        switch ($code) {
+            case JSON_ERROR_DEPTH:
+                $msg = 'Maximum stack depth exceeded';
+                break;
+            case JSON_ERROR_STATE_MISMATCH:
+                $msg = 'Underflow or the modes mismatch';
+                break;
+            case JSON_ERROR_CTRL_CHAR:
+                $msg = 'Unexpected control character found';
+                break;
+            case JSON_ERROR_UTF8:
+                $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+                break;
+            default:
+                $msg = 'Unknown error';
+        }
 
         throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
     }
@@ -196,7 +207,7 @@ final class Utils
      */
     private static function detectAndCleanUtf8(&$data): void
     {
-        if (is_string($data) && preg_match('//u', $data) !== 1) {
+        if (is_string($data) && !preg_match('//u', $data)) {
             $data = preg_replace_callback(
                 '/[\x80-\xFF]+/',
                 function ($m) {
@@ -206,7 +217,6 @@ final class Utils
             );
             if (!is_string($data)) {
                 $pcreErrorCode = preg_last_error();
-
                 throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode));
             }
             $data = str_replace(
@@ -220,8 +230,8 @@ final class Utils
     /**
      * Converts a string with a valid 'memory_limit' format, to bytes.
      *
-     * @param  string|false $val
-     * @return int|false    Returns an integer representing bytes. Returns FALSE in case of error.
+     * @param string|false $val
+     * @return int|false Returns an integer representing bytes. Returns FALSE in case of error.
      */
     public static function expandIniShorthandBytes($val)
     {
@@ -234,7 +244,7 @@ final class Utils
             return (int) $val;
         }
 
-        if (preg_match('/^\s*(?<val>\d+)(?:\.\d+)?\s*(?<unit>[gmk]?)\s*$/i', $val, $match) !== 1) {
+        if (!preg_match('/^\s*(?<val>\d+)(?:\.\d+)?\s*(?<unit>[gmk]?)\s*$/i', $val, $match)) {
             return false;
         }
 
@@ -242,10 +252,8 @@ final class Utils
         switch (strtolower($match['unit'] ?? '')) {
             case 'g':
                 $val *= 1024;
-                // no break
             case 'm':
                 $val *= 1024;
-                // no break
             case 'k':
                 $val *= 1024;
         }
@@ -253,22 +261,24 @@ final class Utils
         return $val;
     }
 
-    public static function getRecordMessageForException(LogRecord $record): string
+    /**
+     * @param array<mixed> $record
+     */
+    public static function getRecordMessageForException(array $record): string
     {
         $context = '';
         $extra = '';
-
         try {
-            if (\count($record->context) > 0) {
-                $context = "\nContext: " . json_encode($record->context, JSON_THROW_ON_ERROR);
+            if ($record['context']) {
+                $context = "\nContext: " . json_encode($record['context']);
             }
-            if (\count($record->extra) > 0) {
-                $extra = "\nExtra: " . json_encode($record->extra, JSON_THROW_ON_ERROR);
+            if ($record['extra']) {
+                $extra = "\nExtra: " . json_encode($record['extra']);
             }
         } catch (\Throwable $e) {
             // noop
         }
 
-        return "\nThe exception occurred while attempting to log: " . $record->message . $context . $extra;
+        return "\nThe exception occurred while attempting to log: " . $record['message'] . $context . $extra;
     }
 }
index 879fc6f53bb5300b2f86596eb0ea0bdd573040f5..ca05695377036e0929399770700c85b237aa67ed 100644 (file)
         }
     ],
     "require": {
-        "php": ">=8.0.0"
+        "php": ">=5.3.0"
     },
     "autoload": {
         "psr-4": {
-            "Psr\\Log\\": "src"
+            "Psr\\Log\\": "Psr/Log/"
         }
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "3.x-dev"
+            "dev-master": "1.1.x-dev"
         }
     }
 }
diff --git a/monolog/vendor/psr/log/src/AbstractLogger.php b/monolog/vendor/psr/log/src/AbstractLogger.php
deleted file mode 100644 (file)
index d60a091..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * This is a simple Logger implementation that other Loggers can inherit from.
- *
- * It simply delegates all log-level-specific methods to the `log` method to
- * reduce boilerplate code that a simple Logger that does the same thing with
- * messages regardless of the error level has to implement.
- */
-abstract class AbstractLogger implements LoggerInterface
-{
-    use LoggerTrait;
-}
diff --git a/monolog/vendor/psr/log/src/InvalidArgumentException.php b/monolog/vendor/psr/log/src/InvalidArgumentException.php
deleted file mode 100644 (file)
index 67f852d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-class InvalidArgumentException extends \InvalidArgumentException
-{
-}
diff --git a/monolog/vendor/psr/log/src/LogLevel.php b/monolog/vendor/psr/log/src/LogLevel.php
deleted file mode 100644 (file)
index 9cebcac..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * Describes log levels.
- */
-class LogLevel
-{
-    const EMERGENCY = 'emergency';
-    const ALERT     = 'alert';
-    const CRITICAL  = 'critical';
-    const ERROR     = 'error';
-    const WARNING   = 'warning';
-    const NOTICE    = 'notice';
-    const INFO      = 'info';
-    const DEBUG     = 'debug';
-}
diff --git a/monolog/vendor/psr/log/src/LoggerAwareInterface.php b/monolog/vendor/psr/log/src/LoggerAwareInterface.php
deleted file mode 100644 (file)
index cc46a95..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * Describes a logger-aware instance.
- */
-interface LoggerAwareInterface
-{
-    /**
-     * Sets a logger instance on the object.
-     *
-     * @param LoggerInterface $logger
-     *
-     * @return void
-     */
-    public function setLogger(LoggerInterface $logger): void;
-}
diff --git a/monolog/vendor/psr/log/src/LoggerAwareTrait.php b/monolog/vendor/psr/log/src/LoggerAwareTrait.php
deleted file mode 100644 (file)
index 4fb57a2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * Basic Implementation of LoggerAwareInterface.
- */
-trait LoggerAwareTrait
-{
-    /**
-     * The logger instance.
-     *
-     * @var LoggerInterface|null
-     */
-    protected ?LoggerInterface $logger = null;
-
-    /**
-     * Sets a logger.
-     *
-     * @param LoggerInterface $logger
-     */
-    public function setLogger(LoggerInterface $logger): void
-    {
-        $this->logger = $logger;
-    }
-}
diff --git a/monolog/vendor/psr/log/src/LoggerInterface.php b/monolog/vendor/psr/log/src/LoggerInterface.php
deleted file mode 100644 (file)
index b3a24b5..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * Describes a logger instance.
- *
- * The message MUST be a string or object implementing __toString().
- *
- * The message MAY contain placeholders in the form: {foo} where foo
- * will be replaced by the context data in key "foo".
- *
- * The context array can contain arbitrary data. The only assumption that
- * can be made by implementors is that if an Exception instance is given
- * to produce a stack trace, it MUST be in a key named "exception".
- *
- * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
- * for the full interface specification.
- */
-interface LoggerInterface
-{
-    /**
-     * System is unusable.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function emergency(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Action must be taken immediately.
-     *
-     * Example: Entire website down, database unavailable, etc. This should
-     * trigger the SMS alerts and wake you up.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function alert(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Critical conditions.
-     *
-     * Example: Application component unavailable, unexpected exception.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function critical(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Runtime errors that do not require immediate action but should typically
-     * be logged and monitored.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function error(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Exceptional occurrences that are not errors.
-     *
-     * Example: Use of deprecated APIs, poor use of an API, undesirable things
-     * that are not necessarily wrong.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function warning(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Normal but significant events.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function notice(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Interesting events.
-     *
-     * Example: User logs in, SQL logs.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function info(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Detailed debug information.
-     *
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     */
-    public function debug(string|\Stringable $message, array $context = []): void;
-
-    /**
-     * Logs with an arbitrary level.
-     *
-     * @param mixed   $level
-     * @param string|\Stringable $message
-     * @param mixed[] $context
-     *
-     * @return void
-     *
-     * @throws \Psr\Log\InvalidArgumentException
-     */
-    public function log($level, string|\Stringable $message, array $context = []): void;
-}
diff --git a/monolog/vendor/psr/log/src/LoggerTrait.php b/monolog/vendor/psr/log/src/LoggerTrait.php
deleted file mode 100644 (file)
index 9c8733f..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * This is a simple Logger trait that classes unable to extend AbstractLogger
- * (because they extend another class, etc) can include.
- *
- * It simply delegates all log-level-specific methods to the `log` method to
- * reduce boilerplate code that a simple Logger that does the same thing with
- * messages regardless of the error level has to implement.
- */
-trait LoggerTrait
-{
-    /**
-     * System is unusable.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function emergency(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::EMERGENCY, $message, $context);
-    }
-
-    /**
-     * Action must be taken immediately.
-     *
-     * Example: Entire website down, database unavailable, etc. This should
-     * trigger the SMS alerts and wake you up.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function alert(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::ALERT, $message, $context);
-    }
-
-    /**
-     * Critical conditions.
-     *
-     * Example: Application component unavailable, unexpected exception.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function critical(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::CRITICAL, $message, $context);
-    }
-
-    /**
-     * Runtime errors that do not require immediate action but should typically
-     * be logged and monitored.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function error(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::ERROR, $message, $context);
-    }
-
-    /**
-     * Exceptional occurrences that are not errors.
-     *
-     * Example: Use of deprecated APIs, poor use of an API, undesirable things
-     * that are not necessarily wrong.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function warning(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::WARNING, $message, $context);
-    }
-
-    /**
-     * Normal but significant events.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function notice(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::NOTICE, $message, $context);
-    }
-
-    /**
-     * Interesting events.
-     *
-     * Example: User logs in, SQL logs.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function info(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::INFO, $message, $context);
-    }
-
-    /**
-     * Detailed debug information.
-     *
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     */
-    public function debug(string|\Stringable $message, array $context = []): void
-    {
-        $this->log(LogLevel::DEBUG, $message, $context);
-    }
-
-    /**
-     * Logs with an arbitrary level.
-     *
-     * @param mixed  $level
-     * @param string|\Stringable $message
-     * @param array  $context
-     *
-     * @return void
-     *
-     * @throws \Psr\Log\InvalidArgumentException
-     */
-    abstract public function log($level, string|\Stringable $message, array $context = []): void;
-}
diff --git a/monolog/vendor/psr/log/src/NullLogger.php b/monolog/vendor/psr/log/src/NullLogger.php
deleted file mode 100644 (file)
index c1cc3c0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace Psr\Log;
-
-/**
- * This Logger can be used to avoid conditional log calls.
- *
- * Logging should always be optional, and if no logger is provided to your
- * library creating a NullLogger instance to have something to throw logs at
- * is a good way to avoid littering your code with `if ($this->logger) { }`
- * blocks.
- */
-class NullLogger extends AbstractLogger
-{
-    /**
-     * Logs with an arbitrary level.
-     *
-     * @param mixed  $level
-     * @param string|\Stringable $message
-     * @param array $context
-     *
-     * @return void
-     *
-     * @throws \Psr\Log\InvalidArgumentException
-     */
-    public function log($level, string|\Stringable $message, array $context = []): void
-    {
-        // noop
-    }
-}