From bd79504f1ee054855313df7d653f298f5060a0b0 Mon Sep 17 00:00:00 2001 From: Kris Buist Date: Wed, 15 Nov 2017 21:38:49 +0100 Subject: [PATCH 001/498] Add a ThresholdHandler This handler can be used to not let any messages from a certain lever through, unless they cross a configured threshold. This is useful together with, for example, a MailHandler when some batch processing is done and you're only interested in major failure and not a minor one. --- doc/02-handlers-formatters-processors.md | 4 + src/Monolog/Handler/ThresholdHandler.php | 127 ++++++++++++++++++ .../Monolog/Handler/ThresholdHandlerTest.php | 108 +++++++++++++++ 3 files changed, 239 insertions(+) create mode 100644 src/Monolog/Handler/ThresholdHandler.php create mode 100644 tests/Monolog/Handler/ThresholdHandlerTest.php diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 9987908c1..aeb77efd5 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -125,6 +125,10 @@ has accessors to read out the information. - [_HandlerWrapper_](../src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create your own wrappers easily. +- [_ThresholdHandler_](../src/Monolog/Handler/ThresholdHandler.php): This handler will buffer all the log messages it + receives, up until a configured threshold is reached, after it will pass all log messages to the wrapped handler. + Useful for applying in bath processing when you're only interested in significant failures instead of minor, single + erroneous events. ## Formatters diff --git a/src/Monolog/Handler/ThresholdHandler.php b/src/Monolog/Handler/ThresholdHandler.php new file mode 100644 index 000000000..2b0949daf --- /dev/null +++ b/src/Monolog/Handler/ThresholdHandler.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + + +/** + * Handler to only pass log messages when a certain threshold of messages is reached. + * + * This can be useful in cases of processing a batch of data, but you're for example only interested + * in case it fails catastrophically instead of a warning for 1 or 2 events. Worse things can happen, right? + * + * Usage example: + * + * ``` + * $log = new Logger('application'); + * $handler = new SomeHandler(...) + * + * // Pass all warnings to the handler when more than 10 & all error messages when more then 5 + * $threshold = new ThresholdHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); + * + * $log->pushHandler($threshold); + *``` + * + * @author Kris Buist + */ +class ThresholdHandler extends AbstractHandler +{ + /** @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 $buffer = []; + + /** + * @param HandlerInterface $handler + * @param int[] $thresholdMap Dictionary of logger level => threshold + * @param int $level + * @param bool $bubble + */ + public function __construct( + HandlerInterface $handler, + array $thresholdMap = [], + int $level = Logger::DEBUG, + bool $bubble = true + ) { + $this->handler = $handler; + foreach ($thresholdMap as $thresholdLevel => $threshold) { + $this->thresholdMap[$thresholdLevel] = $threshold; + } + parent::__construct($level, $bubble); + } + + /** + * Handles a record. + * + * All records may be passed to this method, and the handler should discard + * those that it does not want to handle. + * + * The return value of this function controls the bubbling process of the handler stack. + * 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 array $record The record to handle + * + * @return Boolean 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. + */ + public function handle(array $record): bool + { + if ($record['level'] < $this->level) { + return false; + } + + $level = $record['level']; + + if (!isset($this->thresholdMap[$level])) { + $this->thresholdMap[$level] = 0; + } + + if ($this->thresholdMap[$level] > 0) { + // The threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 + $this->thresholdMap[$level]--; + $this->buffer[$level][] = $record; + return false === $this->bubble; + } + + if ($this->thresholdMap[$level] == 0) { + // This current message is breaking the threshold. Flush the buffer and continue handling the current record + foreach ($this->buffer[$level] ?? [] as $buffered) { + $this->handler->handle($buffered); + } + $this->thresholdMap[$level]--; + unset($this->buffer[$level]); + } + + $this->handler->handle($record); + + return false === $this->bubble; + } +} diff --git a/tests/Monolog/Handler/ThresholdHandlerTest.php b/tests/Monolog/Handler/ThresholdHandlerTest.php new file mode 100644 index 000000000..4ad555d12 --- /dev/null +++ b/tests/Monolog/Handler/ThresholdHandlerTest.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Test\TestCase; + +/** + * @author Kris Buist + * @covers \Monolog\Handler\ThresholdHandler + */ +class ThresholdHandlerTest extends TestCase +{ + public function testNotPassingRecordsBeneathLogLevel() + { + $testHandler = new TestHandler(); + $handler = new ThresholdHandler($testHandler, [], Logger::INFO); + $handler->handle($this->getRecord(Logger::DEBUG)); + $this->assertFalse($testHandler->hasDebugRecords()); + } + + public function testPassThroughWithoutThreshold() + { + $testHandler = new TestHandler(); + $handler = new ThresholdHandler($testHandler, [], Logger::INFO); + + $handler->handle($this->getRecord(Logger::INFO, 'Info 1')); + $handler->handle($this->getRecord(Logger::INFO, 'Info 2')); + $handler->handle($this->getRecord(Logger::WARNING, 'Warning 1')); + + $this->assertTrue($testHandler->hasInfoThatContains('Info 1')); + $this->assertTrue($testHandler->hasInfoThatContains('Info 2')); + $this->assertTrue($testHandler->hasWarningThatContains('Warning 1')); + } + + /** + * @test + */ + public function testHoldingMessagesBeneathThreshold() + { + $testHandler = new TestHandler(); + $handler = new ThresholdHandler($testHandler, [Logger::INFO => 3]); + + $handler->handle($this->getRecord(Logger::DEBUG, 'debug 1')); + $handler->handle($this->getRecord(Logger::DEBUG, 'debug 2')); + + foreach (range(1, 3) as $i) { + $handler->handle($this->getRecord(Logger::INFO, 'info ' . $i)); + } + + $this->assertTrue($testHandler->hasDebugThatContains('debug 1')); + $this->assertTrue($testHandler->hasDebugThatContains('debug 2')); + $this->assertFalse($testHandler->hasInfoRecords()); + + $handler->handle($this->getRecord(Logger::INFO, 'info 4')); + + foreach (range(1, 4) as $i) { + $this->assertTrue($testHandler->hasInfoThatContains('info ' . $i)); + } + } + + /** + * @test + */ + public function testCombinedThresholds() + { + $testHandler = new TestHandler(); + $handler = new ThresholdHandler($testHandler, [Logger::INFO => 5, Logger::WARNING => 10]); + + $handler->handle($this->getRecord(Logger::DEBUG)); + + foreach (range(1, 5) as $i) { + $handler->handle($this->getRecord(Logger::INFO, 'info ' . $i)); + } + + foreach (range(1, 10) as $i) { + $handler->handle($this->getRecord(Logger::WARNING, 'warning ' . $i)); + } + + // Only 1 DEBUG records + $this->assertCount(1, $testHandler->getRecords()); + + $handler->handle($this->getRecord(Logger::INFO, 'info final')); + + // 1 DEBUG + 5 buffered INFO + 1 new INFO + $this->assertCount(7, $testHandler->getRecords()); + + $handler->handle($this->getRecord(Logger::WARNING, 'warning final')); + + // 1 DEBUG + 6 INFO + 10 buffered WARNING + 1 new WARNING + $this->assertCount(18, $testHandler->getRecords()); + + $handler->handle($this->getRecord(Logger::INFO, 'Another info')); + $handler->handle($this->getRecord(Logger::WARNING, 'Anther warning')); + + // 1 DEBUG + 6 INFO + 11 WARNING + 1 new INFO + 1 new WARNING + $this->assertCount(20, $testHandler->getRecords()); + } +} From cf979844dc722552283487f1086d651d4f6b31c0 Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Thu, 22 Feb 2018 11:16:36 -0600 Subject: [PATCH 002/498] Register signal handlers --- doc/03-utilities.md | 3 +- src/Monolog/ErrorHandler.php | 80 ++++++++- tests/Monolog/ErrorHandlerTest.php | 267 ++++++++++++++++++++++++++++- 3 files changed, 347 insertions(+), 3 deletions(-) diff --git a/doc/03-utilities.md b/doc/03-utilities.md index c62aa4161..513d08aae 100644 --- a/doc/03-utilities.md +++ b/doc/03-utilities.md @@ -4,7 +4,8 @@ can then statically access from anywhere. It is not really a best practice but can help in some older codebases or for ease of use. - _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register - a Logger instance as an exception handler, error handler or fatal error handler. + a Logger instance as an exception handler, error handler, fatal error handler or + signal handler. - _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log level is reached. - _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 7bfcd833a..e60410559 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -14,11 +14,12 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Monolog\Handler\AbstractHandler; +use ReflectionExtension; /** * Monolog error handler * - * A facility to enable logging of runtime errors, exceptions and fatal errors. + * A facility to enable logging of runtime errors, exceptions, fatal errors and signals. * * Quick setup: ErrorHandler::register($logger); * @@ -40,6 +41,10 @@ class ErrorHandler private $reservedMemory; private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); + private $previousSignalHandler = array(); + private $signalLevelMap = array(); + private $signalRestartSyscalls = array(); + public function __construct(LoggerInterface $logger) { $this->logger = $logger; @@ -104,6 +109,37 @@ public function registerFatalHandler($level = null, $reservedMemorySize = 20) $this->hasFatalErrorHandler = true; } + public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) + { + if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { + return $this; + } + + if ($callPrevious) { + if (function_exists('pcntl_signal_get_handler')) { + $handler = pcntl_signal_get_handler($signo); + if ($handler === false) { + return $this; + } + $this->previousSignalHandler[$signo] = $handler; + } else { + $this->previousSignalHandler[$signo] = true; + } + } else { + unset($this->previousSignalHandler[$signo]); + } + $this->signalLevelMap[$signo] = $level; + $this->signalRestartSyscalls[$signo] = $restartSyscalls; + + if (function_exists('pcntl_async_signals') && $async !== null) { + pcntl_async_signals($async); + } + + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + + return $this; + } + protected function defaultErrorLevelMap() { return array( @@ -190,6 +226,48 @@ public function handleFatalError() } } + public function handleSignal($signo, array $siginfo = null) + { + static $signals = array(); + + if (!$signals && extension_loaded('pcntl')) { + $pcntl = new ReflectionExtension('pcntl'); + foreach ($pcntl->getConstants() as $name => $value) { + if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_') { + $signals[$value] = $name; + } + } + } + + $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; + $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; + $context = isset($siginfo) ? $siginfo : array(); + $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); + + if (!isset($this->previousSignalHandler[$signo])) { + return; + } + + if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') + && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { + $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; + pcntl_signal($signo, SIG_DFL, $restartSyscalls); + pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + pcntl_sigprocmask(SIG_SETMASK, $oldset); + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + } + } elseif (is_callable($this->previousSignalHandler[$signo])) { + if (PHP_VERSION >= 71000) { + $this->previousSignalHandler[$signo]($signo, $siginfo); + } else { + $this->previousSignalHandler[$signo]($signo); + } + } + } + private static function codeToString($code) { switch ($code) { diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index a9a3f301f..d444dcde8 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -11,10 +11,55 @@ namespace Monolog; +use Monolog\Handler\StreamHandler; use Monolog\Handler\TestHandler; +use Psr\Log\LogLevel; -class ErrorHandlerTest extends \PHPUnit_Framework_TestCase +class ErrorHandlerTest extends TestCase { + + private $asyncSignalHandling; + private $blockedSignals; + private $signalHandlers; + + protected function setUp() + { + $this->signalHandlers = array(); + if (extension_loaded('pcntl')) { + if (function_exists('pcntl_async_signals')) { + $this->asyncSignalHandling = pcntl_async_signals(); + } + if (function_exists('pcntl_sigprocmask')) { + pcntl_sigprocmask(SIG_BLOCK, array(), $this->blockedSignals); + } + } + } + + protected function tearDown() + { + if ($this->asyncSignalHandling !== null) { + pcntl_async_signals($this->asyncSignalHandling); + } + if ($this->blockedSignals !== null) { + pcntl_sigprocmask(SIG_SETMASK, $this->blockedSignals); + } + if ($this->signalHandlers) { + pcntl_signal_dispatch(); + foreach ($this->signalHandlers as $signo => $handler) { + pcntl_signal($signo, $handler); + } + } + } + + private function setSignalHandler($signo, $handler = SIG_DFL) { + if (function_exists('pcntl_signal_get_handler')) { + $this->signalHandlers[$signo] = pcntl_signal_get_handler($signo); + } else { + $this->signalHandlers[$signo] = SIG_DFL; + } + $this->assertTrue(pcntl_signal($signo, $handler)); + } + public function testHandleError() { $logger = new Logger('test', array($handler = new TestHandler)); @@ -28,4 +73,224 @@ public function testHandleError() $this->assertCount(2, $handler->getRecords()); $this->assertTrue($handler->hasEmergencyRecords()); } + + public function testHandleSignal() + { + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + $signo = 2; // SIGINT. + $siginfo = array('signo' => $signo, 'errno' => 0, 'code' => 0); + $errHandler->handleSignal($signo, $siginfo); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasCriticalRecords()); + $records = $handler->getRecords(); + $this->assertSame($siginfo, $records[0]['context']); + } + + /** + * @depends testHandleSignal + * @requires extension pcntl + * @requires extension posix + * @requires function pcntl_signal + * @requires function pcntl_signal_dispatch + * @requires function posix_getpid + * @requires function posix_kill + */ + public function testRegisterSignalHandler() + { + // SIGCONT and SIGURG should be ignored by default. + if (!defined('SIGCONT') || !defined('SIGURG')) { + $this->markTestSkipped('This test requires the SIGCONT and SIGURG pcntl constants.'); + } + + $this->setSignalHandler(SIGCONT, SIG_IGN); + $this->setSignalHandler(SIGURG, SIG_IGN); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + $pid = posix_getpid(); + + $this->assertTrue(posix_kill($pid, SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(0, $handler->getRecords()); + + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, false); + + $this->assertTrue(posix_kill($pid, SIGCONT)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(0, $handler->getRecords()); + + $this->assertTrue(posix_kill($pid, SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasInfoThatContains('SIGURG')); + } + + /** + * @dataProvider defaultPreviousProvider + * @depends testRegisterSignalHandler + * @requires function pcntl_fork + * @requires function pcntl_sigprocmask + * @requires function pcntl_wait + */ + public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected) + { + $this->setSignalHandler($signo, SIG_DFL); + + $path = tempnam(sys_get_temp_dir(), 'monolog-'); + $this->assertNotFalse($path); + + $pid = pcntl_fork(); + if ($pid === 0) { // Child. + $streamHandler = new StreamHandler($path); + $streamHandler->setFormatter($this->getIdentityFormatter()); + $logger = new Logger('test', array($streamHandler)); + $errHandler = new ErrorHandler($logger); + $errHandler->registerSignalHandler($signo, LogLevel::INFO, $callPrevious, false, false); + pcntl_sigprocmask(SIG_SETMASK, array(SIGCONT)); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + // If $callPrevious is true, SIGINT should terminate by this line. + pcntl_sigprocmask(SIG_BLOCK, array(), $oldset); + file_put_contents($path, implode(' ', $oldset), FILE_APPEND); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + exit(); + } + + $this->assertNotSame(-1, $pid); + $this->assertNotSame(-1, pcntl_wait($status)); + $this->assertNotSame(-1, $status); + $this->assertSame($expected, file_get_contents($path)); + } + + public function defaultPreviousProvider() + { + if (!defined('SIGCONT') || !defined('SIGINT') || !defined('SIGURG')) { + return array(); + } + + return array( + array(SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'), + array(SIGINT, true, 'Program received signal SIGINT'), + array(SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), + array(SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), + ); + } + + /** + * @depends testRegisterSignalHandler + * @requires function pcntl_signal_get_handler + */ + public function testRegisterCallablePreviousSignalHandler($callPrevious) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + $previousCalled = 0; + pcntl_signal(SIGURG, function ($signo, array $siginfo = null) use (&$previousCalled) { + ++$previousCalled; + }); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, $callPrevious, false, false); + $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasInfoThatContains('SIGURG')); + $this->assertSame($callPrevious ? 1 : 0, $previousCalled); + } + + public function callablePreviousProvider() + { + return array( + array(false), + array(true), + ); + } + + /** + * @dataProvider restartSyscallsProvider + * @depends testRegisterDefaultPreviousSignalHandler + * @requires function pcntl_fork + * @requires function pcntl_wait + */ + public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + + $parentPid = posix_getpid(); + $microtime = microtime(true); + + $pid = pcntl_fork(); + if ($pid === 0) { // Child. + usleep(100000); + posix_kill($parentPid, SIGURG); + usleep(100000); + exit(); + } + + $this->assertNotSame(-1, $pid); + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false); + if ($restartSyscalls) { + // pcntl_wait is expected to be restarted after the signal handler. + $this->assertNotSame(-1, pcntl_wait($status)); + } else { + // pcntl_wait is expected to be interrupted when the signal handler is invoked. + $this->assertSame(-1, pcntl_wait($status)); + } + $this->assertSame($restartSyscalls, microtime(true) - $microtime > 0.15); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + if ($restartSyscalls) { + // The child has already exited. + $this->assertSame(-1, pcntl_wait($status)); + } else { + // The child has not exited yet. + $this->assertNotSame(-1, pcntl_wait($status)); + } + } + + public function restartSyscallsProvider() + { + return array( + array(false), + array(true), + array(false), + array(true), + ); + } + + /** + * @dataProvider asyncProvider + * @depends testRegisterDefaultPreviousSignalHandler + * @requires function pcntl_async_signals + */ + public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $expectedBefore, $expectedAfter) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + pcntl_async_signals($initialAsync); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new ErrorHandler($logger); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, $desiredAsync); + $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); + $this->assertCount($expectedBefore, $handler->getRecords()); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount($expectedAfter, $handler->getRecords()); + } + + public function asyncProvider() + { + return array( + array(false, false, 0, 1), + array(false, null, 0, 1), + array(false, true, 1, 1), + array(true, false, 0, 1), + array(true, null, 1, 1), + array(true, true, 1, 1), + ); + } + } From 4fea44bf962b857d308fff371212949fa7df8dde Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Thu, 22 Feb 2018 13:48:30 -0600 Subject: [PATCH 003/498] Fix the reflection of constants in HHVM --- src/Monolog/ErrorHandler.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index e60410559..f0ff3d8ca 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -232,11 +232,18 @@ public function handleSignal($signo, array $siginfo = null) if (!$signals && extension_loaded('pcntl')) { $pcntl = new ReflectionExtension('pcntl'); - foreach ($pcntl->getConstants() as $name => $value) { - if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_') { + $constants = $pcntl->getConstants(); + if (!$constants) { + // HHVM 3.24.2 returns an empty array. + $constants = get_defined_constants(true); + $constants = $constants['Core']; + } + foreach ($constants as $name => $value) { + if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { $signals[$value] = $name; } } + unset($constants); } $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; From f5696399f881e75dc62a6bbae35f471cd4430a67 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 02:45:53 +0400 Subject: [PATCH 004/498] Add elasticsearch client to dev dependency --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bc87c44c8..7cfc82c0c 100644 --- a/composer.json +++ b/composer.json @@ -28,13 +28,15 @@ "php-console/php-console": "^3.1.3", "jakub-onderka/php-parallel-lint": "^0.9", "predis/predis": "^1.1", - "phpspec/prophecy": "^1.6.1" + "phpspec/prophecy": "^1.6.1", + "elasticsearch/elasticsearch": "^6.0" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "sentry/sentry": "Allow sending log messages to a Sentry server", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elastic Search server via official client", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", From 57f3ca17917205c3663c420aec77f93b410134d0 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 02:53:11 +0400 Subject: [PATCH 005/498] Rename Elastica handler for naming consistency --- ...cSearchHandler.php => ElasticaHandler.php} | 6 +-- ...andlerTest.php => ElasticaHandlerTest.php} | 42 +++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) rename src/Monolog/Handler/{ElasticSearchHandler.php => ElasticaHandler.php} (93%) rename tests/Monolog/Handler/{ElasticSearchHandlerTest.php => ElasticaHandlerTest.php} (81%) diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticaHandler.php similarity index 93% rename from src/Monolog/Handler/ElasticSearchHandler.php rename to src/Monolog/Handler/ElasticaHandler.php index fbb999fd1..a2c236770 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -27,13 +27,13 @@ * 'index' => 'elastic_index_name', * 'type' => 'elastic_doc_type', * ); - * $handler = new ElasticSearchHandler($client, $options); + * $handler = new ElasticaHandler($client, $options); * $log = new Logger('application'); * $log->pushHandler($handler); * * @author Jelle Vink */ -class ElasticSearchHandler extends AbstractProcessingHandler +class ElasticaHandler extends AbstractProcessingHandler { /** * @var Client @@ -81,7 +81,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface if ($formatter instanceof ElasticaFormatter) { return parent::setFormatter($formatter); } - throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter'); + throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); } /** diff --git a/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php similarity index 81% rename from tests/Monolog/Handler/ElasticSearchHandlerTest.php rename to tests/Monolog/Handler/ElasticaHandlerTest.php index e0e207db6..fb64e6574 100644 --- a/tests/Monolog/Handler/ElasticSearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -19,7 +19,7 @@ use Elastica\Request; use Elastica\Response; -class ElasticSearchHandlerTest extends TestCase +class ElasticaHandlerTest extends TestCase { /** * @var Client mock @@ -49,10 +49,10 @@ public function setUp() } /** - * @covers Monolog\Handler\ElasticSearchHandler::write - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + * @covers Monolog\Handler\ElasticaHandler::write + * @covers Monolog\Handler\ElasticaHandler::handleBatch + * @covers Monolog\Handler\ElasticaHandler::bulkSend + * @covers Monolog\Handler\ElasticaHandler::getDefaultFormatter */ public function testHandle() { @@ -77,17 +77,17 @@ public function testHandle() ->with($expected); // perform tests - $handler = new ElasticSearchHandler($this->client, $this->options); + $handler = new ElasticaHandler($this->client, $this->options); $handler->handle($msg); $handler->handleBatch([$msg]); } /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @covers Monolog\Handler\ElasticaHandler::setFormatter */ public function testSetFormatter() { - $handler = new ElasticSearchHandler($this->client); + $handler = new ElasticaHandler($this->client); $formatter = new ElasticaFormatter('index_new', 'type_new'); $handler->setFormatter($formatter); $this->assertInstanceOf('Monolog\Formatter\ElasticaFormatter', $handler->getFormatter()); @@ -96,20 +96,20 @@ public function testSetFormatter() } /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @covers Monolog\Handler\ElasticaHandler::setFormatter * @expectedException InvalidArgumentException - * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticaFormatter + * @expectedExceptionMessage ElasticaHandler is only compatible with ElasticaFormatter */ public function testSetFormatterInvalid() { - $handler = new ElasticSearchHandler($this->client); + $handler = new ElasticaHandler($this->client); $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); } /** - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::getOptions + * @covers Monolog\Handler\ElasticaHandler::__construct + * @covers Monolog\Handler\ElasticaHandler::getOptions */ public function testOptions() { @@ -118,12 +118,12 @@ public function testOptions() 'type' => $this->options['type'], 'ignore_error' => false, ]; - $handler = new ElasticSearchHandler($this->client, $this->options); + $handler = new ElasticaHandler($this->client, $this->options); $this->assertEquals($expected, $handler->getOptions()); } /** - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticaHandler::bulkSend * @dataProvider providerTestConnectionErrors */ public function testConnectionErrors($ignore, $expectedError) @@ -131,7 +131,7 @@ public function testConnectionErrors($ignore, $expectedError) $clientOpts = ['host' => '127.0.0.1', 'port' => 1]; $client = new Client($clientOpts); $handlerOpts = ['ignore_error' => $ignore]; - $handler = new ElasticSearchHandler($client, $handlerOpts); + $handler = new ElasticaHandler($client, $handlerOpts); if ($expectedError) { $this->expectException($expectedError[0]); @@ -156,10 +156,10 @@ public function providerTestConnectionErrors() /** * Integration test using localhost Elastic Search server * - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + * @covers Monolog\Handler\ElasticaHandler::__construct + * @covers Monolog\Handler\ElasticaHandler::handleBatch + * @covers Monolog\Handler\ElasticaHandler::bulkSend + * @covers Monolog\Handler\ElasticaHandler::getDefaultFormatter */ public function testHandleIntegration() { @@ -182,7 +182,7 @@ public function testHandleIntegration() ]; $client = new Client(); - $handler = new ElasticSearchHandler($client, $this->options); + $handler = new ElasticaHandler($client, $this->options); try { $handler->handleBatch([$msg]); } catch (\RuntimeException $e) { From 32563c49b75636465c5fc69ebe94b01202c3b88b Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 03:10:46 +0400 Subject: [PATCH 006/498] Add elastic search formatter --- .../Formatter/ElasticSearchFormatter.php | 87 +++++++++++++++++++ .../Formatter/ElasticSearchFormatterTest.php | 70 +++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/Monolog/Formatter/ElasticSearchFormatter.php create mode 100644 tests/Monolog/Formatter/ElasticSearchFormatterTest.php diff --git a/src/Monolog/Formatter/ElasticSearchFormatter.php b/src/Monolog/Formatter/ElasticSearchFormatter.php new file mode 100644 index 000000000..1ac9d2c7e --- /dev/null +++ b/src/Monolog/Formatter/ElasticSearchFormatter.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Format a log message into an ElasticSearch record + * + * @author Avtandil Kikabidze + */ +class ElasticSearchFormatter extends NormalizerFormatter +{ + /** + * @var string ElasticSearch index name + */ + protected $index; + + /** + * @var string ElasticSearch record type + */ + protected $type; + + /** + * @param string $index ElasticSearch index name + * @param string $type ElasticSearch record type + */ + public function __construct($index, $type) + { + // ElasticSearch requires an ISO 8601 format date with optional millisecond precision. + parent::__construct('Y-m-d\TH:i:s.uP'); + + $this->index = $index; + $this->type = $type; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $record = parent::format($record); + + return $this->getDocument($record); + } + + /** + * Getter index + * + * @return string + */ + public function getIndex(): string + { + return $this->index; + } + + /** + * Getter type + * + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * Convert a log message into an ElasticSearch record + * + * @param array $record Log message + * @return array + */ + protected function getDocument($record): array + { + $record['_index'] = $this->index; + $record['_type'] = $this->type; + + return $record; + } +} diff --git a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php new file mode 100644 index 000000000..74a66bd6f --- /dev/null +++ b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Logger; + +class ElasticSearchFormatterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @covers Monolog\Formatter\ElasticSearchFormatter::__construct + * @covers Monolog\Formatter\ElasticSearchFormatter::format + * @covers Monolog\Formatter\ElasticSearchFormatter::getDocument + */ + public function testFormat() + { + // Test log message + $msg = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => [], + 'message' => 'log', + ]; + + // Expected values + $expected = $msg; + $expected['datetime'] = '1970-01-01T00:00:00.000000+00:00'; + $expected['context'] = [ + 'class' => ['stdClass' => []], + 'foo' => 7, + 0 => 'bar', + ]; + + // Format log message + $formatter = new ElasticSearchFormatter('my_index', 'doc_type'); + $doc = $formatter->format($msg); + $this->assertInternalType('array', $doc); + + // Record parameters + $this->assertEquals('my_index', $doc['_index']); + $this->assertEquals('doc_type', $doc['_type']); + + // Record data values + foreach (array_keys($expected) as $key) { + $this->assertEquals($expected[$key], $doc[$key]); + } + } + + /** + * @covers Monolog\Formatter\ElasticSearchFormatter::getIndex + * @covers Monolog\Formatter\ElasticSearchFormatter::getType + */ + public function testGetters() + { + $formatter = new ElasticaFormatter('my_index', 'doc_type'); + $this->assertEquals('my_index', $formatter->getIndex()); + $this->assertEquals('doc_type', $formatter->getType()); + } +} From 1e4b86d2284d49609068e803a5a0272822aff80e Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 03:50:12 +0400 Subject: [PATCH 007/498] Use ISO 8601 date constant --- src/Monolog/Formatter/ElasticSearchFormatter.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/ElasticSearchFormatter.php b/src/Monolog/Formatter/ElasticSearchFormatter.php index 1ac9d2c7e..56e4d2e4f 100644 --- a/src/Monolog/Formatter/ElasticSearchFormatter.php +++ b/src/Monolog/Formatter/ElasticSearchFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use DateTime; + /** * Format a log message into an ElasticSearch record * @@ -35,7 +37,7 @@ class ElasticSearchFormatter extends NormalizerFormatter public function __construct($index, $type) { // ElasticSearch requires an ISO 8601 format date with optional millisecond precision. - parent::__construct('Y-m-d\TH:i:s.uP'); + parent::__construct(DateTime::ISO8601); $this->index = $index; $this->type = $type; From ca326c4831ac73094cceabb8ec33ebbd74171d13 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 03:56:17 +0400 Subject: [PATCH 008/498] Fix class name --- tests/Monolog/Formatter/ElasticSearchFormatterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php index 74a66bd6f..aefdbd00b 100644 --- a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php @@ -63,7 +63,7 @@ public function testFormat() */ public function testGetters() { - $formatter = new ElasticaFormatter('my_index', 'doc_type'); + $formatter = new ElasticSearchFormatter('my_index', 'doc_type'); $this->assertEquals('my_index', $formatter->getIndex()); $this->assertEquals('doc_type', $formatter->getType()); } From 3bbdf5868bd6f35b3ae3c60792830d8d3699762e Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:11:03 +0400 Subject: [PATCH 009/498] Use right format for date --- tests/Monolog/Formatter/ElasticSearchFormatterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php index aefdbd00b..ee95191c4 100644 --- a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticSearchFormatterTest.php @@ -35,7 +35,7 @@ public function testFormat() // Expected values $expected = $msg; - $expected['datetime'] = '1970-01-01T00:00:00.000000+00:00'; + $expected['datetime'] = '1970-01-01T00:00:00+0000'; $expected['context'] = [ 'class' => ['stdClass' => []], 'foo' => 7, From 1d006d80cb1d8cea885aae5c617e13ac6c6fa225 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:11:26 +0400 Subject: [PATCH 010/498] Add official ElasticSearch handler --- src/Monolog/Handler/ElasticSearchHandler.php | 158 +++++++++++ .../Handler/ElasticSearchHandlerTest.php | 266 ++++++++++++++++++ 2 files changed, 424 insertions(+) create mode 100644 src/Monolog/Handler/ElasticSearchHandler.php create mode 100644 tests/Monolog/Handler/ElasticSearchHandlerTest.php diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php new file mode 100644 index 000000000..d465438aa --- /dev/null +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Elasticsearch\Client; +use Elasticsearch\Common\Exceptions\RuntimeException as ElasticSearchRuntimeException; +use Exception; +use InvalidArgumentException; +use Monolog\Formatter\ElasticSearchFormatter; +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; +use RuntimeException; + +/** + * Elastic Search handler + * + * @link https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html + * + * Simple usage example: + * + * $client = \ElasticSearch\ClientBuilder::create() + * ->setHosts($hosts) + * ->build(); + * + * $options = array( + * 'index' => 'elastic_index_name', + * 'type' => 'elastic_doc_type', + * ); + * $handler = new ElasticSearchHandler($client, $options); + * $log = new Logger('application'); + * $log->pushHandler($handler); + * + * @author Avtandil Kikabidze + */ +class ElasticSearchHandler extends AbstractProcessingHandler +{ + /** + * @var \Elasticsearch\Client + */ + protected $client; + + /** + * @var array Handler config options + */ + protected $options = []; + + /** + * @param \Elasticsearch\Client $client ElasticSearch Client object + * @param array $options Handler configuration + * @param int $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + $this->client = $client; + $this->options = array_merge( + [ + 'index' => 'monolog', // Elastic index name + 'type' => 'record', // Elastic document type + 'ignore_error' => false, // Suppress ElasticSearch exceptions + ], + $options + ); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $this->bulkSend([$record['formatted']]); + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + if ($formatter instanceof ElasticSearchFormatter) { + return parent::setFormatter($formatter); + } + throw new InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticSearchFormatter'); + } + + /** + * Getter options + * + * @return array + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new ElasticSearchFormatter($this->options['index'], $this->options['type']); + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + $documents = $this->getFormatter()->formatBatch($records); + $this->bulkSend($documents); + } + + /** + * Use ElasticSearch bulk API to send list of documents + * + * @param array $records + * @throws \RuntimeException + */ + protected function bulkSend(array $records) + { + try { + $params = [ + 'body' => [], + ]; + + foreach ($records as $record) { + $params['body'][] = [ + 'index' => [ + '_index' => $record['_index'], + '_type' => $record['_type'], + ], + ]; + unset($record['_index'], $record['_type']); + + $params['body'][] = $record; + } + + $responses = $this->client->bulk($params); + + if ($responses['errors'] === true) { + throw new ElasticSearchRuntimeException('ElasticSearch returned error for one of the records'); + } + } catch (Exception $e) { + if (! $this->options['ignore_error']) { + throw new RuntimeException('Error sending messages to ElasticSearch', 0, $e); + } + } + } +} diff --git a/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/tests/Monolog/Handler/ElasticSearchHandlerTest.php new file mode 100644 index 000000000..1045e0343 --- /dev/null +++ b/tests/Monolog/Handler/ElasticSearchHandlerTest.php @@ -0,0 +1,266 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Elasticsearch\ClientBuilder; +use Monolog\Formatter\ElasticSearchFormatter; +use Monolog\Formatter\NormalizerFormatter; +use Monolog\Test\TestCase; +use Monolog\Logger; +use Elasticsearch\Client; + +class ElasticSearchHandlerTest extends TestCase +{ + /** + * @var Client mock + */ + protected $client; + + /** + * @var array Default handler options + */ + protected $options = [ + 'index' => 'my_index', + 'type' => 'doc_type', + ]; + + public function setUp() + { + // ElasticSearch lib required + if (!class_exists('Elasticsearch\Client')) { + $this->markTestSkipped('elasticsearch/elasticsearch not installed'); + } + + // base mock ElasticSearch Client object + $this->client = $this->getMockBuilder('Elasticsearch\Client') + ->setMethods(['bulk']) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::write + * @covers Monolog\Handler\ElasticSearchHandler::handleBatch + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + */ + public function testHandle() + { + // log message + $msg = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => [], + 'message' => 'log', + ]; + + // format expected result + $formatter = new ElasticSearchFormatter($this->options['index'], $this->options['type']); + $data = $formatter->format($msg); + unset($data['_index'], $data['_type']); + + $expected = [ + 'body' => [ + [ + 'index' => [ + '_index' => $this->options['index'], + '_type' => $this->options['type'], + ], + ], + $data, + ] + ]; + + // setup ES client mock + $this->client->expects($this->any()) + ->method('bulk') + ->with($expected); + + // perform tests + $handler = new ElasticSearchHandler($this->client, $this->options); + $handler->handle($msg); + $handler->handleBatch([$msg]); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + */ + public function testSetFormatter() + { + $handler = new ElasticSearchHandler($this->client); + $formatter = new ElasticSearchFormatter('index_new', 'type_new'); + $handler->setFormatter($formatter); + $this->assertInstanceOf('Monolog\Formatter\ElasticSearchFormatter', $handler->getFormatter()); + $this->assertEquals('index_new', $handler->getFormatter()->getIndex()); + $this->assertEquals('type_new', $handler->getFormatter()->getType()); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @expectedException InvalidArgumentException + * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticSearchFormatter + */ + public function testSetFormatterInvalid() + { + $handler = new ElasticSearchHandler($this->client); + $formatter = new NormalizerFormatter(); + $handler->setFormatter($formatter); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::__construct + * @covers Monolog\Handler\ElasticSearchHandler::getOptions + */ + public function testOptions() + { + $expected = [ + 'index' => $this->options['index'], + 'type' => $this->options['type'], + 'ignore_error' => false, + ]; + $handler = new ElasticSearchHandler($this->client, $this->options); + $this->assertEquals($expected, $handler->getOptions()); + } + + /** + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @dataProvider providerTestConnectionErrors + */ + public function testConnectionErrors($ignore, $expectedError) + { + $hosts = [['host' => '127.0.0.1', 'port' => 1]]; + $client = ClientBuilder::create() + ->setHosts($hosts) + ->build(); + + $handlerOpts = ['ignore_error' => $ignore]; + $handler = new ElasticSearchHandler($client, $handlerOpts); + + if ($expectedError) { + $this->expectException($expectedError[0]); + $this->expectExceptionMessage($expectedError[1]); + $handler->handle($this->getRecord()); + } else { + $this->assertFalse($handler->handle($this->getRecord())); + } + } + + /** + * @return array + */ + public function providerTestConnectionErrors() + { + return [ + [false, ['RuntimeException', 'Error sending messages to ElasticSearch']], + [true, false], + ]; + } + + /** + * Integration test using localhost Elastic Search server + * + * @covers Monolog\Handler\ElasticSearchHandler::__construct + * @covers Monolog\Handler\ElasticSearchHandler::handleBatch + * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + */ + public function testHandleIntegration() + { + $msg = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => [], + 'message' => 'log', + ]; + + $expected = $msg; + $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); + $expected['context'] = [ + 'class' => ["stdClass" => []], + 'foo' => 7, + 0 => 'bar', + ]; + + $client = ClientBuilder::create() + ->build(); + $handler = new ElasticSearchHandler($client, $this->options); + try { + $handler->handleBatch([$msg]); + } catch (\RuntimeException $e) { + $this->markTestSkipped('Cannot connect to Elastic Search server on localhost'); + } + + // check document id from ES server response + $documentId = $this->getCreatedDocId($client->transport->getLastConnection()->getLastRequestInfo()); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + + // retrieve document source from ES and validate + $document = $this->getDocSourceFromElastic( + $client, + $this->options['index'], + $this->options['type'], + $documentId + ); + + $this->assertEquals($expected, $document); + + // remove test index from ES + $client->indices()->delete(['index' => $this->options['index']]); + } + + /** + * Return last created document id from ES response + * + * @param array $info ElasticSearch last request info + * @return string|null + */ + protected function getCreatedDocId(array $info) + { + $data = json_decode($info['response']['body'], true); + + if (!empty($data['items'][0]['index']['_id'])) { + return $data['items'][0]['index']['_id']; + } + } + + /** + * Retrieve document by id from Elasticsearch + * + * @param Client $client ElasticSearch client + * @param string $index + * @param string $type + * @param string $documentId + * @return array + */ + protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + { + $params = [ + 'index' => $index, + 'type' => $type, + 'id' => $documentId + ]; + + $data = $client->get($params); + + if (!empty($data['_source'])) { + return $data['_source']; + } + + return []; + } +} From 569cdd635dabd3bf6f86513b5f4e8ff039309f5d Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:13:50 +0400 Subject: [PATCH 011/498] Update upgrade guide --- UPGRADE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 81b6e90b2..0fb5bdf1c 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,8 @@ ### 2.0.0 +- Added support for official ElasticSearch client. To avoid name collision, + old `ElasticSearchHandler` renamed to `ElasticaHandler` + - The timezone is now set per Logger instance and not statically, either via ->setTimezone or passed in the constructor. Calls to Logger::setTimezone should be converted. From aad9de4d0de36a0be7ea4f1dfebb33f243c93bdb Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:38:38 +0400 Subject: [PATCH 012/498] Fix unhandled throwable --- src/Monolog/Handler/ElasticSearchHandler.php | 4 ++-- tests/Monolog/Handler/ElasticSearchHandlerTest.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index d465438aa..3df39d914 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -13,12 +13,12 @@ use Elasticsearch\Client; use Elasticsearch\Common\Exceptions\RuntimeException as ElasticSearchRuntimeException; -use Exception; use InvalidArgumentException; use Monolog\Formatter\ElasticSearchFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use RuntimeException; +use Throwable; /** * Elastic Search handler @@ -149,7 +149,7 @@ protected function bulkSend(array $records) if ($responses['errors'] === true) { throw new ElasticSearchRuntimeException('ElasticSearch returned error for one of the records'); } - } catch (Exception $e) { + } catch (Throwable $e) { if (! $this->options['ignore_error']) { throw new RuntimeException('Error sending messages to ElasticSearch', 0, $e); } diff --git a/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/tests/Monolog/Handler/ElasticSearchHandlerTest.php index 1045e0343..e7d022978 100644 --- a/tests/Monolog/Handler/ElasticSearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticSearchHandlerTest.php @@ -196,7 +196,9 @@ public function testHandleIntegration() 0 => 'bar', ]; + $hosts = [['host' => '127.0.0.1', 'port' => 9200]]; $client = ClientBuilder::create() + ->setHosts($hosts) ->build(); $handler = new ElasticSearchHandler($client, $this->options); try { From 4a6308787b7ea33a61c09c98dfc0da999819b1f6 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:45:51 +0400 Subject: [PATCH 013/498] Try to fix travis build script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6f6213676..e75f6791e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ matrix: env: deps=low fast_finish: true -before_script: +before_install: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = amqp.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 9df69ca4ca56e632cd14a3c7476a8fbfa4968a45 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sat, 7 Apr 2018 04:52:28 +0400 Subject: [PATCH 014/498] Add PHP 7.2 to the travis script --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e75f6791e..88a11f0d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ dist: trusty php: - 7.0 - 7.1 + - 7.2 - nightly cache: From 67d1af8a96c80d7e92049ddd647e529320cbd9d1 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sun, 8 Apr 2018 21:10:32 +0400 Subject: [PATCH 015/498] Revert travis file changes --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 88a11f0d4..6f6213676 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ dist: trusty php: - 7.0 - 7.1 - - 7.2 - nightly cache: @@ -19,7 +18,7 @@ matrix: env: deps=low fast_finish: true -before_install: +before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = amqp.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 25c427a0e4def624048ce03205e610bdfa2e2921 Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Mon, 18 Jun 2018 11:17:10 -0500 Subject: [PATCH 016/498] Add a missing @dataProvider --- tests/Monolog/ErrorHandlerTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index d444dcde8..7026bb610 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -179,6 +179,7 @@ public function defaultPreviousProvider() } /** + * @dataProvider callablePreviousProvider * @depends testRegisterSignalHandler * @requires function pcntl_signal_get_handler */ From 23fd84fec03d7412bbfa31d28c98e70d623b4483 Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Mon, 18 Jun 2018 11:25:41 -0500 Subject: [PATCH 017/498] Wait for children that are being tested --- tests/Monolog/ErrorHandlerTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 7026bb610..003008069 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -131,7 +131,7 @@ public function testRegisterSignalHandler() * @depends testRegisterSignalHandler * @requires function pcntl_fork * @requires function pcntl_sigprocmask - * @requires function pcntl_wait + * @requires function pcntl_waitpid */ public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected) { @@ -159,7 +159,7 @@ public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, } $this->assertNotSame(-1, $pid); - $this->assertNotSame(-1, pcntl_wait($status)); + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); $this->assertNotSame(-1, $status); $this->assertSame($expected, file_get_contents($path)); } @@ -213,7 +213,7 @@ public function callablePreviousProvider() * @dataProvider restartSyscallsProvider * @depends testRegisterDefaultPreviousSignalHandler * @requires function pcntl_fork - * @requires function pcntl_wait + * @requires function pcntl_waitpid */ public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) { @@ -236,20 +236,20 @@ public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false); if ($restartSyscalls) { // pcntl_wait is expected to be restarted after the signal handler. - $this->assertNotSame(-1, pcntl_wait($status)); + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); } else { // pcntl_wait is expected to be interrupted when the signal handler is invoked. - $this->assertSame(-1, pcntl_wait($status)); + $this->assertSame(-1, pcntl_waitpid($pid, $status)); } $this->assertSame($restartSyscalls, microtime(true) - $microtime > 0.15); $this->assertTrue(pcntl_signal_dispatch()); $this->assertCount(1, $handler->getRecords()); if ($restartSyscalls) { // The child has already exited. - $this->assertSame(-1, pcntl_wait($status)); + $this->assertSame(-1, pcntl_waitpid($pid, $status)); } else { // The child has not exited yet. - $this->assertNotSame(-1, pcntl_wait($status)); + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); } } From 3b1a8296fff463b56dd0e8e40102ac8519ac3a1f Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Sun, 24 Jun 2018 20:49:32 +0400 Subject: [PATCH 018/498] Fix merging issues --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ec6750a8e..0b8c937d5 100644 --- a/composer.json +++ b/composer.json @@ -29,8 +29,7 @@ "jakub-onderka/php-parallel-lint": "^0.9", "predis/predis": "^1.1", "phpspec/prophecy": "^1.6.1", - "elasticsearch/elasticsearch": "^6.0" - "phpspec/prophecy": "^1.6.1", + "elasticsearch/elasticsearch": "^6.0", "rollbar/rollbar": "^1.3" }, "suggest": { From 34e3a48326fd413e1554d07622da6ddde7b724b1 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Wed, 27 Jun 2018 11:38:33 +0400 Subject: [PATCH 019/498] Update ES record type to _doc --- src/Monolog/Handler/ElasticSearchHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index 3df39d914..4c6096a22 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -66,7 +66,7 @@ public function __construct(Client $client, array $options = [], $level = Logger $this->options = array_merge( [ 'index' => 'monolog', // Elastic index name - 'type' => 'record', // Elastic document type + 'type' => '_doc', // Elastic document type 'ignore_error' => false, // Suppress ElasticSearch exceptions ], $options From 4c7795d310a591ef6d6149d32280f43fbe4d95a5 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Wed, 27 Jun 2018 11:48:39 +0400 Subject: [PATCH 020/498] Rename ElasticSearch to Elasticsearch --- UPGRADE.md | 4 +- composer.json | 2 +- doc/02-handlers-formatters-processors.md | 2 +- ...rmatter.php => ElasticsearchFormatter.php} | 16 ++--- ...chHandler.php => ElasticsearchHandler.php} | 30 ++++----- ...est.php => ElasticsearchFormatterTest.php} | 16 ++--- ...rTest.php => ElasticsearchHandlerTest.php} | 64 +++++++++---------- 7 files changed, 67 insertions(+), 67 deletions(-) rename src/Monolog/Formatter/{ElasticSearchFormatter.php => ElasticsearchFormatter.php} (76%) rename src/Monolog/Handler/{ElasticSearchHandler.php => ElasticsearchHandler.php} (80%) rename tests/Monolog/Formatter/{ElasticSearchFormatterTest.php => ElasticsearchFormatterTest.php} (76%) rename tests/Monolog/Handler/{ElasticSearchHandlerTest.php => ElasticsearchHandlerTest.php} (76%) diff --git a/UPGRADE.md b/UPGRADE.md index 0fb5bdf1c..8c84904c9 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,7 +1,7 @@ ### 2.0.0 -- Added support for official ElasticSearch client. To avoid name collision, - old `ElasticSearchHandler` renamed to `ElasticaHandler` +- Added support for official Elasticsearch client. To avoid name collision, + old `ElasticsearchHandler` renamed to `ElasticaHandler` - The timezone is now set per Logger instance and not statically, either via ->setTimezone or passed in the constructor. Calls to Logger::setTimezone diff --git a/composer.json b/composer.json index 0b8c937d5..2541bde83 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,7 @@ "sentry/sentry": "Allow sending log messages to a Sentry server", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "elasticsearch/elasticsearch": "Allow sending log messages to an Elastic Search server via official client", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index fb7add9d2..253a1a5b7 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -81,7 +81,7 @@ [Mongo](http://pecl.php.net/package/mongo) extension connection. - [_CouchDBHandler_](../src/Monolog/Handler/CouchDBHandler.php): Logs records to a CouchDB server. - [_DoctrineCouchDBHandler_](../src/Monolog/Handler/DoctrineCouchDBHandler.php): Logs records to a CouchDB server via the Doctrine CouchDB ODM. -- [_ElasticSearchHandler_](../src/Monolog/Handler/ElasticSearchHandler.php): Logs records to an Elastic Search server. +- [_ElasticsearchHandler_](../src/Monolog/Handler/ElasticsearchHandler.php): Logs records to an Elasticsearch server. - [_DynamoDbHandler_](../src/Monolog/Handler/DynamoDbHandler.php): Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php). ### Wrappers / Special Handlers diff --git a/src/Monolog/Formatter/ElasticSearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php similarity index 76% rename from src/Monolog/Formatter/ElasticSearchFormatter.php rename to src/Monolog/Formatter/ElasticsearchFormatter.php index 56e4d2e4f..682bdbe11 100644 --- a/src/Monolog/Formatter/ElasticSearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -14,29 +14,29 @@ use DateTime; /** - * Format a log message into an ElasticSearch record + * Format a log message into an Elasticsearch record * * @author Avtandil Kikabidze */ -class ElasticSearchFormatter extends NormalizerFormatter +class ElasticsearchFormatter extends NormalizerFormatter { /** - * @var string ElasticSearch index name + * @var string Elasticsearch index name */ protected $index; /** - * @var string ElasticSearch record type + * @var string Elasticsearch record type */ protected $type; /** - * @param string $index ElasticSearch index name - * @param string $type ElasticSearch record type + * @param string $index Elasticsearch index name + * @param string $type Elasticsearch record type */ public function __construct($index, $type) { - // ElasticSearch requires an ISO 8601 format date with optional millisecond precision. + // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. parent::__construct(DateTime::ISO8601); $this->index = $index; @@ -74,7 +74,7 @@ public function getType(): string } /** - * Convert a log message into an ElasticSearch record + * Convert a log message into an Elasticsearch record * * @param array $record Log message * @return array diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php similarity index 80% rename from src/Monolog/Handler/ElasticSearchHandler.php rename to src/Monolog/Handler/ElasticsearchHandler.php index 4c6096a22..f733e4e51 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -12,36 +12,36 @@ namespace Monolog\Handler; use Elasticsearch\Client; -use Elasticsearch\Common\Exceptions\RuntimeException as ElasticSearchRuntimeException; +use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; use InvalidArgumentException; -use Monolog\Formatter\ElasticSearchFormatter; +use Monolog\Formatter\ElasticsearchFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use RuntimeException; use Throwable; /** - * Elastic Search handler + * Elasticsearch handler * * @link https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html * * Simple usage example: * - * $client = \ElasticSearch\ClientBuilder::create() + * $client = \Elasticsearch\ClientBuilder::create() * ->setHosts($hosts) * ->build(); * * $options = array( * 'index' => 'elastic_index_name', - * 'type' => 'elastic_doc_type', + * 'type' => 'elastic_doc_type', * ); - * $handler = new ElasticSearchHandler($client, $options); + * $handler = new ElasticsearchHandler($client, $options); * $log = new Logger('application'); * $log->pushHandler($handler); * * @author Avtandil Kikabidze */ -class ElasticSearchHandler extends AbstractProcessingHandler +class ElasticsearchHandler extends AbstractProcessingHandler { /** * @var \Elasticsearch\Client @@ -54,7 +54,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler protected $options = []; /** - * @param \Elasticsearch\Client $client ElasticSearch Client object + * @param \Elasticsearch\Client $client Elasticsearch Client object * @param array $options Handler configuration * @param int $level The minimum logging level at which this handler will be triggered * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not @@ -67,7 +67,7 @@ public function __construct(Client $client, array $options = [], $level = Logger [ 'index' => 'monolog', // Elastic index name 'type' => '_doc', // Elastic document type - 'ignore_error' => false, // Suppress ElasticSearch exceptions + 'ignore_error' => false, // Suppress Elasticsearch exceptions ], $options ); @@ -86,10 +86,10 @@ protected function write(array $record) */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - if ($formatter instanceof ElasticSearchFormatter) { + if ($formatter instanceof ElasticsearchFormatter) { return parent::setFormatter($formatter); } - throw new InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticSearchFormatter'); + throw new InvalidArgumentException('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); } /** @@ -107,7 +107,7 @@ public function getOptions(): array */ protected function getDefaultFormatter(): FormatterInterface { - return new ElasticSearchFormatter($this->options['index'], $this->options['type']); + return new ElasticsearchFormatter($this->options['index'], $this->options['type']); } /** @@ -120,7 +120,7 @@ public function handleBatch(array $records) } /** - * Use ElasticSearch bulk API to send list of documents + * Use Elasticsearch bulk API to send list of documents * * @param array $records * @throws \RuntimeException @@ -147,11 +147,11 @@ protected function bulkSend(array $records) $responses = $this->client->bulk($params); if ($responses['errors'] === true) { - throw new ElasticSearchRuntimeException('ElasticSearch returned error for one of the records'); + throw new ElasticsearchRuntimeException('Elasticsearch returned error for one of the records'); } } catch (Throwable $e) { if (! $this->options['ignore_error']) { - throw new RuntimeException('Error sending messages to ElasticSearch', 0, $e); + throw new RuntimeException('Error sending messages to Elasticsearch', 0, $e); } } } diff --git a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php similarity index 76% rename from tests/Monolog/Formatter/ElasticSearchFormatterTest.php rename to tests/Monolog/Formatter/ElasticsearchFormatterTest.php index ee95191c4..d68c8f110 100644 --- a/tests/Monolog/Formatter/ElasticSearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php @@ -13,12 +13,12 @@ use Monolog\Logger; -class ElasticSearchFormatterTest extends \PHPUnit\Framework\TestCase +class ElasticsearchFormatterTest extends \PHPUnit\Framework\TestCase { /** - * @covers Monolog\Formatter\ElasticSearchFormatter::__construct - * @covers Monolog\Formatter\ElasticSearchFormatter::format - * @covers Monolog\Formatter\ElasticSearchFormatter::getDocument + * @covers Monolog\Formatter\ElasticsearchFormatter::__construct + * @covers Monolog\Formatter\ElasticsearchFormatter::format + * @covers Monolog\Formatter\ElasticsearchFormatter::getDocument */ public function testFormat() { @@ -43,7 +43,7 @@ public function testFormat() ]; // Format log message - $formatter = new ElasticSearchFormatter('my_index', 'doc_type'); + $formatter = new ElasticsearchFormatter('my_index', 'doc_type'); $doc = $formatter->format($msg); $this->assertInternalType('array', $doc); @@ -58,12 +58,12 @@ public function testFormat() } /** - * @covers Monolog\Formatter\ElasticSearchFormatter::getIndex - * @covers Monolog\Formatter\ElasticSearchFormatter::getType + * @covers Monolog\Formatter\ElasticsearchFormatter::getIndex + * @covers Monolog\Formatter\ElasticsearchFormatter::getType */ public function testGetters() { - $formatter = new ElasticSearchFormatter('my_index', 'doc_type'); + $formatter = new ElasticsearchFormatter('my_index', 'doc_type'); $this->assertEquals('my_index', $formatter->getIndex()); $this->assertEquals('doc_type', $formatter->getType()); } diff --git a/tests/Monolog/Handler/ElasticSearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php similarity index 76% rename from tests/Monolog/Handler/ElasticSearchHandlerTest.php rename to tests/Monolog/Handler/ElasticsearchHandlerTest.php index b3503b060..943a67eed 100644 --- a/tests/Monolog/Handler/ElasticSearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -12,13 +12,13 @@ namespace Monolog\Handler; use Elasticsearch\ClientBuilder; -use Monolog\Formatter\ElasticSearchFormatter; +use Monolog\Formatter\ElasticsearchFormatter; use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; use Monolog\Logger; use Elasticsearch\Client; -class ElasticSearchHandlerTest extends TestCase +class ElasticsearchHandlerTest extends TestCase { /** * @var Client mock @@ -35,12 +35,12 @@ class ElasticSearchHandlerTest extends TestCase public function setUp() { - // ElasticSearch lib required + // Elasticsearch lib required if (!class_exists('Elasticsearch\Client')) { $this->markTestSkipped('elasticsearch/elasticsearch not installed'); } - // base mock ElasticSearch Client object + // base mock Elasticsearch Client object $this->client = $this->getMockBuilder('Elasticsearch\Client') ->setMethods(['bulk']) ->disableOriginalConstructor() @@ -48,10 +48,10 @@ public function setUp() } /** - * @covers Monolog\Handler\ElasticSearchHandler::write - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + * @covers Monolog\Handler\ElasticsearchHandler::write + * @covers Monolog\Handler\ElasticsearchHandler::handleBatch + * @covers Monolog\Handler\ElasticsearchHandler::bulkSend + * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter */ public function testHandle() { @@ -67,7 +67,7 @@ public function testHandle() ]; // format expected result - $formatter = new ElasticSearchFormatter($this->options['index'], $this->options['type']); + $formatter = new ElasticsearchFormatter($this->options['index'], $this->options['type']); $data = $formatter->format($msg); unset($data['_index'], $data['_type']); @@ -89,39 +89,39 @@ public function testHandle() ->with($expected); // perform tests - $handler = new ElasticSearchHandler($this->client, $this->options); + $handler = new ElasticsearchHandler($this->client, $this->options); $handler->handle($msg); $handler->handleBatch([$msg]); } /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @covers Monolog\Handler\ElasticsearchHandler::setFormatter */ public function testSetFormatter() { - $handler = new ElasticSearchHandler($this->client); - $formatter = new ElasticSearchFormatter('index_new', 'type_new'); + $handler = new ElasticsearchHandler($this->client); + $formatter = new ElasticsearchFormatter('index_new', 'type_new'); $handler->setFormatter($formatter); - $this->assertInstanceOf('Monolog\Formatter\ElasticSearchFormatter', $handler->getFormatter()); + $this->assertInstanceOf('Monolog\Formatter\ElasticsearchFormatter', $handler->getFormatter()); $this->assertEquals('index_new', $handler->getFormatter()->getIndex()); $this->assertEquals('type_new', $handler->getFormatter()->getType()); } /** - * @covers Monolog\Handler\ElasticSearchHandler::setFormatter + * @covers Monolog\Handler\ElasticsearchHandler::setFormatter * @expectedException InvalidArgumentException - * @expectedExceptionMessage ElasticSearchHandler is only compatible with ElasticSearchFormatter + * @expectedExceptionMessage ElasticsearchHandler is only compatible with ElasticsearchFormatter */ public function testSetFormatterInvalid() { - $handler = new ElasticSearchHandler($this->client); + $handler = new ElasticsearchHandler($this->client); $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); } /** - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::getOptions + * @covers Monolog\Handler\ElasticsearchHandler::__construct + * @covers Monolog\Handler\ElasticsearchHandler::getOptions */ public function testOptions() { @@ -130,12 +130,12 @@ public function testOptions() 'type' => $this->options['type'], 'ignore_error' => false, ]; - $handler = new ElasticSearchHandler($this->client, $this->options); + $handler = new ElasticsearchHandler($this->client, $this->options); $this->assertEquals($expected, $handler->getOptions()); } /** - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend + * @covers Monolog\Handler\ElasticsearchHandler::bulkSend * @dataProvider providerTestConnectionErrors */ public function testConnectionErrors($ignore, $expectedError) @@ -146,7 +146,7 @@ public function testConnectionErrors($ignore, $expectedError) ->build(); $handlerOpts = ['ignore_error' => $ignore]; - $handler = new ElasticSearchHandler($client, $handlerOpts); + $handler = new ElasticsearchHandler($client, $handlerOpts); if ($expectedError) { $this->expectException($expectedError[0]); @@ -163,18 +163,18 @@ public function testConnectionErrors($ignore, $expectedError) public function providerTestConnectionErrors() { return [ - [false, ['RuntimeException', 'Error sending messages to ElasticSearch']], + [false, ['RuntimeException', 'Error sending messages to Elasticsearch']], [true, false], ]; } /** - * Integration test using localhost Elastic Search server + * Integration test using localhost Elasticsearch server * - * @covers Monolog\Handler\ElasticSearchHandler::__construct - * @covers Monolog\Handler\ElasticSearchHandler::handleBatch - * @covers Monolog\Handler\ElasticSearchHandler::bulkSend - * @covers Monolog\Handler\ElasticSearchHandler::getDefaultFormatter + * @covers Monolog\Handler\ElasticsearchHandler::__construct + * @covers Monolog\Handler\ElasticsearchHandler::handleBatch + * @covers Monolog\Handler\ElasticsearchHandler::bulkSend + * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter */ public function testHandleIntegration() { @@ -200,12 +200,12 @@ public function testHandleIntegration() $client = ClientBuilder::create() ->setHosts($hosts) ->build(); - $handler = new ElasticSearchHandler($client, $this->options); + $handler = new ElasticsearchHandler($client, $this->options); try { $handler->handleBatch([$msg]); } catch (\RuntimeException $e) { - $this->markTestSkipped('Cannot connect to Elastic Search server on localhost'); + $this->markTestSkipped('Cannot connect to Elasticsearch server on localhost'); } // check document id from ES server response @@ -229,7 +229,7 @@ public function testHandleIntegration() /** * Return last created document id from ES response * - * @param array $info ElasticSearch last request info + * @param array $info Elasticsearch last request info * @return string|null */ protected function getCreatedDocId(array $info) @@ -244,7 +244,7 @@ protected function getCreatedDocId(array $info) /** * Retrieve document by id from Elasticsearch * - * @param Client $client ElasticSearch client + * @param Client $client Elasticsearch client * @param string $index * @param string $type * @param string $documentId From 37b587687d9475323afdd0ffec6e96b04c1d6163 Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Sun, 1 Jul 2018 23:42:41 -0500 Subject: [PATCH 021/498] Move POSIX signal handling to SignalHandler* Suggested by Helmut Hummel (@helhum). --- doc/03-utilities.md | 5 +- src/Monolog/ErrorHandler.php | 87 +-------- src/Monolog/SignalHandler.php | 115 +++++++++++ tests/Monolog/ErrorHandlerTest.php | 268 +------------------------- tests/Monolog/SignalHandlerTest.php | 287 ++++++++++++++++++++++++++++ 5 files changed, 407 insertions(+), 355 deletions(-) create mode 100644 src/Monolog/SignalHandler.php create mode 100644 tests/Monolog/SignalHandlerTest.php diff --git a/doc/03-utilities.md b/doc/03-utilities.md index 513d08aae..fd3fd0e7d 100644 --- a/doc/03-utilities.md +++ b/doc/03-utilities.md @@ -4,8 +4,9 @@ can then statically access from anywhere. It is not really a best practice but can help in some older codebases or for ease of use. - _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register - a Logger instance as an exception handler, error handler, fatal error handler or - signal handler. + a Logger instance as an exception handler, error handler or fatal error handler. +- _SignalHandler_: The `Monolog\SignalHandler` class allows you to easily register + a Logger instance as a POSIX signal handler. - _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log level is reached. - _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index b96c58ae6..b30257387 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -14,12 +14,11 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Monolog\Handler\AbstractHandler; -use ReflectionExtension; /** * Monolog error handler * - * A facility to enable logging of runtime errors, exceptions, fatal errors and signals. + * A facility to enable logging of runtime errors, exceptions and fatal errors. * * Quick setup: ErrorHandler::register($logger); * @@ -42,10 +41,6 @@ class ErrorHandler private $lastFatalTrace; private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); - private $previousSignalHandler = array(); - private $signalLevelMap = array(); - private $signalRestartSyscalls = array(); - public function __construct(LoggerInterface $logger) { $this->logger = $logger; @@ -110,37 +105,6 @@ public function registerFatalHandler($level = null, $reservedMemorySize = 20) $this->hasFatalErrorHandler = true; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) - { - if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { - return $this; - } - - if ($callPrevious) { - if (function_exists('pcntl_signal_get_handler')) { - $handler = pcntl_signal_get_handler($signo); - if ($handler === false) { - return $this; - } - $this->previousSignalHandler[$signo] = $handler; - } else { - $this->previousSignalHandler[$signo] = true; - } - } else { - unset($this->previousSignalHandler[$signo]); - } - $this->signalLevelMap[$signo] = $level; - $this->signalRestartSyscalls[$signo] = $restartSyscalls; - - if (function_exists('pcntl_async_signals') && $async !== null) { - pcntl_async_signals($async); - } - - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); - - return $this; - } - protected function defaultErrorLevelMap() { return array( @@ -234,55 +198,6 @@ public function handleFatalError() } } - public function handleSignal($signo, array $siginfo = null) - { - static $signals = array(); - - if (!$signals && extension_loaded('pcntl')) { - $pcntl = new ReflectionExtension('pcntl'); - $constants = $pcntl->getConstants(); - if (!$constants) { - // HHVM 3.24.2 returns an empty array. - $constants = get_defined_constants(true); - $constants = $constants['Core']; - } - foreach ($constants as $name => $value) { - if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { - $signals[$value] = $name; - } - } - unset($constants); - } - - $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; - $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; - $context = isset($siginfo) ? $siginfo : array(); - $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); - - if (!isset($this->previousSignalHandler[$signo])) { - return; - } - - if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { - if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') - && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { - $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; - pcntl_signal($signo, SIG_DFL, $restartSyscalls); - pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); - posix_kill(posix_getpid(), $signo); - pcntl_signal_dispatch(); - pcntl_sigprocmask(SIG_SETMASK, $oldset); - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); - } - } elseif (is_callable($this->previousSignalHandler[$signo])) { - if (PHP_VERSION >= 71000) { - $this->previousSignalHandler[$signo]($signo, $siginfo); - } else { - $this->previousSignalHandler[$signo]($signo); - } - } - } - private static function codeToString($code) { switch ($code) { diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php new file mode 100644 index 000000000..d5907805a --- /dev/null +++ b/src/Monolog/SignalHandler.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use ReflectionExtension; + +/** + * Monolog POSIX signal handler + * + * @author Robert Gust-Bardon + */ +class SignalHandler +{ + private $logger; + + private $previousSignalHandler = array(); + private $signalLevelMap = array(); + private $signalRestartSyscalls = array(); + + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) + { + if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { + return $this; + } + + if ($callPrevious) { + if (function_exists('pcntl_signal_get_handler')) { + $handler = pcntl_signal_get_handler($signo); + if ($handler === false) { + return $this; + } + $this->previousSignalHandler[$signo] = $handler; + } else { + $this->previousSignalHandler[$signo] = true; + } + } else { + unset($this->previousSignalHandler[$signo]); + } + $this->signalLevelMap[$signo] = $level; + $this->signalRestartSyscalls[$signo] = $restartSyscalls; + + if (function_exists('pcntl_async_signals') && $async !== null) { + pcntl_async_signals($async); + } + + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + + return $this; + } + + public function handleSignal($signo, array $siginfo = null) + { + static $signals = array(); + + if (!$signals && extension_loaded('pcntl')) { + $pcntl = new ReflectionExtension('pcntl'); + $constants = $pcntl->getConstants(); + if (!$constants) { + // HHVM 3.24.2 returns an empty array. + $constants = get_defined_constants(true); + $constants = $constants['Core']; + } + foreach ($constants as $name => $value) { + if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { + $signals[$value] = $name; + } + } + unset($constants); + } + + $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; + $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; + $context = isset($siginfo) ? $siginfo : array(); + $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); + + if (!isset($this->previousSignalHandler[$signo])) { + return; + } + + if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') + && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { + $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; + pcntl_signal($signo, SIG_DFL, $restartSyscalls); + pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + pcntl_sigprocmask(SIG_SETMASK, $oldset); + pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + } + } elseif (is_callable($this->previousSignalHandler[$signo])) { + if (PHP_VERSION_ID >= 70100) { + $this->previousSignalHandler[$signo]($signo, $siginfo); + } else { + $this->previousSignalHandler[$signo]($signo); + } + } + } +} diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 003008069..a9a3f301f 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -11,55 +11,10 @@ namespace Monolog; -use Monolog\Handler\StreamHandler; use Monolog\Handler\TestHandler; -use Psr\Log\LogLevel; -class ErrorHandlerTest extends TestCase +class ErrorHandlerTest extends \PHPUnit_Framework_TestCase { - - private $asyncSignalHandling; - private $blockedSignals; - private $signalHandlers; - - protected function setUp() - { - $this->signalHandlers = array(); - if (extension_loaded('pcntl')) { - if (function_exists('pcntl_async_signals')) { - $this->asyncSignalHandling = pcntl_async_signals(); - } - if (function_exists('pcntl_sigprocmask')) { - pcntl_sigprocmask(SIG_BLOCK, array(), $this->blockedSignals); - } - } - } - - protected function tearDown() - { - if ($this->asyncSignalHandling !== null) { - pcntl_async_signals($this->asyncSignalHandling); - } - if ($this->blockedSignals !== null) { - pcntl_sigprocmask(SIG_SETMASK, $this->blockedSignals); - } - if ($this->signalHandlers) { - pcntl_signal_dispatch(); - foreach ($this->signalHandlers as $signo => $handler) { - pcntl_signal($signo, $handler); - } - } - } - - private function setSignalHandler($signo, $handler = SIG_DFL) { - if (function_exists('pcntl_signal_get_handler')) { - $this->signalHandlers[$signo] = pcntl_signal_get_handler($signo); - } else { - $this->signalHandlers[$signo] = SIG_DFL; - } - $this->assertTrue(pcntl_signal($signo, $handler)); - } - public function testHandleError() { $logger = new Logger('test', array($handler = new TestHandler)); @@ -73,225 +28,4 @@ public function testHandleError() $this->assertCount(2, $handler->getRecords()); $this->assertTrue($handler->hasEmergencyRecords()); } - - public function testHandleSignal() - { - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - $signo = 2; // SIGINT. - $siginfo = array('signo' => $signo, 'errno' => 0, 'code' => 0); - $errHandler->handleSignal($signo, $siginfo); - $this->assertCount(1, $handler->getRecords()); - $this->assertTrue($handler->hasCriticalRecords()); - $records = $handler->getRecords(); - $this->assertSame($siginfo, $records[0]['context']); - } - - /** - * @depends testHandleSignal - * @requires extension pcntl - * @requires extension posix - * @requires function pcntl_signal - * @requires function pcntl_signal_dispatch - * @requires function posix_getpid - * @requires function posix_kill - */ - public function testRegisterSignalHandler() - { - // SIGCONT and SIGURG should be ignored by default. - if (!defined('SIGCONT') || !defined('SIGURG')) { - $this->markTestSkipped('This test requires the SIGCONT and SIGURG pcntl constants.'); - } - - $this->setSignalHandler(SIGCONT, SIG_IGN); - $this->setSignalHandler(SIGURG, SIG_IGN); - - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - $pid = posix_getpid(); - - $this->assertTrue(posix_kill($pid, SIGURG)); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount(0, $handler->getRecords()); - - $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, false); - - $this->assertTrue(posix_kill($pid, SIGCONT)); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount(0, $handler->getRecords()); - - $this->assertTrue(posix_kill($pid, SIGURG)); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount(1, $handler->getRecords()); - $this->assertTrue($handler->hasInfoThatContains('SIGURG')); - } - - /** - * @dataProvider defaultPreviousProvider - * @depends testRegisterSignalHandler - * @requires function pcntl_fork - * @requires function pcntl_sigprocmask - * @requires function pcntl_waitpid - */ - public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected) - { - $this->setSignalHandler($signo, SIG_DFL); - - $path = tempnam(sys_get_temp_dir(), 'monolog-'); - $this->assertNotFalse($path); - - $pid = pcntl_fork(); - if ($pid === 0) { // Child. - $streamHandler = new StreamHandler($path); - $streamHandler->setFormatter($this->getIdentityFormatter()); - $logger = new Logger('test', array($streamHandler)); - $errHandler = new ErrorHandler($logger); - $errHandler->registerSignalHandler($signo, LogLevel::INFO, $callPrevious, false, false); - pcntl_sigprocmask(SIG_SETMASK, array(SIGCONT)); - posix_kill(posix_getpid(), $signo); - pcntl_signal_dispatch(); - // If $callPrevious is true, SIGINT should terminate by this line. - pcntl_sigprocmask(SIG_BLOCK, array(), $oldset); - file_put_contents($path, implode(' ', $oldset), FILE_APPEND); - posix_kill(posix_getpid(), $signo); - pcntl_signal_dispatch(); - exit(); - } - - $this->assertNotSame(-1, $pid); - $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); - $this->assertNotSame(-1, $status); - $this->assertSame($expected, file_get_contents($path)); - } - - public function defaultPreviousProvider() - { - if (!defined('SIGCONT') || !defined('SIGINT') || !defined('SIGURG')) { - return array(); - } - - return array( - array(SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'), - array(SIGINT, true, 'Program received signal SIGINT'), - array(SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), - array(SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), - ); - } - - /** - * @dataProvider callablePreviousProvider - * @depends testRegisterSignalHandler - * @requires function pcntl_signal_get_handler - */ - public function testRegisterCallablePreviousSignalHandler($callPrevious) - { - $this->setSignalHandler(SIGURG, SIG_IGN); - - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - $previousCalled = 0; - pcntl_signal(SIGURG, function ($signo, array $siginfo = null) use (&$previousCalled) { - ++$previousCalled; - }); - $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, $callPrevious, false, false); - $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount(1, $handler->getRecords()); - $this->assertTrue($handler->hasInfoThatContains('SIGURG')); - $this->assertSame($callPrevious ? 1 : 0, $previousCalled); - } - - public function callablePreviousProvider() - { - return array( - array(false), - array(true), - ); - } - - /** - * @dataProvider restartSyscallsProvider - * @depends testRegisterDefaultPreviousSignalHandler - * @requires function pcntl_fork - * @requires function pcntl_waitpid - */ - public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) - { - $this->setSignalHandler(SIGURG, SIG_IGN); - - $parentPid = posix_getpid(); - $microtime = microtime(true); - - $pid = pcntl_fork(); - if ($pid === 0) { // Child. - usleep(100000); - posix_kill($parentPid, SIGURG); - usleep(100000); - exit(); - } - - $this->assertNotSame(-1, $pid); - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false); - if ($restartSyscalls) { - // pcntl_wait is expected to be restarted after the signal handler. - $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); - } else { - // pcntl_wait is expected to be interrupted when the signal handler is invoked. - $this->assertSame(-1, pcntl_waitpid($pid, $status)); - } - $this->assertSame($restartSyscalls, microtime(true) - $microtime > 0.15); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount(1, $handler->getRecords()); - if ($restartSyscalls) { - // The child has already exited. - $this->assertSame(-1, pcntl_waitpid($pid, $status)); - } else { - // The child has not exited yet. - $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); - } - } - - public function restartSyscallsProvider() - { - return array( - array(false), - array(true), - array(false), - array(true), - ); - } - - /** - * @dataProvider asyncProvider - * @depends testRegisterDefaultPreviousSignalHandler - * @requires function pcntl_async_signals - */ - public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $expectedBefore, $expectedAfter) - { - $this->setSignalHandler(SIGURG, SIG_IGN); - pcntl_async_signals($initialAsync); - - $logger = new Logger('test', array($handler = new TestHandler)); - $errHandler = new ErrorHandler($logger); - $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, $desiredAsync); - $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); - $this->assertCount($expectedBefore, $handler->getRecords()); - $this->assertTrue(pcntl_signal_dispatch()); - $this->assertCount($expectedAfter, $handler->getRecords()); - } - - public function asyncProvider() - { - return array( - array(false, false, 0, 1), - array(false, null, 0, 1), - array(false, true, 1, 1), - array(true, false, 0, 1), - array(true, null, 1, 1), - array(true, true, 1, 1), - ); - } - } diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php new file mode 100644 index 000000000..9fa079290 --- /dev/null +++ b/tests/Monolog/SignalHandlerTest.php @@ -0,0 +1,287 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use Monolog\Handler\StreamHandler; +use Monolog\Handler\TestHandler; +use Psr\Log\LogLevel; + +/** + * @author Robert Gust-Bardon + * @covers Monolog\SignalHandler + */ +class SignalHandlerTest extends TestCase +{ + + private $asyncSignalHandling; + private $blockedSignals; + private $signalHandlers; + + protected function setUp() + { + $this->signalHandlers = array(); + if (extension_loaded('pcntl')) { + if (function_exists('pcntl_async_signals')) { + $this->asyncSignalHandling = pcntl_async_signals(); + } + if (function_exists('pcntl_sigprocmask')) { + pcntl_sigprocmask(SIG_BLOCK, array(), $this->blockedSignals); + } + } + } + + protected function tearDown() + { + if ($this->asyncSignalHandling !== null) { + pcntl_async_signals($this->asyncSignalHandling); + } + if ($this->blockedSignals !== null) { + pcntl_sigprocmask(SIG_SETMASK, $this->blockedSignals); + } + if ($this->signalHandlers) { + pcntl_signal_dispatch(); + foreach ($this->signalHandlers as $signo => $handler) { + pcntl_signal($signo, $handler); + } + } + } + + private function setSignalHandler($signo, $handler = SIG_DFL) { + if (function_exists('pcntl_signal_get_handler')) { + $this->signalHandlers[$signo] = pcntl_signal_get_handler($signo); + } else { + $this->signalHandlers[$signo] = SIG_DFL; + } + $this->assertTrue(pcntl_signal($signo, $handler)); + } + + public function testHandleSignal() + { + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new SignalHandler($logger); + $signo = 2; // SIGINT. + $siginfo = array('signo' => $signo, 'errno' => 0, 'code' => 0); + $errHandler->handleSignal($signo, $siginfo); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasCriticalRecords()); + $records = $handler->getRecords(); + $this->assertSame($siginfo, $records[0]['context']); + } + + /** + * @depends testHandleSignal + * @requires extension pcntl + * @requires extension posix + * @requires function pcntl_signal + * @requires function pcntl_signal_dispatch + * @requires function posix_getpid + * @requires function posix_kill + */ + public function testRegisterSignalHandler() + { + // SIGCONT and SIGURG should be ignored by default. + if (!defined('SIGCONT') || !defined('SIGURG')) { + $this->markTestSkipped('This test requires the SIGCONT and SIGURG pcntl constants.'); + } + + $this->setSignalHandler(SIGCONT, SIG_IGN); + $this->setSignalHandler(SIGURG, SIG_IGN); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new SignalHandler($logger); + $pid = posix_getpid(); + + $this->assertTrue(posix_kill($pid, SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(0, $handler->getRecords()); + + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, false); + + $this->assertTrue(posix_kill($pid, SIGCONT)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(0, $handler->getRecords()); + + $this->assertTrue(posix_kill($pid, SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasInfoThatContains('SIGURG')); + } + + /** + * @dataProvider defaultPreviousProvider + * @depends testRegisterSignalHandler + * @requires function pcntl_fork + * @requires function pcntl_sigprocmask + * @requires function pcntl_waitpid + */ + public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, $expected) + { + $this->setSignalHandler($signo, SIG_DFL); + + $path = tempnam(sys_get_temp_dir(), 'monolog-'); + $this->assertNotFalse($path); + + $pid = pcntl_fork(); + if ($pid === 0) { // Child. + $streamHandler = new StreamHandler($path); + $streamHandler->setFormatter($this->getIdentityFormatter()); + $logger = new Logger('test', array($streamHandler)); + $errHandler = new SignalHandler($logger); + $errHandler->registerSignalHandler($signo, LogLevel::INFO, $callPrevious, false, false); + pcntl_sigprocmask(SIG_SETMASK, array(SIGCONT)); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + // If $callPrevious is true, SIGINT should terminate by this line. + pcntl_sigprocmask(SIG_BLOCK, array(), $oldset); + file_put_contents($path, implode(' ', $oldset), FILE_APPEND); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + exit(); + } + + $this->assertNotSame(-1, $pid); + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); + $this->assertNotSame(-1, $status); + $this->assertSame($expected, file_get_contents($path)); + } + + public function defaultPreviousProvider() + { + if (!defined('SIGCONT') || !defined('SIGINT') || !defined('SIGURG')) { + return array(); + } + + return array( + array(SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'), + array(SIGINT, true, 'Program received signal SIGINT'), + array(SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), + array(SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), + ); + } + + /** + * @dataProvider callablePreviousProvider + * @depends testRegisterSignalHandler + * @requires function pcntl_signal_get_handler + */ + public function testRegisterCallablePreviousSignalHandler($callPrevious) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new SignalHandler($logger); + $previousCalled = 0; + pcntl_signal(SIGURG, function ($signo, array $siginfo = null) use (&$previousCalled) { + ++$previousCalled; + }); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, $callPrevious, false, false); + $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasInfoThatContains('SIGURG')); + $this->assertSame($callPrevious ? 1 : 0, $previousCalled); + } + + public function callablePreviousProvider() + { + return array( + array(false), + array(true), + ); + } + + /** + * @dataProvider restartSyscallsProvider + * @depends testRegisterDefaultPreviousSignalHandler + * @requires function pcntl_fork + * @requires function pcntl_waitpid + */ + public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + + $parentPid = posix_getpid(); + $microtime = microtime(true); + + $pid = pcntl_fork(); + if ($pid === 0) { // Child. + usleep(100000); + posix_kill($parentPid, SIGURG); + usleep(100000); + exit(); + } + + $this->assertNotSame(-1, $pid); + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new SignalHandler($logger); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false); + if ($restartSyscalls) { + // pcntl_wait is expected to be restarted after the signal handler. + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); + } else { + // pcntl_wait is expected to be interrupted when the signal handler is invoked. + $this->assertSame(-1, pcntl_waitpid($pid, $status)); + } + $this->assertSame($restartSyscalls, microtime(true) - $microtime > 0.15); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount(1, $handler->getRecords()); + if ($restartSyscalls) { + // The child has already exited. + $this->assertSame(-1, pcntl_waitpid($pid, $status)); + } else { + // The child has not exited yet. + $this->assertNotSame(-1, pcntl_waitpid($pid, $status)); + } + } + + public function restartSyscallsProvider() + { + return array( + array(false), + array(true), + array(false), + array(true), + ); + } + + /** + * @dataProvider asyncProvider + * @depends testRegisterDefaultPreviousSignalHandler + * @requires function pcntl_async_signals + */ + public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $expectedBefore, $expectedAfter) + { + $this->setSignalHandler(SIGURG, SIG_IGN); + pcntl_async_signals($initialAsync); + + $logger = new Logger('test', array($handler = new TestHandler)); + $errHandler = new SignalHandler($logger); + $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, $desiredAsync); + $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); + $this->assertCount($expectedBefore, $handler->getRecords()); + $this->assertTrue(pcntl_signal_dispatch()); + $this->assertCount($expectedAfter, $handler->getRecords()); + } + + public function asyncProvider() + { + return array( + array(false, false, 0, 1), + array(false, null, 0, 1), + array(false, true, 1, 1), + array(true, false, 0, 1), + array(true, null, 1, 1), + array(true, true, 1, 1), + ); + } + +} From 06143b03e5c1598bfa6c6df65432010da0ecc28b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 4 Jul 2018 14:10:04 +0200 Subject: [PATCH 022/498] Add a bunch of return types and fix type inconsistencies reports from phan --- doc/04-extending.md | 4 +- src/Monolog/DateTimeImmutable.php | 7 ++- .../Formatter/GelfMessageFormatter.php | 6 +-- src/Monolog/Formatter/HtmlFormatter.php | 13 +++--- src/Monolog/Formatter/JsonFormatter.php | 2 + src/Monolog/Formatter/LineFormatter.php | 15 ++++--- src/Monolog/Formatter/LogmaticFormatter.php | 14 +----- src/Monolog/Formatter/LogstashFormatter.php | 12 +++--- src/Monolog/Formatter/NormalizerFormatter.php | 4 +- src/Monolog/Formatter/WildfireFormatter.php | 3 +- src/Monolog/Handler/AbstractHandler.php | 2 +- .../Handler/AbstractProcessingHandler.php | 5 +-- src/Monolog/Handler/AbstractSyslogHandler.php | 2 +- src/Monolog/Handler/AmqpHandler.php | 6 +-- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- src/Monolog/Handler/BufferHandler.php | 4 +- src/Monolog/Handler/ChromePHPHandler.php | 6 +-- src/Monolog/Handler/CouchDBHandler.php | 4 +- src/Monolog/Handler/CubeHandler.php | 4 +- src/Monolog/Handler/Curl/Util.php | 4 +- src/Monolog/Handler/DeduplicationHandler.php | 2 +- .../Handler/DoctrineCouchDBHandler.php | 4 +- src/Monolog/Handler/DynamoDbHandler.php | 4 +- src/Monolog/Handler/ElasticSearchHandler.php | 6 +-- src/Monolog/Handler/ErrorLogHandler.php | 4 +- src/Monolog/Handler/FilterHandler.php | 4 +- src/Monolog/Handler/FingersCrossedHandler.php | 4 +- src/Monolog/Handler/FirePHPHandler.php | 2 +- src/Monolog/Handler/FleepHookHandler.php | 4 +- src/Monolog/Handler/FlowdockHandler.php | 6 +-- .../Handler/FormattableHandlerTrait.php | 1 + src/Monolog/Handler/GelfHandler.php | 4 +- src/Monolog/Handler/GroupHandler.php | 4 +- src/Monolog/Handler/Handler.php | 4 +- src/Monolog/Handler/HandlerInterface.php | 4 +- src/Monolog/Handler/HandlerWrapper.php | 8 ++-- src/Monolog/Handler/HipChatHandler.php | 39 ++++------------- src/Monolog/Handler/IFTTTHandler.php | 4 +- src/Monolog/Handler/InsightOpsHandler.php | 2 +- src/Monolog/Handler/LogEntriesHandler.php | 2 +- src/Monolog/Handler/LogglyHandler.php | 6 +-- src/Monolog/Handler/MailHandler.php | 10 ++--- src/Monolog/Handler/MandrillHandler.php | 13 ++++-- src/Monolog/Handler/MongoDBHandler.php | 4 +- src/Monolog/Handler/NativeMailerHandler.php | 4 +- src/Monolog/Handler/NewRelicHandler.php | 2 +- src/Monolog/Handler/PHPConsoleHandler.php | 23 +++++----- src/Monolog/Handler/ProcessHandler.php | 31 +++++-------- .../Handler/ProcessableHandlerTrait.php | 1 + src/Monolog/Handler/PsrHandler.php | 2 +- src/Monolog/Handler/PushoverHandler.php | 4 +- src/Monolog/Handler/RavenHandler.php | 7 +-- src/Monolog/Handler/RedisHandler.php | 2 +- src/Monolog/Handler/RollbarHandler.php | 6 +-- src/Monolog/Handler/RotatingFileHandler.php | 11 ++--- src/Monolog/Handler/SendGridHandler.php | 2 +- src/Monolog/Handler/SlackHandler.php | 4 +- src/Monolog/Handler/SlackWebhookHandler.php | 4 +- src/Monolog/Handler/SlackbotHandler.php | 4 +- src/Monolog/Handler/SocketHandler.php | 43 +++++++------------ src/Monolog/Handler/SqsHandler.php | 4 +- src/Monolog/Handler/StreamHandler.php | 15 +++---- src/Monolog/Handler/SwiftMailerHandler.php | 4 +- src/Monolog/Handler/SyslogHandler.php | 6 +-- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 2 +- src/Monolog/Handler/SyslogUdpHandler.php | 6 +-- src/Monolog/Handler/TestHandler.php | 2 +- .../Handler/WhatFailureGroupHandler.php | 2 +- src/Monolog/Handler/ZendMonitorHandler.php | 20 ++------- src/Monolog/Logger.php | 8 ++-- .../Processor/PsrLogMessageProcessor.php | 7 +-- src/Monolog/Test/TestCase.php | 12 +++--- tests/Monolog/Handler/HandlerWrapperTest.php | 5 +-- 73 files changed, 227 insertions(+), 280 deletions(-) diff --git a/doc/04-extending.md b/doc/04-extending.md index ffb070094..5ba7c0fdc 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -30,13 +30,13 @@ class PDOHandler extends AbstractProcessingHandler private $pdo; private $statement; - public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true) + public function __construct(PDO $pdo, $level = Logger::DEBUG, bool $bubble = true) { $this->pdo = $pdo; parent::__construct($level, $bubble); } - protected function write(array $record) + protected function write(array $record): void { if (!$this->initialized) { $this->initialize(); diff --git a/src/Monolog/DateTimeImmutable.php b/src/Monolog/DateTimeImmutable.php index 6e7a5fc66..6a1ba9b25 100644 --- a/src/Monolog/DateTimeImmutable.php +++ b/src/Monolog/DateTimeImmutable.php @@ -11,6 +11,8 @@ namespace Monolog; +use DateTimeZone; + /** * Overrides default json encoding of date time objects * @@ -19,9 +21,12 @@ */ class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable { + /** + * @var bool + */ private $useMicroseconds; - public function __construct($useMicroseconds, \DateTimeZone $timezone = null) + public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null) { $this->useMicroseconds = $useMicroseconds; diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 4e95a6e4f..21176a643 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -58,13 +58,13 @@ class GelfMessageFormatter extends NormalizerFormatter Logger::EMERGENCY => 0, ]; - public function __construct(string $systemName = null, string $extraPrefix = null, string $contextPrefix = 'ctxt_', int $maxLength = null) + public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null) { parent::__construct('U.u'); - $this->systemName = $systemName ?: gethostname(); + $this->systemName = (is_null($systemName) || $systemName === '') ? gethostname() : $systemName; - $this->extraPrefix = $extraPrefix; + $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix; $this->contextPrefix = $contextPrefix; $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength; } diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 26f74fa99..e116177de 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -37,9 +37,9 @@ class HtmlFormatter extends NormalizerFormatter ]; /** - * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format */ - public function __construct(string $dateFormat = null) + public function __construct(?string $dateFormat = null) { parent::__construct($dateFormat); } @@ -50,7 +50,6 @@ public function __construct(string $dateFormat = null) * @param string $th Row header content * @param string $td Row standard cell content * @param bool $escapeTd false if td content must not be html escaped - * @return string */ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): string { @@ -79,8 +78,8 @@ protected function addTitle(string $title, int $level) /** * Formats a log record. * - * @param array $record A record to format - * @return mixed The formatted record + * @param array $record A record to format + * @return string The formatted record */ public function format(array $record): string { @@ -113,8 +112,8 @@ public function format(array $record): string /** * Formats a set of log records. * - * @param array $records A set of records to format - * @return mixed The formatted set of records + * @param array $records A set of records to format + * @return string The formatted set of records */ public function formatBatch(array $records): string { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index e0d5449e4..3281be129 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -61,6 +61,8 @@ public function isAppendingNewlines(): bool /** * {@inheritdoc} + * + * @suppress PhanTypeComparisonToArray */ public function format(array $record): string { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 6cbdb5209..48bb2c051 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -29,14 +29,14 @@ class LineFormatter extends NormalizerFormatter protected $includeStacktraces; /** - * @param string $format The format of the message - * @param string $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 + * @param ?string $format The format of the message + * @param ?string $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) + public function __construct(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = false, bool $ignoreEmptyContextAndExtra = false) { - $this->format = $format ?: static::SIMPLE_FORMAT; + $this->format = $format === null ? static::SIMPLE_FORMAT : $format; $this->allowInlineLineBreaks = $allowInlineLineBreaks; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; parent::__construct($dateFormat); @@ -124,6 +124,9 @@ public function stringify($value): string return $this->replaceNewlines($this->convertToString($value)); } + /** + * @suppress PhanParamSignatureMismatch + */ protected function normalizeException(\Throwable $e, int $depth = 0): string { $str = $this->formatException($e); diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index 7a75e00f3..8c6ff2f48 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -21,30 +21,20 @@ class LogmaticFormatter extends JsonFormatter const MARKERS = ["sourcecode", "php"]; /** - * @param string + * @var string */ protected $hostname = ''; /** - * @param string + * @var string */ protected $appname = ''; - /** - * Set hostname - * - * @param string $hostname - */ public function setHostname(string $hostname) { $this->hostname = $hostname; } - /** - * Set appname - * - * @param string $appname - */ public function setAppname(string $appname) { $this->appname = $appname; diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index 74464e57f..6404acf0c 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -42,17 +42,17 @@ class LogstashFormatter extends NormalizerFormatter protected $contextKey; /** - * @param string $applicationName the application that sends the data, used as the "type" field of logstash - * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine - * @param string $extraKey the key for extra keys inside logstash "fields", defaults to extra - * @param string $contextKey the key for context keys inside logstash "fields", defaults to context + * @param string $applicationName the application that sends the data, used as the "type" field of logstash + * @param ?string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine + * @param string $extraKey the key for extra keys inside logstash "fields", defaults to extra + * @param string $contextKey the key for context keys inside logstash "fields", defaults to context */ - public function __construct(string $applicationName, string $systemName = null, string $extraKey = 'extra', string $contextKey = 'context') + public function __construct(string $applicationName, ?string $systemName = null, string $extraKey = 'extra', string $contextKey = 'context') { // logstash requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\TH:i:s.uP'); - $this->systemName = $systemName ?: gethostname(); + $this->systemName = $systemName === null ? gethostname() : $systemName; $this->applicationName = $applicationName; $this->extraKey = $extraKey; $this->contextKey = $contextKey; diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 2177f91e4..c325865b5 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -28,9 +28,9 @@ class NormalizerFormatter implements FormatterInterface protected $maxNormalizeItemCount = 1000; /** - * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format */ - public function __construct(string $dateFormat = null) + public function __construct(?string $dateFormat = null) { $this->dateFormat = null === $dateFormat ? static::SIMPLE_DATE : $dateFormat; if (!function_exists('json_encode')) { diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index c8a3bb4a7..a5812b89b 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -91,7 +91,7 @@ public function format(array $record): string // The message itself is a serialization of the above JSON object + it's length return sprintf( - '%s|%s|', + '%d|%s|', strlen($json), $json ); @@ -107,6 +107,7 @@ public function formatBatch(array $records) /** * {@inheritdoc} + * @suppress PhanTypeMismatchReturn */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index d47710842..7c507466e 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -27,7 +27,7 @@ abstract class AbstractHandler extends Handler * @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 */ - public function __construct($level = Logger::DEBUG, $bubble = true) + public function __construct($level = Logger::DEBUG, bool $bubble = true) { $this->setLevel($level); $this->bubble = $bubble; diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 654e67181..474c4860e 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -46,9 +46,6 @@ public function handle(array $record): bool /** * Writes the record down to the log of the implementing handler - * - * @param array $record - * @return void */ - abstract protected function write(array $record); + abstract protected function write(array $record): void; } diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 0c692aa98..3428000e2 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -58,7 +58,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler * @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($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) + public function __construct($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 6e39a113d..064e50a99 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -36,7 +36,7 @@ class AmqpHandler extends AbstractProcessingHandler * @param int $level * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct($exchange, $exchangeName = null, $level = Logger::DEBUG, $bubble = true) + public function __construct($exchange, $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) { if ($exchange instanceof AMQPChannel) { $this->exchangeName = $exchangeName; @@ -53,7 +53,7 @@ public function __construct($exchange, $exchangeName = null, $level = Logger::DE /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $data = $record["formatted"]; $routingKey = $this->getRoutingKey($record); @@ -80,7 +80,7 @@ protected function write(array $record) /** * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->exchange instanceof AMQPExchange) { parent::handleBatch($records); diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 7774adefa..37a66d621 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -41,7 +41,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { // Accumulate records static::$records[] = $record; diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 676c7c142..a8a643945 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -39,7 +39,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @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, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) + public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, bool $bubble = true, $flushOnOverflow = false) { parent::__construct($level, $bubble); $this->handler = $handler; @@ -101,7 +101,7 @@ public function __destruct() /** * {@inheritdoc} */ - public function close() + public function close(): void { $this->flush(); } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 9c1ca5235..46ef7d341 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -64,7 +64,7 @@ class ChromePHPHandler extends AbstractProcessingHandler * @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($level = Logger::DEBUG, $bubble = true) + public function __construct($level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); if (!function_exists('json_encode')) { @@ -75,7 +75,7 @@ public function __construct($level = Logger::DEBUG, $bubble = true) /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if (!$this->isWebRequest()) { return; @@ -112,7 +112,7 @@ protected function getDefaultFormatter(): FormatterInterface * @see send() * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { if (!$this->isWebRequest()) { return; diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index e0603f343..b2d1e1897 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -24,7 +24,7 @@ class CouchDBHandler extends AbstractProcessingHandler { private $options; - public function __construct(array $options = [], $level = Logger::DEBUG, $bubble = true) + public function __construct(array $options = [], $level = Logger::DEBUG, bool $bubble = true) { $this->options = array_merge([ 'host' => 'localhost', @@ -40,7 +40,7 @@ public function __construct(array $options = [], $level = Logger::DEBUG, $bubble /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $basicAuth = null; if ($this->options['username']) { diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 82b169210..7de7705a7 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -35,7 +35,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($url, $level = Logger::DEBUG, $bubble = true) + public function __construct($url, $level = Logger::DEBUG, bool $bubble = true) { $urlInfo = parse_url($url); @@ -102,7 +102,7 @@ protected function connectHttp() /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $date = $record['datetime']; diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index b0bec3d9b..f1d0c17d9 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -29,7 +29,7 @@ class Util * @param resource $ch curl handler * @throws \RuntimeException */ - public static function execute($ch, $retries = 5, $closeAfterDone = true) + public static function execute($ch, int $retries = 5, bool $closeAfterDone = true): void { while ($retries--) { if (curl_exec($ch) === false) { @@ -42,7 +42,7 @@ public static function execute($ch, $retries = 5, $closeAfterDone = true) curl_close($ch); } - throw new \RuntimeException(sprintf('Curl error (code %s): %s', $curlErrno, $curlError)); + throw new \RuntimeException(sprintf('Curl error (code %d): %s', $curlErrno, $curlError)); } continue; diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 6d7753cba..ce4b99e27 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -62,7 +62,7 @@ class DeduplicationHandler extends BufferHandler * @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 */ - public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true) + public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, bool $bubble = true) { parent::__construct($handler, 0, Logger::DEBUG, $bubble, false); diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index 13a08eecf..b80490d13 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -25,7 +25,7 @@ class DoctrineCouchDBHandler extends AbstractProcessingHandler { private $client; - public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true) + public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool $bubble = true) { $this->client = $client; parent::__construct($level, $bubble); @@ -34,7 +34,7 @@ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubb /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->client->postDocument($record['formatted']); } diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index a6991fa93..cd2bc64af 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -54,7 +54,7 @@ class DynamoDbHandler extends AbstractProcessingHandler * @param int $level * @param bool $bubble */ - public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true) + public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, bool $bubble = true) { if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) { $this->version = 3; @@ -72,7 +72,7 @@ public function __construct(DynamoDbClient $client, $table, $level = Logger::DEB /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $filtered = $this->filterEmptyFields($record['formatted']); if ($this->version === 3) { diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index b7dc56760..619e84dc5 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -51,7 +51,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler * @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(Client $client, array $options = [], $level = Logger::DEBUG, $bubble = true) + public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; @@ -68,7 +68,7 @@ public function __construct(Client $client, array $options = [], $level = Logger /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->bulkSend([$record['formatted']]); } @@ -105,7 +105,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { $documents = $this->getFormatter()->formatBatch($records); $this->bulkSend($documents); diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 3108aed78..60f12d11b 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -34,7 +34,7 @@ class ErrorLogHandler extends AbstractProcessingHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries */ - public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false) + public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, bool $bubble = true, $expandNewlines = false) { parent::__construct($level, $bubble); @@ -70,7 +70,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!$this->expandNewlines) { error_log((string) $record['formatted'], $this->messageType); diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index b42ce9664..886178de0 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -52,7 +52,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface * @param int $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 */ - public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) + public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) { $this->handler = $handler; $this->bubble = $bubble; @@ -126,7 +126,7 @@ public function handle(array $record): bool /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { $filtered = []; foreach ($records as $record) { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 8943d4f01..8e33f2539 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -47,7 +47,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered */ - public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null) + public function __construct($handler, $activationStrategy = null, $bufferSize = 0, bool $bubble = true, $stopBuffering = true, $passthruLevel = null) { if (null === $activationStrategy) { $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); @@ -128,7 +128,7 @@ public function handle(array $record): bool /** * {@inheritdoc} */ - public function close() + public function close(): void { if (null !== $this->passthruLevel) { $level = $this->passthruLevel; diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 8f5c0c698..29b4714d9 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -130,7 +130,7 @@ protected function sendHeader($header, $content) * @see sendInitHeaders() * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { if (!self::$sendHeaders || !$this->isWebRequest()) { return; diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 748100b1b..2740b8836 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -45,7 +45,7 @@ class FleepHookHandler extends SocketHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @throws MissingExtensionException */ - public function __construct($token, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler'); @@ -74,7 +74,7 @@ protected function getDefaultFormatter(): FormatterInterface * * @param array $record */ - public function write(array $record) + public function write(array $record): void { parent::write($record); $this->closeSocket(); diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index 67d129189..096666226 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -40,7 +40,7 @@ class FlowdockHandler extends SocketHandler * * @throws MissingExtensionException if OpenSSL is missing */ - public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true) + public function __construct($apiToken, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); @@ -64,8 +64,6 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface /** * Gets the default formatter. - * - * @suppress PhanTypeMissingReturn */ protected function getDefaultFormatter(): FormatterInterface { @@ -77,7 +75,7 @@ protected function getDefaultFormatter(): FormatterInterface * * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { parent::write($record); diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 2b7e56f94..9acace45f 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -28,6 +28,7 @@ trait FormattableHandlerTrait /** * {@inheritdoc} + * @suppress PhanTypeMismatchReturn */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 53def8227..b5c113559 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -34,7 +34,7 @@ class GelfHandler extends AbstractProcessingHandler * @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(PublisherInterface $publisher, $level = Logger::DEBUG, $bubble = true) + public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -44,7 +44,7 @@ public function __construct(PublisherInterface $publisher, $level = Logger::DEBU /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->publisher->publish($record['formatted']); } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 30fd68ebe..6201ad00f 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -28,7 +28,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface * @param array $handlers Array of Handlers. * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct(array $handlers, $bubble = true) + public function __construct(array $handlers, bool $bubble = true) { foreach ($handlers as $handler) { if (!$handler instanceof HandlerInterface) { @@ -73,7 +73,7 @@ public function handle(array $record): bool /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->processors) { $processed = []; diff --git a/src/Monolog/Handler/Handler.php b/src/Monolog/Handler/Handler.php index 347e7b704..9f43fe10b 100644 --- a/src/Monolog/Handler/Handler.php +++ b/src/Monolog/Handler/Handler.php @@ -21,7 +21,7 @@ abstract class Handler implements HandlerInterface /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { foreach ($records as $record) { $this->handle($record); @@ -31,7 +31,7 @@ public function handleBatch(array $records) /** * {@inheritdoc} */ - public function close() + public function close(): void { } diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index 8ad7e38f8..d35161b5b 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -54,7 +54,7 @@ public function handle(array $record): bool; * * @param array $records The records to handle (an array of record arrays) */ - public function handleBatch(array $records); + public function handleBatch(array $records): void; /** * Closes the handler. @@ -64,5 +64,5 @@ public function handleBatch(array $records); * Implementations have to be idempotent (i.e. it should be possible to call close several times without breakage) * and ideally handlers should be able to reopen themselves on handle() after they have been closed. */ - public function close(); + public function close(): void; } diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index 28fe57d6c..8dc8a8469 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -65,17 +65,17 @@ public function handle(array $record): bool /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { - return $this->handler->handleBatch($records); + $this->handler->handleBatch($records); } /** * {@inheritdoc} */ - public function close() + public function close(): void { - return $this->handler->close(); + $this->handler->close(); } /** diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index 87286e3f3..ce09299db 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -80,7 +80,7 @@ class HipChatHandler extends SocketHandler * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) * @param string $host The HipChat server hostname. */ - public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com') + public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, bool $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com') { $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80'; parent::__construct($connectionString, $level, $bubble); @@ -140,11 +140,8 @@ private function buildContent($record) /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { // needed for rooms with special (spaces, etc) characters in the name $room = rawurlencode($this->room); @@ -160,11 +157,8 @@ private function buildHeader($content) /** * Assigns a color to each level of log records. - * - * @param int $level - * @return string */ - protected function getAlertColor($level) + protected function getAlertColor(int $level): string { switch (true) { case $level >= Logger::ERROR: @@ -182,10 +176,8 @@ protected function getAlertColor($level) /** * {@inheritdoc} - * - * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { parent::write($record); $this->finalizeWrite(); @@ -197,7 +189,7 @@ protected function write(array $record) * If we do not read some but close the socket too early, hipchat sometimes * drops the request entirely. */ - protected function finalizeWrite() + protected function finalizeWrite(): void { $res = $this->getResource(); if (is_resource($res)) { @@ -209,38 +201,25 @@ protected function finalizeWrite() /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if (count($records) == 0) { - return true; + return; } $batchRecords = $this->combineRecords($records); - $handled = false; foreach ($batchRecords as $batchRecord) { - if ($this->isHandling($batchRecord)) { - $this->write($batchRecord); - $handled = true; - } - } - - if (!$handled) { - return false; + $this->handle($batchRecord); } - - return false === $this->bubble; } /** * Combines multiple records into one. Error level of the combined record * will be the highest level from the given records. Datetime will be taken * from the first record. - * - * @param $records - * @return array */ - private function combineRecords($records) + private function combineRecords(array $records): array { $batchRecord = null; $batchRecords = []; diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index f5d440dfa..669b3f36f 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -35,7 +35,7 @@ class IFTTTHandler extends AbstractProcessingHandler * @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($eventName, $secretKey, $level = Logger::ERROR, $bubble = true) + public function __construct($eventName, $secretKey, $level = Logger::ERROR, bool $bubble = true) { $this->eventName = $eventName; $this->secretKey = $secretKey; @@ -46,7 +46,7 @@ public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bub /** * {@inheritdoc} */ - public function write(array $record) + public function write(array $record): void { $postData = [ "value1" => $record["channel"], diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index bd6dfe609..dfe1a9dcd 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -35,7 +35,7 @@ class InsightOpsHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index c74b9d2ee..a2671b0fe 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -31,7 +31,7 @@ class LogEntriesHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 544e7c7f7..647c7e136 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -32,7 +32,7 @@ class LogglyHandler extends AbstractProcessingHandler protected $tag = []; - public function __construct($token, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('curl')) { throw new \LogicException('The curl extension is needed to use the LogglyHandler'); @@ -57,12 +57,12 @@ public function addTag($tag) } } - protected function write(array $record) + protected function write(array $record): void { $this->send($record["formatted"], self::ENDPOINT_SINGLE); } - public function handleBatch(array $records) + public function handleBatch(array $records): void { $level = $this->level; diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 634fbc193..3bbfd5655 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -24,7 +24,7 @@ abstract class MailHandler extends AbstractProcessingHandler /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { $messages = []; @@ -46,17 +46,17 @@ public function handleBatch(array $records) * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content */ - abstract protected function send(string $content, array $records); + abstract protected function send(string $content, array $records): void; /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->send((string) $record['formatted'], [$record]); } - protected function getHighestRecord(array $records) + protected function getHighestRecord(array $records): array { $highestRecord = null; foreach ($records as $record) { @@ -68,7 +68,7 @@ protected function getHighestRecord(array $records) return $highestRecord; } - protected function isHtmlBody($body) + protected function isHtmlBody(string $body): bool { return substr($body, 0, 1) === '<'; } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 6cf90e7f7..f84aa8cc1 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Swift; /** * MandrillHandler uses cURL to send the emails to the Mandrill API @@ -29,7 +30,7 @@ class MandrillHandler extends MailHandler * @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($apiKey, $message, $level = Logger::ERROR, $bubble = true) + public function __construct($apiKey, $message, $level = Logger::ERROR, bool $bubble = true) { parent::__construct($level, $bubble); @@ -46,16 +47,20 @@ public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = /** * {@inheritdoc} */ - protected function send(string $content, array $records) + protected function send(string $content, array $records): void { - $mime = null; + $mime = 'text/plain'; if ($this->isHtmlBody($content)) { $mime = 'text/html'; } $message = clone $this->message; $message->setBody($content, $mime); - $message->setDate(time()); + if (version_compare(Swift::VERSION, '6.0.0', '>=')) { + $message->setDate(new \DateTimeImmutable()); + } else { + $message->setDate(time()); + } $ch = curl_init(); diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 5415ee525..98a238221 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -46,7 +46,7 @@ class MongoDBHandler extends AbstractProcessingHandler * @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($mongodb, $database, $collection, $level = Logger::DEBUG, $bubble = true) + public function __construct($mongodb, $database, $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'); @@ -62,7 +62,7 @@ public function __construct($mongodb, $database, $collection, $level = Logger::D parent::__construct($level, $bubble); } - protected function write(array $record) + protected function write(array $record): void { if (isset($this->collection)) { $this->collection->insertOne($record['formatted']); diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index b597761e7..b6f8dbbb5 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -72,7 +72,7 @@ class NativeMailerHandler extends MailHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int $maxColumnWidth The maximum column width that the message lines will have */ - public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) + public function __construct($to, $subject, $from, $level = Logger::ERROR, bool $bubble = true, $maxColumnWidth = 70) { parent::__construct($level, $bubble); $this->to = (array) $to; @@ -115,7 +115,7 @@ public function addParameter($parameters) /** * {@inheritdoc} */ - protected function send(string $content, array $records) + protected function send(string $content, array $records): void { $contentType = $this->getContentType() ?: ($this->isHtmlBody($content) ? 'text/html' : 'text/plain'); diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index d757067bf..c4540b69b 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -72,7 +72,7 @@ public function __construct( /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!$this->isNewRelicEnabled()) { throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index c2b7b3e87..f40e3d5f7 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -59,7 +59,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON 'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug - 'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) + 'dataStorage' => null, // \PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) ]; /** @var Connector */ @@ -68,11 +68,11 @@ class PHPConsoleHandler extends AbstractProcessingHandler /** * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param int $level + * @param int|string $level * @param bool $bubble * @throws \RuntimeException */ - public function __construct(array $options = [], Connector $connector = null, $level = Logger::DEBUG, $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'); @@ -92,7 +92,10 @@ private function initOptions(array $options) return array_replace($this->options, $options); } - private function initConnector(Connector $connector = null) + /** + * @suppress PhanTypeMismatchArgument + */ + private function initConnector(Connector $connector = null): Connector { if (!$connector) { if ($this->options['dataStorage']) { @@ -147,12 +150,12 @@ private function initConnector(Connector $connector = null) return $connector; } - public function getConnector() + public function getConnector(): Connector { return $this->connector; } - public function getOptions() + public function getOptions(): array { return $this->options; } @@ -172,7 +175,7 @@ public function handle(array $record): bool * @param array $record * @return void */ - protected function write(array $record) + protected function write(array $record): void { if ($record['level'] < Logger::NOTICE) { $this->handleDebugRecord($record); @@ -183,7 +186,7 @@ protected function write(array $record) } } - private function handleDebugRecord(array $record) + private function handleDebugRecord(array $record): void { $tags = $this->getRecordTags($record); $message = $record['message']; @@ -193,12 +196,12 @@ private function handleDebugRecord(array $record) $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } - private function handleExceptionRecord(array $record) + private function handleExceptionRecord(array $record): void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } - private function handleErrorRecord(array $record) + private function handleErrorRecord(array $record): void { $context = $record['context']; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 8cf6087b1..4478fe1d3 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -39,7 +39,7 @@ class ProcessHandler extends AbstractProcessingHandler private $command; /** - * @var string + * @var ?string */ private $cwd; @@ -62,10 +62,10 @@ class ProcessHandler extends AbstractProcessingHandler * especially if you do not use the $cwd parameter. * @param string|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. - * @param string $cwd "Current working directory" (CWD) for the process to be executed in. + * @param ?string $cwd "Current working directory" (CWD) for the process to be executed in. * @throws \InvalidArgumentException */ - public function __construct(string $command, $level = Logger::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.'); @@ -83,11 +83,9 @@ public function __construct(string $command, $level = Logger::DEBUG, bool $bubbl /** * Writes the record down to the log of the implementing handler * - * @param array $record * @throws \UnexpectedValueException - * @return void */ - protected function write(array $record) + protected function write(array $record): void { $this->ensureProcessIsStarted(); @@ -102,10 +100,8 @@ protected function write(array $record) /** * Makes sure that the process is actually started, and if not, starts it, * assigns the stream pipes, and handles startup errors, if any. - * - * @return void */ - private function ensureProcessIsStarted() + private function ensureProcessIsStarted(): void { if (is_resource($this->process) === false) { $this->startProcess(); @@ -116,10 +112,8 @@ private function ensureProcessIsStarted() /** * Starts the actual process and sets all streams to non-blocking. - * - * @return void */ - private function startProcess() + private function startProcess(): void { $this->process = proc_open($this->command, self::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); @@ -132,9 +126,8 @@ private function startProcess() * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any. * * @throws \UnexpectedValueException - * @return void */ - private function handleStartupErrors() + private function handleStartupErrors(): void { $selected = $this->selectErrorStream(); if (false === $selected) { @@ -169,7 +162,7 @@ protected function selectErrorStream() * @codeCoverageIgnore * @return string Empty string if there are no errors. */ - protected function readProcessErrors() + protected function readProcessErrors(): string { return stream_get_contents($this->pipes[2]); } @@ -178,18 +171,16 @@ protected function readProcessErrors() * Writes to the input stream of the opened process. * * @codeCoverageIgnore - * @param $string - * @return void */ - protected function writeProcessInput($string) + protected function writeProcessInput(string $string): void { - fwrite($this->pipes[0], (string) $string); + fwrite($this->pipes[0], $string); } /** * {@inheritdoc} */ - public function close() + public function close(): void { if (is_resource($this->process)) { foreach ($this->pipes as $pipe) { diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index bba940e83..a78b64159 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -25,6 +25,7 @@ trait ProcessableHandlerTrait /** * {@inheritdoc} + * @suppress PhanTypeMismatchReturn */ public function pushProcessor(callable $callback): HandlerInterface { diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index e39233b46..b59e99af1 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -33,7 +33,7 @@ class PsrHandler extends AbstractHandler * @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(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true) + public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 3e6834228..c6cba6e80 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -79,7 +79,7 @@ class PushoverHandler extends SocketHandler * @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). */ - public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) + public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, bool $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) { $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; parent::__construct($connectionString, $level, $bubble); @@ -152,7 +152,7 @@ private function buildHeader($content) return $header; } - protected function write(array $record) + protected function write(array $record): void { foreach ($this->users as $user) { $this->user = $user; diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 7ea5fd7d9..801e52c1d 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -59,7 +59,7 @@ class RavenHandler extends AbstractProcessingHandler * @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(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) + public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -69,7 +69,7 @@ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $ /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { $level = $this->level; @@ -130,8 +130,9 @@ public function getBatchFormatter() /** * {@inheritdoc} + * @suppress PhanTypeMismatchArgument */ - protected function write(array $record) + protected function write(array $record): void { /** @var bool|null|array This is false, unless set below to null or an array of data, when we read the current user context */ $previousUserContext = false; diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index e7ddb44bb..ede8be318 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -55,7 +55,7 @@ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $b /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if ($this->capSize) { $this->writeCapped($record); diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 2f35093cb..4df6f15e4 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -63,7 +63,7 @@ class RollbarHandler extends AbstractProcessingHandler * @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(RollbarLogger $rollbarLogger, $level = Logger::ERROR, $bubble = true) + public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true) { $this->rollbarLogger = $rollbarLogger; @@ -73,7 +73,7 @@ public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors @@ -113,7 +113,7 @@ public function flush() /** * {@inheritdoc} */ - public function close() + public function close(): void { $this->flush(); } diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index d9733ba00..32fbb8771 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -44,7 +44,7 @@ class RotatingFileHandler extends StreamHandler * @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($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) + public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, $filePermission = null, $useLocking = false) { $this->filename = $filename; $this->maxFiles = (int) $maxFiles; @@ -58,7 +58,7 @@ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $b /** * {@inheritdoc} */ - public function close() + public function close(): void { parent::close(); @@ -91,7 +91,7 @@ public function setFilenameFormat($filenameFormat, $dateFormat) /** * {@inheritdoc} */ - protected function write(array $record) + 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) { @@ -109,7 +109,7 @@ protected function write(array $record) /** * Rotates the files. */ - protected function rotate() + protected function rotate(): void { // update filename $this->url = $this->getTimedFilename(); @@ -135,7 +135,8 @@ protected function rotate() if (is_writable($file)) { // suppress errors here as unlink() might fail if two processes // are cleaning up/rotating at the same time - set_error_handler(function ($errno, $errstr, $errfile, $errline) { + set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline): bool { + return false; }); unlink($file); restore_error_handler(); diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 7d82d9465..c154a5d17 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -72,7 +72,7 @@ public function __construct(string $apiUser, string $apiKey, string $from, $to, /** * {@inheritdoc} */ - protected function send(string $content, array $records) + protected function send(string $content, array $records): void { $message = []; $message['api_user'] = $this->apiUser; diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 6f671ac12..30a10fc12 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -48,7 +48,7 @@ class SlackHandler extends SocketHandler * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ - public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array()) + public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, bool $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array()) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); @@ -145,7 +145,7 @@ private function buildHeader($content) * * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { parent::write($record); $this->finalizeWrite(); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 2904db3f1..9c26486ca 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -47,7 +47,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ - public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, $bubble = true, array $excludeFields = array()) + public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, bool $bubble = true, array $excludeFields = array()) { parent::__construct($level, $bubble); @@ -79,7 +79,7 @@ public function getWebhookUrl() * * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { $postData = $this->slackRecord->getSlackData($record); $postString = json_encode($postData); diff --git a/src/Monolog/Handler/SlackbotHandler.php b/src/Monolog/Handler/SlackbotHandler.php index dd2db593e..3a1dfa5c6 100644 --- a/src/Monolog/Handler/SlackbotHandler.php +++ b/src/Monolog/Handler/SlackbotHandler.php @@ -46,7 +46,7 @@ class SlackbotHandler extends AbstractProcessingHandler * @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($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true) + public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, bool $bubble = true) { parent::__construct($level, $bubble); @@ -60,7 +60,7 @@ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITI * * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { $slackbotUrl = sprintf( 'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s', diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 36ea0b5f2..3dc6d9754 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -30,6 +30,7 @@ class SocketHandler extends AbstractProcessingHandler /** @var float */ private $writingTimeout = 10; private $lastSentBytes = null; + /** @var int */ private $chunkSize = null; private $persistent = false; private $errno; @@ -41,7 +42,7 @@ class SocketHandler extends AbstractProcessingHandler * @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($connectionString, $level = Logger::DEBUG, $bubble = true) + public function __construct($connectionString, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); $this->connectionString = $connectionString; @@ -56,7 +57,7 @@ public function __construct($connectionString, $level = Logger::DEBUG, $bubble = * @throws \UnexpectedValueException * @throws \RuntimeException */ - protected function write(array $record) + protected function write(array $record): void { $this->connectIfNotConnected(); $data = $this->generateDataStream($record); @@ -66,7 +67,7 @@ protected function write(array $record) /** * We will not close a PersistentSocket instance so it can be reused in other requests. */ - public function close() + public function close(): void { if (!$this->isPersistent()) { $this->closeSocket(); @@ -76,7 +77,7 @@ public function close() /** * Close socket, if open */ - public function closeSocket() + public function closeSocket(): void { if (is_resource($this->resource)) { fclose($this->resource); @@ -85,23 +86,19 @@ public function closeSocket() } /** - * Set socket connection to nbe persistent. It only has effect before the connection is initiated. - * - * @param bool $persistent + * Set socket connection to be persistent. It only has effect before the connection is initiated. */ - public function setPersistent($persistent) + public function setPersistent(bool $persistent): void { - $this->persistent = (bool) $persistent; + $this->persistent = $persistent; } /** * Set connection timeout. Only has effect before we connect. * - * @param float $seconds - * * @see http://php.net/manual/en/function.fsockopen.php */ - public function setConnectionTimeout($seconds) + public function setConnectionTimeout(float $seconds): void { $this->validateTimeout($seconds); $this->connectionTimeout = (float) $seconds; @@ -110,11 +107,9 @@ public function setConnectionTimeout($seconds) /** * Set write timeout. Only has effect before we connect. * - * @param float $seconds - * * @see http://php.net/manual/en/function.stream-set-timeout.php */ - public function setTimeout($seconds) + public function setTimeout(float $seconds): void { $this->validateTimeout($seconds); $this->timeout = (float) $seconds; @@ -125,7 +120,7 @@ public function setTimeout($seconds) * * @param float $seconds 0 for no timeout */ - public function setWritingTimeout($seconds) + public function setWritingTimeout(float $seconds): void { $this->validateTimeout($seconds); $this->writingTimeout = (float) $seconds; @@ -133,20 +128,16 @@ public function setWritingTimeout($seconds) /** * Set chunk size. Only has effect during connection in the writing cycle. - * - * @param float $bytes */ - public function setChunkSize($bytes) + public function setChunkSize(int $bytes): void { $this->chunkSize = $bytes; } /** * Get current connection string - * - * @return string */ - public function getConnectionString() + public function getConnectionString(): string { return $this->connectionString; } @@ -189,10 +180,8 @@ public function getWritingTimeout(): float /** * Get current chunk size - * - * @return float */ - public function getChunkSize() + public function getChunkSize(): int { return $this->chunkSize; } @@ -201,10 +190,8 @@ public function getChunkSize() * Check to see if the socket is currently available. * * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. - * - * @return bool */ - public function isConnected() + public function isConnected(): bool { return is_resource($this->resource) && !feof($this->resource); // on TCP - other party can close connection. diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index ed595c714..f282d023b 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -31,7 +31,7 @@ class SqsHandler extends AbstractProcessingHandler /** @var string */ private $queueUrl; - public function __construct(SqsClient $sqsClient, $queueUrl, $level = Logger::DEBUG, $bubble = true) + public function __construct(SqsClient $sqsClient, $queueUrl, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -44,7 +44,7 @@ public function __construct(SqsClient $sqsClient, $queueUrl, $level = Logger::DE * * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) { throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string'); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 6631ef4e1..92ccc04d1 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -41,7 +41,7 @@ class StreamHandler extends AbstractProcessingHandler * @throws \Exception If a missing directory is not buildable * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) + public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, $filePermission = null, $useLocking = false) { parent::__construct($level, $bubble); if (is_resource($stream)) { @@ -59,7 +59,7 @@ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $fi /** * {@inheritdoc} */ - public function close() + public function close(): void { if ($this->url && is_resource($this->stream)) { fclose($this->stream); @@ -90,7 +90,7 @@ public function getUrl() /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!is_resource($this->stream)) { if (null === $this->url || '' === $this->url) { @@ -138,12 +138,7 @@ private function customErrorHandler($code, $msg) $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); } - /** - * @param string $stream - * - * @return null|string - */ - private function getDirFromStream($stream) + private function getDirFromStream(string $stream): ?string { $pos = strpos($stream, '://'); if ($pos === false) { @@ -154,7 +149,7 @@ private function getDirFromStream($stream) return dirname(substr($stream, 7)); } - return; + return null; } private function createDir() diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 73ef3cfc9..4fa14ca87 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -44,7 +44,7 @@ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ER /** * {@inheritdoc} */ - protected function send(string $content, array $records) + protected function send(string $content, array $records): void { $this->mailer->send($this->buildMessage($content, $records)); } @@ -85,7 +85,7 @@ protected function buildMessage(string $content, array $records): Swift_Message $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } - $mime = null; + $mime = 'text/plain'; if ($this->isHtmlBody($content)) { $mime = 'text/html'; } diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index df7c89a85..fb7faef63 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -38,7 +38,7 @@ class SyslogHandler extends AbstractSyslogHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ - public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) + public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, $logopts = LOG_PID) { parent::__construct($facility, $level, $bubble); @@ -49,7 +49,7 @@ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG /** * {@inheritdoc} */ - public function close() + public function close(): void { closelog(); } @@ -57,7 +57,7 @@ public function close() /** * {@inheritdoc} */ - protected function write(array $record) + 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.'"'); diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index f1801b375..91888ac56 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -33,7 +33,7 @@ public function write($line, $header = "") $this->send($this->assembleMessage($line, $header)); } - public function close() + public function close(): void { if (is_resource($this->socket)) { socket_close($this->socket); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index dc8440200..103206bbf 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -32,7 +32,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @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. */ - public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php') + public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, $ident = 'php') { parent::__construct($facility, $level, $bubble); @@ -41,7 +41,7 @@ public function __construct($host, $port = 514, $facility = LOG_USER, $level = L $this->socket = new UdpSocket($host, $port ?: 514); } - protected function write(array $record) + protected function write(array $record): void { $lines = $this->splitMessageIntoLines($record['formatted']); @@ -52,7 +52,7 @@ protected function write(array $record) } } - public function close() + public function close(): void { $this->socket->close(); } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 55c483342..db9174e25 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -138,7 +138,7 @@ public function hasRecordThatPasses(callable $predicate, $level) /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->recordsByLevel[$record['level']][] = $record; $this->records[] = $record; diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index c2a58d5da..5c1f86b1d 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -44,7 +44,7 @@ public function handle(array $record): bool /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->processors) { $processed = array(); diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index c0bceb423..95eca6d59 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -45,7 +45,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler * @param bool $bubble * @throws MissingExtensionException */ - public function __construct($level = Logger::DEBUG, $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 in order to use this handler'); @@ -56,7 +56,7 @@ public function __construct($level = Logger::DEBUG, $bubble = true) /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->writeZendMonitorCustomEvent( $this->levelMap[$record['level']], @@ -65,14 +65,7 @@ protected function write(array $record) ); } - /** - * Write a record to Zend Monitor - * - * @param int $level - * @param string $message - * @param array $formatted - */ - protected function writeZendMonitorCustomEvent($level, $message, $formatted) + protected function writeZendMonitorCustomEvent(int $level, string $message, array $formatted) { zend_monitor_custom_event($level, $message, $formatted); } @@ -85,12 +78,7 @@ public function getDefaultFormatter(): FormatterInterface return new NormalizerFormatter(); } - /** - * Get the level map - * - * @return array - */ - public function getLevelMap() + public function getLevelMap(): array { return $this->levelMap; } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index a22bf7ec0..876fd0515 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -135,7 +135,7 @@ class Logger implements LoggerInterface protected $timezone; /** - * @var callable + * @var ?callable */ protected $exceptionHandler; @@ -143,9 +143,9 @@ class Logger implements LoggerInterface * @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 $timezone Optional timezone, if not provided date_default_timezone_get() will be used + * @param ?DateTimeZone $timezone Optional timezone, if not provided date_default_timezone_get() will be used */ - public function __construct(string $name, array $handlers = [], array $processors = [], DateTimeZone $timezone = null) + public function __construct(string $name, array $handlers = [], array $processors = [], ?DateTimeZone $timezone = null) { $this->name = $name; $this->setHandlers($handlers); @@ -360,7 +360,7 @@ public static function getLevelName(int $level): string /** * Converts PSR-3 levels to Monolog ones if necessary * - * @param string|int Level number (monolog) or name (PSR-3) + * @param string|int $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined */ public static function toMonologLevel($level): int diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 7311c2be1..ef8c4b2e5 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -22,16 +22,17 @@ class PsrLogMessageProcessor { const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; + /** @var ?string */ private $dateFormat; /** @var bool */ private $removeUsedContextFields; /** - * @param string $dateFormat The format of the timestamp: one supported by DateTime::format - * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset + * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset */ - public function __construct(string $dateFormat = null, bool $removeUsedContextFields = false) + public function __construct(?string $dateFormat = null, bool $removeUsedContextFields = false) { $this->dateFormat = $dateFormat; $this->removeUsedContextFields = $removeUsedContextFields; diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 23cf9add8..ecb8907f3 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -25,10 +25,10 @@ class TestCase extends \PHPUnit\Framework\TestCase /** * @return array Record */ - protected function getRecord($level = Logger::WARNING, $message = 'test', $context = []) + protected function getRecord($level = Logger::WARNING, $message = 'test', array $context = []): array { return [ - 'message' => $message, + 'message' => (string) $message, 'context' => $context, 'level' => $level, 'level_name' => Logger::getLevelName($level), @@ -38,10 +38,7 @@ protected function getRecord($level = Logger::WARNING, $message = 'test', $conte ]; } - /** - * @return array - */ - protected function getMultipleRecords() + protected function getMultipleRecords(): array { return [ $this->getRecord(Logger::DEBUG, 'debug message 1'), @@ -52,6 +49,9 @@ protected function getMultipleRecords() ]; } + /** + * @suppress PhanTypeMismatchReturn + */ protected function getIdentityFormatter(): FormatterInterface { $formatter = $this->createMock(FormatterInterface::class); diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index bedc17508..42fff1c6d 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -82,9 +82,8 @@ public function testHandleBatch($result) $records = $this->getMultipleRecords(); $this->handler->expects($this->once()) ->method('handleBatch') - ->with($records) - ->willReturn($result); + ->with($records); - $this->assertEquals($result, $this->wrapper->handleBatch($records)); + $this->wrapper->handleBatch($records); } } From c9d15bb8086fcde0a537cf6352072c9d5cdc5d74 Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Tue, 31 May 2016 20:48:51 +1000 Subject: [PATCH 023/498] Add fluent setters for parameters in the slack handler --- src/Monolog/Handler/Slack/SlackRecord.php | 139 +++++++++++++++++++--- src/Monolog/Handler/SlackHandler.php | 88 ++++++++++++++ 2 files changed, 210 insertions(+), 17 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 90286e888..8a1726a6d 100755 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -85,26 +85,31 @@ class SlackRecord */ private $normalizerFormatter; - public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) - { - $this->channel = $channel; - $this->username = $username; - $this->userIcon = $userIcon !== null ? trim($userIcon, ':') : null; - $this->useAttachment = $useAttachment; - $this->useShortAttachment = $useShortAttachment; - $this->includeContextAndExtra = $includeContextAndExtra; - $this->excludeFields = $excludeFields; - $this->formatter = $formatter; - - if ($this->includeContextAndExtra) { - $this->normalizerFormatter = new NormalizerFormatter(); - } + public function __construct( + $channel = null, + $username = null, + $useAttachment = true, + $userIcon = null, + $useShortAttachment = false, + $includeContextAndExtra = false, + array $excludeFields = array(), + FormatterInterface $formatter = null + ) { + $this + ->setChannel($channel) + ->setUsername($username) + ->useAttachment($useAttachment) + ->setUserIcon($userIcon) + ->useShortAttachment($useShortAttachment) + ->includeContextAndExtra($includeContextAndExtra) + ->excludeFields($excludeFields) + ->setFormatter($formatter); } public function getSlackData(array $record) { $dataArray = array(); - $record = $this->excludeFields($record); + $record = $this->removeExcludedFields($record); if ($this->username) { $dataArray['username'] = $this->username; @@ -215,14 +220,114 @@ public function stringify($fields) : json_encode($normalized, JSON_UNESCAPED_UNICODE); } + /** + * Channel used by the bot when posting + * + * @param ?string $channel + * + * @return SlackHandler + */ + public function setChannel(?string $channel = null): self + { + $this->channel = $channel; + + return $this; + } + + /** + * Username used by the bot when posting + * + * @param ?string $username + * + * @return SlackHandler + */ + public function setUsername(?string $username = null): self + { + $this->username = $username; + + return $this; + } + + /** + * @param bool $useAttachment + * + * @return SlackHandler + */ + public function useAttachment(bool $useAttachment = true): self + { + $this->useAttachment = $useAttachment; + + return $this; + } + + /** + * @param string $userIcon + * + * @return SlackHandler + */ + public function setUserIcon(?string $userIcon = null): self + { + $this->userIcon = $userIcon; + + if (\is_string($userIcon)) { + $this->userIcon = trim($userIcon, ':'); + } + + return $this; + } + + /** + * @param bool $useShortAttachment + * + * @return SlackHandler + */ + public function useShortAttachment(bool $useShortAttachment = false): self + { + $this->useShortAttachment = $useShortAttachment; + + return $this; + } + + /** + * @param bool $includeContextAndExtra + * + * @return SlackHandler + */ + public function includeContextAndExtra(bool $includeContextAndExtra = false): self + { + $this->includeContextAndExtra = $includeContextAndExtra; + + if ($this->includeContextAndExtra) { + $this->normalizerFormatter = new NormalizerFormatter(); + } + + return $this; + } + + /** + * @param array $excludeFields + * + * @return SlackHandler + */ + public function excludeFields(array $excludeFields = []): self + { + $this->excludeFields = $excludeFields; + + return $this; + } + /** * Sets the formatter * * @param FormatterInterface $formatter + * + * @return SlackHandler */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(?FormatterInterface $formatter = null): self { $this->formatter = $formatter; + + return $this; } /** @@ -270,7 +375,7 @@ private function generateAttachmentFields(array $data) * * @return array */ - private function excludeFields(array $record) + private function removeExcludedFields(array $record) { foreach ($this->excludeFields as $field) { $keys = explode('.', $field); diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 6f671ac12..ec6784774 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -216,4 +216,92 @@ public function getFormatter(): FormatterInterface return $formatter; } + + /** + * Channel used by the bot when posting + * + * @param string $channel + * + * @return SlackHandler + */ + public function setChannel(string $channel): self + { + $this->slackRecord->setChannel($channel); + + return $this; + } + + /** + * Username used by the bot when posting + * + * @param string $username + * + * @return SlackHandler + */ + public function setUsername(string $username): self + { + $this->slackRecord->setUsername($username); + + return $this; + } + + /** + * @param bool $useAttachment + * + * @return SlackHandler + */ + public function useAttachment(bool $useAttachment): self + { + $this->slackRecord->useAttachment($useAttachment); + + return $this; + } + + /** + * @param string $iconEmoji + * + * @return SlackHandler + */ + public function setIconEmoji(string $iconEmoji): self + { + $this->slackRecord->setUserIcon($iconEmoji); + + return $this; + } + + /** + * @param bool $useShortAttachment + * + * @return SlackHandler + */ + public function useShortAttachment(bool $useShortAttachment): self + { + $this->slackRecord->useShortAttachment($useShortAttachment); + + return $this; + } + + /** + * @param bool $includeContextAndExtra + * + * @return SlackHandler + */ + public function includeContextAndExtra(bool $includeContextAndExtra): self + { + $this->slackRecord->includeContextAndExtra($includeContextAndExtra); + + return $this; + } + + /** + * @param array $excludeFields + * + * @return SlackHandler + */ + public function excludeFields(array $excludeFields): self + { + $this->slackRecord->excludeFields($excludeFields); + + return $this; + } } From 0625068bf0a6667d18cca284eda1ba40907d2538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 31 May 2017 17:19:21 +0200 Subject: [PATCH 024/498] Added a new ResettableInterface and implemented it where possible. When one use Monolog in a long process like an AMQP worker with a `FingersCrossedHandler` or `BufferHandler` there is a drawback: as soon as there is an AMQP message that generate a log >= error (for example), all next AMQP messages will output logs, even if theses messages don't generate log where level >= error. In the same context there is a drawback for processor that add an UUID to the logs. The UUID should change for each AMQP messages. --- This patch address this issue with a new interface: `ResettableInterface` interface. Side note: `reset()`, `flush()`, `clear()`, are already used in Monolog. So basically, one can use the `reset()` on the `Logger` and on some `Handler`s / `Processor`s. It's especially useful for * the `FingersCrossedHandler`: it `close()` the buffer, then it `clear()` the buffer. * the `BufferHandler`: it `flush()` the buffer, then it `clear()` the buffer. * the `UidProcessor`: it renew the `uid`. --- CHANGELOG.md | 2 + src/Monolog/Handler/AbstractHandler.php | 16 +++- .../Handler/AbstractProcessingHandler.php | 2 + src/Monolog/Handler/BrowserConsoleHandler.php | 9 ++- src/Monolog/Handler/BufferHandler.php | 10 +++ src/Monolog/Handler/FingersCrossedHandler.php | 8 ++ src/Monolog/Handler/GroupHandler.php | 12 +++ src/Monolog/Handler/HandlerWrapper.php | 10 ++- src/Monolog/Logger.php | 17 ++++- src/Monolog/Processor/UidProcessor.php | 17 ++++- src/Monolog/ResettableInterface.php | 25 +++++++ .../Handler/BrowserConsoleHandlerTest.php | 2 +- .../Monolog/Handler/ChromePHPHandlerTest.php | 4 +- .../Handler/FingersCrossedHandlerTest.php | 4 +- tests/Monolog/Handler/FirePHPHandlerTest.php | 4 +- tests/Monolog/LoggerTest.php | 73 +++++++++++++++++++ 16 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 src/Monolog/ResettableInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a69362b68..75ac442b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ * Fixed table row styling issues in HtmlFormatter * Fixed RavenHandler dropping the message when logging exception * Fixed WhatFailureGroupHandler skipping processors when using handleBatch + * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors + and implement it where possible ### 1.23.0 (2017-06-19) diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index bf56549d5..b286a01c0 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -11,16 +11,17 @@ namespace Monolog\Handler; -use Monolog\Logger; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; +use Monolog\Logger; +use Monolog\ResettableInterface; /** * Base Handler class providing the Handler structure * * @author Jordi Boggiano */ -abstract class AbstractHandler implements HandlerInterface +abstract class AbstractHandler implements HandlerInterface, ResettableInterface { protected $level = Logger::DEBUG; protected $bubble = true; @@ -174,6 +175,17 @@ public function __destruct() } } + public function reset() + { + $this->close(); + + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } + /** * Gets the default formatter. * diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 6f18f72e1..e1e89530a 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\ResettableInterface; + /** * Base Handler class providing the Handler structure * diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 0225ee714..14fa0dc70 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -69,14 +69,19 @@ public static function send() } elseif ($format === 'js') { static::writeOutput(static::generateScript()); } - static::reset(); + static::resetStatic(); } } + public function reset() + { + self::resetStatic(); + } + /** * Forget all logged records */ - public static function reset() + public static function resetStatic() { static::$records = array(); } diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index c15e28a24..ca2c7a799 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\ResettableInterface; /** * Buffers all records until closing the handler and then pass them as batch. @@ -114,4 +115,13 @@ public function clear() $this->bufferSize = 0; $this->buffer = array(); } + + public function reset() + { + parent::reset(); + + if ($this->handler instanceof ResettableInterface) { + $this->handler->reset(); + } + } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index d8026be6f..a2d85dde6 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -14,6 +14,7 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Logger; +use Monolog\ResettableInterface; /** * Buffers all records until a certain level is reached @@ -147,7 +148,14 @@ public function close() */ public function reset() { + parent::reset(); + + $this->buffer = array(); $this->buffering = true; + + if ($this->handler instanceof ResettableInterface) { + $this->handler->reset(); + } } /** diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index c38508c25..28e5c5648 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; +use Monolog\ResettableInterface; /** * Forwards records to multiple handlers @@ -90,6 +91,17 @@ public function handleBatch(array $records) } } + public function reset() + { + parent::reset(); + + foreach ($this->handlers as $handler) { + if ($handler instanceof ResettableInterface) { + $handler->reset(); + } + } + } + /** * {@inheritdoc} */ diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index e540d80f4..55e649868 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; /** @@ -30,7 +31,7 @@ * * @author Alexey Karapetov */ -class HandlerWrapper implements HandlerInterface +class HandlerWrapper implements HandlerInterface, ResettableInterface { /** * @var HandlerInterface @@ -105,4 +106,11 @@ public function getFormatter() { return $this->handler->getFormatter(); } + + public function reset() + { + if ($this->handler instanceof ResettableInterface) { + return $this->handler->reset(); + } + } } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 5034ead19..d998bb655 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -25,7 +25,7 @@ * * @author Jordi Boggiano */ -class Logger implements LoggerInterface +class Logger implements LoggerInterface, ResettableInterface { /** * Detailed debug information @@ -354,6 +354,21 @@ public function addRecord($level, $message, array $context = array()) return true; } + public function reset() + { + foreach ($this->handlers as $handler) { + if ($handler instanceof ResettableInterface) { + $handler->reset(); + } + } + + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } + /** * Adds a log record at the DEBUG level. * diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 812707cdb..47f13f007 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -11,12 +11,14 @@ namespace Monolog\Processor; +use Monolog\ResettableInterface; + /** * Adds a unique identifier into records * * @author Simon Mönch */ -class UidProcessor +class UidProcessor implements ResettableInterface { private $uid; @@ -26,7 +28,8 @@ public function __construct($length = 7) throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); } - $this->uid = substr(hash('md5', uniqid('', true)), 0, $length); + + $this->uid = $this->generateUid($length); } public function __invoke(array $record) @@ -43,4 +46,14 @@ public function getUid() { return $this->uid; } + + public function reset() + { + $this->uid = $this->generateUid(strlen($this->uid)); + } + + private function generateUid($length) + { + return substr(hash('md5', uniqid('', true)), 0, $length); + } } diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php new file mode 100644 index 000000000..5e7bd6f3a --- /dev/null +++ b/src/Monolog/ResettableInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +/** + * Handler or Processor implementing this interface will be reset when Logger::reset() is called. + * + * Resetting an Handler or a Processor usually means cleaning all buffers or + * resetting in its internal state. + * + * @author Grégoire Pineau + */ +interface ResettableInterface +{ + public function reset(); +} diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index ffb1d746a..ffe45da2f 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -21,7 +21,7 @@ class BrowserConsoleHandlerTest extends TestCase { protected function setUp() { - BrowserConsoleHandler::reset(); + BrowserConsoleHandler::resetStatic(); } protected function generateScript() diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 0449f8b1a..421cc4918 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -21,7 +21,7 @@ class ChromePHPHandlerTest extends TestCase { protected function setUp() { - TestChromePHPHandler::reset(); + TestChromePHPHandler::resetStatic(); $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0'; } @@ -136,7 +136,7 @@ class TestChromePHPHandler extends ChromePHPHandler { protected $headers = array(); - public static function reset() + public static function resetStatic() { self::$initialized = false; self::$overflowed = false; diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index b92bf437b..0ec36531a 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -58,7 +58,7 @@ public function testHandleStopsBufferingAfterTrigger() * @covers Monolog\Handler\FingersCrossedHandler::activate * @covers Monolog\Handler\FingersCrossedHandler::reset */ - public function testHandleRestartBufferingAfterReset() + public function testHandleResetBufferingAfterReset() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test); @@ -76,7 +76,7 @@ public function testHandleRestartBufferingAfterReset() * @covers Monolog\Handler\FingersCrossedHandler::handle * @covers Monolog\Handler\FingersCrossedHandler::activate */ - public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled() + public function testHandleResetBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false); diff --git a/tests/Monolog/Handler/FirePHPHandlerTest.php b/tests/Monolog/Handler/FirePHPHandlerTest.php index 0eb10a63f..7a404e660 100644 --- a/tests/Monolog/Handler/FirePHPHandlerTest.php +++ b/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -21,7 +21,7 @@ class FirePHPHandlerTest extends TestCase { public function setUp() { - TestFirePHPHandler::reset(); + TestFirePHPHandler::resetStatic(); $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0'; } @@ -77,7 +77,7 @@ class TestFirePHPHandler extends FirePHPHandler { protected $headers = array(); - public static function reset() + public static function resetStatic() { self::$initialized = false; self::$sendHeaders = true; diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index f938ea028..442e87dea 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -614,4 +614,77 @@ public function testCustomHandleException() $logger->pushHandler($handler); $logger->info('test'); } + + public function testReset() + { + $logger = new Logger('app'); + + $testHandler = new Handler\TestHandler(); + $bufferHandler = new Handler\BufferHandler($testHandler); + $groupHandler = new Handler\GroupHandler(array($bufferHandler)); + $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler); + + $logger->pushHandler($fingersCrossedHandler); + + $processorUid1 = new Processor\UidProcessor(10); + $uid1 = $processorUid1->getUid(); + $groupHandler->pushProcessor($processorUid1); + + $processorUid2 = new Processor\UidProcessor(5); + $uid2 = $processorUid2->getUid(); + $logger->pushProcessor($processorUid2); + + $getProperty = function ($object, $property) { + $reflectionProperty = new \ReflectionProperty(get_class($object), $property); + $reflectionProperty->setAccessible(true); + + return $reflectionProperty->getValue($object); + }; + $that = $this; + $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) { + $that->assertEmpty($getProperty($bufferHandler, 'buffer')); + }; + $assertBuffersEmpty = function() use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) { + $assertBufferOfBufferHandlerEmpty(); + $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); + }; + + $logger->debug('debug'); + $logger->reset(); + $assertBuffersEmpty(); + $this->assertFalse($testHandler->hasDebugRecords()); + $this->assertFalse($testHandler->hasErrorRecords()); + $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); + $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); + + $logger->debug('debug'); + $logger->error('error'); + $logger->reset(); + $assertBuffersEmpty(); + $this->assertTrue($testHandler->hasDebugRecords()); + $this->assertTrue($testHandler->hasErrorRecords()); + $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); + $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); + + $logger->info('info'); + $this->assertNotEmpty($getProperty($fingersCrossedHandler, 'buffer')); + $assertBufferOfBufferHandlerEmpty(); + $this->assertFalse($testHandler->hasInfoRecords()); + + $logger->reset(); + $assertBuffersEmpty(); + $this->assertFalse($testHandler->hasInfoRecords()); + $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); + $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); + + $logger->notice('notice'); + $logger->emergency('emergency'); + $logger->reset(); + $assertBuffersEmpty(); + $this->assertFalse($testHandler->hasInfoRecords()); + $this->assertTrue($testHandler->hasNoticeRecords()); + $this->assertTrue($testHandler->hasEmergencyRecords()); + $this->assertNotSame($uid1, $processorUid1->getUid()); + $this->assertNotSame($uid2, $processorUid2->getUid()); + } } From b6b455ed1150567eebe41adef25cc1e58e981531 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 17 Jul 2018 17:19:56 +0100 Subject: [PATCH 025/498] Add scalar hints and return types to the SlackRecord handler. --- src/Monolog/Handler/Slack/SlackRecord.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 90286e888..91413e5fc 100755 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -47,7 +47,7 @@ class SlackRecord /** * User icon e.g. 'ghost', 'http://example.com/user.png' - * @var string + * @var string|null */ private $userIcon; @@ -85,7 +85,7 @@ class SlackRecord */ private $normalizerFormatter; - public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) + public function __construct(?string $channel = null, ?string $username = null, bool $useAttachment = true, ?string $userIcon = null, bool $useShortAttachment = false, bool $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) { $this->channel = $channel; $this->username = $username; @@ -101,7 +101,7 @@ public function __construct($channel = null, $username = null, $useAttachment = } } - public function getSlackData(array $record) + public function getSlackData(array $record): array { $dataArray = array(); $record = $this->excludeFields($record); @@ -181,7 +181,7 @@ public function getSlackData(array $record) * @param int $level * @return string */ - public function getAttachmentColor($level) + public function getAttachmentColor(int $level): string { switch (true) { case $level >= Logger::ERROR: @@ -202,7 +202,7 @@ public function getAttachmentColor($level) * * @return string */ - public function stringify($fields) + public function stringify(array $fields): string { $normalized = $this->normalizerFormatter->format($fields); $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; @@ -220,7 +220,7 @@ public function stringify($fields) * * @param FormatterInterface $formatter */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): void { $this->formatter = $formatter; } @@ -233,7 +233,7 @@ public function setFormatter(FormatterInterface $formatter) * * @return array */ - private function generateAttachmentField($title, $value) + private function generateAttachmentField(string $title, $value): array { $value = is_array($value) ? sprintf('```%s```', $this->stringify($value)) @@ -253,7 +253,7 @@ private function generateAttachmentField($title, $value) * * @return array */ - private function generateAttachmentFields(array $data) + private function generateAttachmentFields(array $data): array { $fields = array(); foreach ($this->normalizerFormatter->format($data) as $key => $value) { @@ -270,7 +270,7 @@ private function generateAttachmentFields(array $data) * * @return array */ - private function excludeFields(array $record) + private function excludeFields(array $record): array { foreach ($this->excludeFields as $field) { $keys = explode('.', $field); From 10bef97dea14cee40beb9864740d9c3cb4c6e1e3 Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 17 Jul 2018 17:25:17 +0100 Subject: [PATCH 026/498] Add scalar hints and return types to the ActivationStrategyInterface interface and its implementations. --- .../Handler/FingersCrossed/ActivationStrategyInterface.php | 2 +- .../Handler/FingersCrossed/ChannelLevelActivationStrategy.php | 2 +- .../Handler/FingersCrossed/ErrorLevelActivationStrategy.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index b73854ad7..3b7659695 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -24,5 +24,5 @@ interface ActivationStrategyInterface * @param array $record * @return bool */ - public function isHandlerActivated(array $record); + public function isHandlerActivated(array $record): bool; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 63a14cb6e..8d0e4a2eb 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -48,7 +48,7 @@ public function __construct($defaultActionLevel, $channelToActionLevel = []) $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { return $record['level'] >= $this->channelToActionLevel[$record['channel']]; diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index d0ebd8405..5a2a79912 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -27,7 +27,7 @@ public function __construct($actionLevel) $this->actionLevel = Logger::toMonologLevel($actionLevel); } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { return $record['level'] >= $this->actionLevel; } From dc003d137ebed0e70124e23861e76f2fe9481d0a Mon Sep 17 00:00:00 2001 From: Kat Date: Tue, 17 Jul 2018 17:32:33 +0100 Subject: [PATCH 027/498] Add docblocks and return type to the FingersCrossed strategy classes. --- .../FingersCrossed/ChannelLevelActivationStrategy.php | 9 ++++++++- .../FingersCrossed/ErrorLevelActivationStrategy.php | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 8d0e4a2eb..56681c11f 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -35,14 +35,21 @@ */ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { + /** + * @var string|int + */ private $defaultActionLevel; + + /** + * @var array + */ private $channelToActionLevel; /** * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any * @param array $channelToActionLevel An array that maps channel names to action levels. */ - public function __construct($defaultActionLevel, $channelToActionLevel = []) + public function __construct($defaultActionLevel, array $channelToActionLevel = []) { $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel); $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 5a2a79912..7c0eb6ae7 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -20,13 +20,23 @@ */ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { + /** + * @var string|int + */ private $actionLevel; + /** + * @param string|int $actionLevel + */ public function __construct($actionLevel) { $this->actionLevel = Logger::toMonologLevel($actionLevel); } + /** + * @param array $record + * @return bool + */ public function isHandlerActivated(array $record): bool { return $record['level'] >= $this->actionLevel; From 334b8d8783a1262c3b8311d6599889d82e9cc58c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 18 Jul 2018 09:55:49 +0200 Subject: [PATCH 028/498] More type hints on some handler classes --- CHANGELOG.md | 2 +- src/Monolog/Formatter/HtmlFormatter.php | 6 +-- src/Monolog/Handler/AbstractSyslogHandler.php | 6 +-- src/Monolog/Handler/AmqpHandler.php | 17 ++----- .../ActivationStrategyInterface.php | 5 +- .../ChannelLevelActivationStrategy.php | 6 +-- .../ErrorLevelActivationStrategy.php | 5 +- .../Handler/FormattableHandlerTrait.php | 2 + src/Monolog/Handler/InsightOpsHandler.php | 2 +- .../Handler/ProcessableHandlerTrait.php | 5 +- src/Monolog/Handler/Slack/SlackRecord.php | 47 +++++-------------- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 9 ++-- src/Monolog/Logger.php | 2 +- 13 files changed, 43 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c033f931..1d6770e96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * Added ability to customize error handling at the Logger level using Logger::setExceptionHandler * Added InsightOpsHandler to migrate users of the LogEntriesHandler - * Added protection to NormalizerHandler against circular and very deep structures, it now stops normalizing at a depth of 9 + * Added protection to NormalizerFormatter against circular and very deep structures, it now stops normalizing at a depth of 9 * Added capture of stack traces to ErrorHandler when logging PHP errors * Added forwarding of context info to FluentdFormatter * Added SocketHandler::setChunkSize to override the default chunk size in case you must send large log lines to rsyslog for example diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index e116177de..0f8db9a7b 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -47,9 +47,9 @@ public function __construct(?string $dateFormat = null) /** * Creates an HTML table row * - * @param string $th Row header content - * @param string $td Row standard cell content - * @param bool $escapeTd false if td content must not be html escaped + * @param string $th Row header content + * @param string $td Row standard cell content + * @param bool $escapeTd false if td content must not be html escaped */ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): string { diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 3428000e2..9a9b52383 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -54,9 +54,9 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler ]; /** - * @param mixed $facility - * @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 + * @param mixed $facility + * @param string|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($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 064e50a99..ba45dd51c 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -33,10 +33,10 @@ class AmqpHandler extends AbstractProcessingHandler /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use * @param string $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only - * @param int $level + * @param string|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($exchange, $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) + public function __construct($exchange, ?string $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) { if ($exchange instanceof AMQPChannel) { $this->exchangeName = $exchangeName; @@ -108,25 +108,18 @@ public function handleBatch(array $records): void /** * Gets the routing key for the AMQP exchange - * - * @param array $record - * @return string */ - protected function getRoutingKey(array $record) + protected function getRoutingKey(array $record): string { $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']); return strtolower($routingKey); } - /** - * @param string $data - * @return AMQPMessage - */ - private function createAmqpMessage($data) + private function createAmqpMessage(string $data): AMQPMessage { return new AMQPMessage( - (string) $data, + $data, [ 'delivery_mode' => 2, 'content_type' => 'application/json', diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index b73854ad7..1ba99c73d 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -20,9 +20,6 @@ interface ActivationStrategyInterface { /** * Returns whether the given record activates the handler. - * - * @param array $record - * @return bool */ - public function isHandlerActivated(array $record); + public function isHandlerActivated(array $record): bool; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 63a14cb6e..f92a55635 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -39,8 +39,8 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private $channelToActionLevel; /** - * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $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 $channelToActionLevel An array that maps channel names to action levels. */ public function __construct($defaultActionLevel, $channelToActionLevel = []) { @@ -48,7 +48,7 @@ public function __construct($defaultActionLevel, $channelToActionLevel = []) $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { return $record['level'] >= $this->channelToActionLevel[$record['channel']]; diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index d0ebd8405..447aa0533 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -22,12 +22,15 @@ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { private $actionLevel; + /** + * @param int|string $actionLevel Level or name or value + */ public function __construct($actionLevel) { $this->actionLevel = Logger::toMonologLevel($actionLevel); } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { return $record['level'] >= $this->actionLevel; } diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 9acace45f..b1f1b588a 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -52,6 +52,8 @@ public function getFormatter(): FormatterInterface /** * Gets the default formatter. * + * Overwrite this if the LineFormatter is not a good default for your handler. + * * @return FormatterInterface */ protected function getDefaultFormatter(): FormatterInterface diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index dfe1a9dcd..e211cc753 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -13,7 +13,7 @@ use Monolog\Logger; - /** +/** * Inspired on LogEntriesHandler. * * @author Robert Kaufmann III diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index a78b64159..58821100f 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -48,11 +48,8 @@ public function popProcessor(): callable /** * Processes a record. - * - * @param array $record - * @return array */ - protected function processRecord(array $record) + protected function processRecord(array $record): array { foreach ($this->processors as $processor) { $record = $processor($record); diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 90286e888..0fbd4ab70 100755 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -35,19 +35,19 @@ class SlackRecord /** * Slack channel (encoded ID or name) - * @var string|null + * @var ?string */ private $channel; /** * Name of a bot - * @var string|null + * @var ?string */ private $username; /** * User icon e.g. 'ghost', 'http://example.com/user.png' - * @var string + * @var ?string */ private $userIcon; @@ -85,7 +85,7 @@ class SlackRecord */ private $normalizerFormatter; - public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) + public function __construct(?string $channel = null, ?string $username = null, bool $useAttachment = true, ?string $userIcon = null, bool $useShortAttachment = false, bool $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) { $this->channel = $channel; $this->username = $username; @@ -101,7 +101,7 @@ public function __construct($channel = null, $username = null, $useAttachment = } } - public function getSlackData(array $record) + public function getSlackData(array $record): array { $dataArray = array(); $record = $this->excludeFields($record); @@ -177,11 +177,8 @@ public function getSlackData(array $record) /** * Returned a Slack message attachment color associated with * provided level. - * - * @param int $level - * @return string */ - public function getAttachmentColor($level) + public function getAttachmentColor(int $level): string { switch (true) { case $level >= Logger::ERROR: @@ -197,12 +194,8 @@ public function getAttachmentColor($level) /** * Stringifies an array of key/value pairs to be used in attachment fields - * - * @param array $fields - * - * @return string */ - public function stringify($fields) + public function stringify(array $fields): string { $normalized = $this->normalizerFormatter->format($fields); $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; @@ -215,25 +208,19 @@ public function stringify($fields) : json_encode($normalized, JSON_UNESCAPED_UNICODE); } - /** - * Sets the formatter - * - * @param FormatterInterface $formatter - */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): self { $this->formatter = $formatter; + + return $this; } /** * Generates attachment field * - * @param string $title * @param string|array $value - * - * @return array */ - private function generateAttachmentField($title, $value) + private function generateAttachmentField(string $title, $value): array { $value = is_array($value) ? sprintf('```%s```', $this->stringify($value)) @@ -248,12 +235,8 @@ private function generateAttachmentField($title, $value) /** * Generates a collection of attachment fields from array - * - * @param array $data - * - * @return array */ - private function generateAttachmentFields(array $data) + private function generateAttachmentFields(array $data): array { $fields = array(); foreach ($this->normalizerFormatter->format($data) as $key => $value) { @@ -265,12 +248,8 @@ private function generateAttachmentFields(array $data) /** * Get a copy of record with fields excluded according to $this->excludeFields - * - * @param array $record - * - * @return array */ - private function excludeFields(array $record) + private function excludeFields(array $record): array { foreach ($this->excludeFields as $field) { $keys = explode('.', $field); diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 91888ac56..17e2aef0a 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -15,13 +15,14 @@ class UdpSocket { const DATAGRAM_MAX_LENGTH = 65023; + /** @var string */ protected $ip; + /** @var int */ protected $port; - /** @var resource|null */ protected $socket; - public function __construct($ip, $port = 514) + public function __construct(string $ip, int $port = 514) { $this->ip = $ip; $this->port = $port; @@ -41,7 +42,7 @@ public function close(): void } } - protected function send($chunk) + protected function send(string $chunk): void { if (!is_resource($this->socket)) { throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); @@ -49,7 +50,7 @@ protected function send($chunk) socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); } - protected function assembleMessage($line, $header) + protected function assembleMessage(string $line, string $header): string { $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header); diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 876fd0515..c44959f67 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -360,7 +360,7 @@ public static function getLevelName(int $level): string /** * Converts PSR-3 levels to Monolog ones if necessary * - * @param string|int $level Level number (monolog) or name (PSR-3) + * @param string|int $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined */ public static function toMonologLevel($level): int From bff2c8488e69dc7f2a6fa8f50ec02a5f2c07009e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 9 Aug 2018 08:21:24 +0200 Subject: [PATCH 029/498] Update Raven client package URL --- src/Monolog/Handler/RavenHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 34ff0091d..e52bd413e 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -18,7 +18,7 @@ /** * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server - * using raven-php (https://github.com/getsentry/raven-php) + * using sentry-php (https://github.com/getsentry/sentry-php) * * @author Marc Abramowitz */ From be5c43916743540bce0ef638d4d72a772d974f47 Mon Sep 17 00:00:00 2001 From: Avtandil Kikabidze Date: Wed, 12 Sep 2018 18:20:33 +0400 Subject: [PATCH 030/498] Add more type hints --- src/Monolog/Formatter/ElasticaFormatter.php | 2 ++ src/Monolog/Formatter/ElasticsearchFormatter.php | 4 ++-- src/Monolog/Handler/ElasticaHandler.php | 4 ++-- src/Monolog/Handler/ElasticsearchHandler.php | 8 ++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index a6354f508..128e07ab8 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -65,6 +65,8 @@ public function getType(): string /** * Convert a log message into an Elastica Document + * @param array $record + * @return Document */ protected function getDocument(array $record): Document { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 682bdbe11..1667f2cc7 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -34,7 +34,7 @@ class ElasticsearchFormatter extends NormalizerFormatter * @param string $index Elasticsearch index name * @param string $type Elasticsearch record type */ - public function __construct($index, $type) + public function __construct(string $index, string $type) { // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. parent::__construct(DateTime::ISO8601); @@ -79,7 +79,7 @@ public function getType(): string * @param array $record Log message * @return array */ - protected function getDocument($record): array + protected function getDocument(array $record): array { $record['_index'] = $this->index; $record['_type'] = $this->type; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 876e15d30..4fedefc0e 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -88,7 +88,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface * Getter options * @return array */ - public function getOptions() + public function getOptions(): array { return $this->options; } @@ -115,7 +115,7 @@ public function handleBatch(array $records): void * @param array $documents * @throws \RuntimeException */ - protected function bulkSend(array $documents) + protected function bulkSend(array $documents): void { try { $this->client->addDocuments($documents); diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index f733e4e51..690d7feef 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -59,7 +59,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler * @param int $level The minimum logging level at which this handler will be triggered * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, $bubble = true) + public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; @@ -76,7 +76,7 @@ public function __construct(Client $client, array $options = [], $level = Logger /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->bulkSend([$record['formatted']]); } @@ -113,7 +113,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritdoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { $documents = $this->getFormatter()->formatBatch($records); $this->bulkSend($documents); @@ -125,7 +125,7 @@ public function handleBatch(array $records) * @param array $records * @throws \RuntimeException */ - protected function bulkSend(array $records) + protected function bulkSend(array $records): void { try { $params = [ From e9dcd8490f5b9d093ed3901e9bef8b51463b9c3a Mon Sep 17 00:00:00 2001 From: Mike Schinkel Date: Sun, 23 Sep 2018 23:03:04 -0400 Subject: [PATCH 031/498] Updated @see URL for GELF formatter. --- src/Monolog/Formatter/GelfMessageFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 21176a643..54a2fd0d7 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -16,7 +16,7 @@ /** * Serializes a log message to GELF - * @see http://www.graylog2.org/about/gelf + * @see http://docs.graylog.org/en/latest/pages/gelf.html * * @author Matt Lehner */ From 9117a6c747524c78bf0fff7eb5fb5e33a6a4f021 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 17 Aug 2018 09:54:55 +0200 Subject: [PATCH 032/498] Fix displaying anonymous classes --- src/Monolog/ErrorHandler.php | 3 ++- src/Monolog/Formatter/JsonFormatter.php | 5 +++-- src/Monolog/Formatter/LineFormatter.php | 8 +++++--- src/Monolog/Formatter/MongoDBFormatter.php | 6 ++++-- src/Monolog/Formatter/NormalizerFormatter.php | 9 +++++---- src/Monolog/Processor/PsrLogMessageProcessor.php | 4 +++- src/Monolog/Registry.php | 10 ++++++++++ 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index b30257387..7c7d48c23 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Monolog\Handler\AbstractHandler; +use Monolog\Registry; /** * Monolog error handler @@ -133,7 +134,7 @@ public function handleException($e) { $this->logger->log( $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel, - sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()), + sprintf('Uncaught Exception %s: "%s" at %s line %s', Registry::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()), array('exception' => $e) ); diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index b8309b10f..fcb08474e 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Exception; +use Monolog\Registry; use Throwable; /** @@ -179,11 +180,11 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof Exception && !$e instanceof Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); } $data = array( - 'class' => get_class($e), + 'class' => Registry::getClass($e), 'message' => $e->getMessage(), 'code' => $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index d3e209e6c..939cd0438 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\Registry; + /** * Formats incoming records into a one-line string * @@ -129,17 +131,17 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof \Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); } $previousText = ''; if ($previous = $e->getPrevious()) { do { - $previousText .= ', '.get_class($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); + $previousText .= ', '.Registry::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); } while ($previous = $previous->getPrevious()); } - $str = '[object] ('.get_class($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; + $str = '[object] ('.Registry::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; if ($this->includeStacktraces) { $str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n"; } diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index eb067bb72..46944c533 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\Registry; + /** * Formats a record for use with the MongoDBHandler. * @@ -75,7 +77,7 @@ protected function formatArray(array $record, $nestingLevel = 0) protected function formatObject($value, $nestingLevel) { $objectVars = get_object_vars($value); - $objectVars['class'] = get_class($value); + $objectVars['class'] = Registry::getClass($value); return $this->formatArray($objectVars, $nestingLevel); } @@ -83,7 +85,7 @@ protected function formatObject($value, $nestingLevel) protected function formatException(\Exception $exception, $nestingLevel) { $formattedException = array( - 'class' => get_class($exception), + 'class' => Registry::getClass($exception), 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 0d96ed09d..50b4f50e2 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Exception; +use Monolog\Registry; /** * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets @@ -108,7 +109,7 @@ protected function normalize($data, $depth = 0) $value = $this->toJson($data, true); } - return sprintf("[object] (%s: %s)", get_class($data), $value); + return sprintf("[object] (%s: %s)", Registry::getClass($data), $value); } if (is_resource($data)) { @@ -122,11 +123,11 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); } $data = array( - 'class' => get_class($e), + 'class' => Registry::getClass($e), 'message' => $e->getMessage(), 'code' => $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), @@ -159,7 +160,7 @@ protected function normalizeException($e) // as a class name to avoid any unexpected leak of sensitive information $frame['args'] = array_map(function ($arg) { if (is_object($arg) && !($arg instanceof \DateTime || $arg instanceof \DateTimeInterface)) { - return sprintf("[object] (%s)", get_class($arg)); + return sprintf("[object] (%s)", Registry::getClass($arg)); } return $arg; diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index c2686ce5b..f7df00740 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\Registry; + /** * Processes a record's message according to PSR-3 rules * @@ -35,7 +37,7 @@ public function __invoke(array $record) if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { $replacements['{'.$key.'}'] = $val; } elseif (is_object($val)) { - $replacements['{'.$key.'}'] = '[object '.get_class($val).']'; + $replacements['{'.$key.'}'] = '[object '.Registry::getClass($val).']'; } else { $replacements['{'.$key.'}'] = '['.gettype($val).']'; } diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index 159b751cd..b165ccd44 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -131,4 +131,14 @@ public static function __callStatic($name, $arguments) { return self::getInstance($name); } + + /** + * @internal + */ + public function getClass($object) + { + $class = \get_class($object); + + return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; + } } From 44def471c0f9790db46432094a6cda81dfaa42df Mon Sep 17 00:00:00 2001 From: Dominik Liebler Date: Wed, 3 Oct 2018 13:57:08 +0200 Subject: [PATCH 033/498] removed Silex, as it is now longer actively developed --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 82bd4e7ef..32b124889 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) can be used very easily with Monolog since it implements the interface. - [Symfony2](http://symfony.com) comes out of the box with Monolog. -- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog. - [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog. - [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog. - [PPI](http://www.ppi.io/) comes out of the box with Monolog. From db8130ce83e4754708d6a4f5af06dd226aa01f4d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 12 Oct 2018 11:59:23 -0700 Subject: [PATCH 034/498] Add ProcessorInterface, an optional one to allow labelling Monolog processors --- src/Monolog/Processor/GitProcessor.php | 2 +- .../Processor/IntrospectionProcessor.php | 2 +- src/Monolog/Processor/MemoryProcessor.php | 2 +- src/Monolog/Processor/MercurialProcessor.php | 2 +- src/Monolog/Processor/ProcessIdProcessor.php | 2 +- src/Monolog/Processor/ProcessorInterface.php | 25 +++++++++++++++++++ .../Processor/PsrLogMessageProcessor.php | 2 +- src/Monolog/Processor/TagProcessor.php | 2 +- src/Monolog/Processor/UidProcessor.php | 2 +- src/Monolog/Processor/WebProcessor.php | 2 +- 10 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 src/Monolog/Processor/ProcessorInterface.php diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 1899400dc..9fc3f50f0 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -19,7 +19,7 @@ * @author Nick Otter * @author Jordi Boggiano */ -class GitProcessor +class GitProcessor implements ProcessorInterface { private $level; private static $cache; diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 2c07caede..6ae192a23 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -24,7 +24,7 @@ * * @author Jordi Boggiano */ -class IntrospectionProcessor +class IntrospectionProcessor implements ProcessorInterface { private $level; diff --git a/src/Monolog/Processor/MemoryProcessor.php b/src/Monolog/Processor/MemoryProcessor.php index 73f132d70..2a379a302 100644 --- a/src/Monolog/Processor/MemoryProcessor.php +++ b/src/Monolog/Processor/MemoryProcessor.php @@ -16,7 +16,7 @@ * * @author Rob Jensen */ -abstract class MemoryProcessor +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. diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 7c07a7e99..2f5b32659 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -18,7 +18,7 @@ * * @author Jonathan A. Schweder */ -class MercurialProcessor +class MercurialProcessor implements ProcessorInterface { private $level; private static $cache; diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 9d3f5590f..66b80fbbd 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -16,7 +16,7 @@ * * @author Andreas Hörnicke */ -class ProcessIdProcessor +class ProcessIdProcessor implements ProcessorInterface { /** * @param array $record diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php new file mode 100644 index 000000000..7e64d4dfa --- /dev/null +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * An optional interface to allow labelling Monolog processors. + * + * @author Nicolas Grekas + */ +interface ProcessorInterface +{ + /** + * @return array The processed records + */ + public function __invoke(array $records); +} diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index c2686ce5b..00a1c03b1 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -18,7 +18,7 @@ * * @author Jordi Boggiano */ -class PsrLogMessageProcessor +class PsrLogMessageProcessor implements ProcessorInterface { /** * @param array $record diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index 7e2df2acb..615a4d991 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -16,7 +16,7 @@ * * @author Martijn Riemers */ -class TagProcessor +class TagProcessor implements ProcessorInterface { private $tags; diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 812707cdb..c8d818b1b 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -16,7 +16,7 @@ * * @author Simon Mönch */ -class UidProcessor +class UidProcessor implements ProcessorInterface { private $uid; diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index ea1d89782..684188f66 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -16,7 +16,7 @@ * * @author Jordi Boggiano */ -class WebProcessor +class WebProcessor implements ProcessorInterface { /** * @var array|\ArrayAccess From 67365f03006994c385932c91a5481c240af8bc2f Mon Sep 17 00:00:00 2001 From: Dimitri Gritsajuk Date: Sun, 28 Oct 2018 14:14:18 +0100 Subject: [PATCH 035/498] Fix test --- tests/Monolog/Handler/SyslogUdpHandlerTest.php | 4 ++-- tests/Monolog/Handler/UdpSocketTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 9f32d9103..c35b33183 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -44,7 +44,7 @@ public function testWeSplitIntoLines() $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->setMethods(['write']) - ->setConstructorArgs(['lol', 'lol']) + ->setConstructorArgs(['lol']) ->getMock(); $socket->expects($this->at(0)) ->method('write') @@ -65,7 +65,7 @@ public function testSplitWorksOnEmptyMsg() $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->setMethods(['write']) - ->setConstructorArgs(['lol', 'lol']) + ->setConstructorArgs(['lol']) ->getMock(); $socket->expects($this->never()) ->method('write'); diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index 1adf79a0e..bc01a25b7 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -23,7 +23,7 @@ public function testWeDoNotTruncateShortMessages() { $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->setMethods(['send']) - ->setConstructorArgs(['lol', 'lol']) + ->setConstructorArgs(['lol']) ->getMock(); $socket->expects($this->at(0)) @@ -37,7 +37,7 @@ public function testLongMessagesAreTruncated() { $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->setMethods(['send']) - ->setConstructorArgs(['lol', 'lol']) + ->setConstructorArgs(['lol']) ->getMock(); $truncatedString = str_repeat("derp", 16254).'d'; From dfb4805e841c0f7da7289962659bae8983c09574 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Tue, 30 Oct 2018 00:11:40 +0200 Subject: [PATCH 036/498] add php 7.3 to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 045161507..0bc3dc928 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ dist: trusty php: - 7.1 - 7.2 + - 7.3 - nightly cache: From 869ca5963ffcef102aa20d387170fb9cdecc8a21 Mon Sep 17 00:00:00 2001 From: Dimitri Gritsajuk Date: Sun, 28 Oct 2018 15:43:09 +0100 Subject: [PATCH 037/498] [RavenHandler] Add environment and breadcrumbs support --- composer.json | 2 +- src/Monolog/Handler/RavenHandler.php | 45 ++++++++++++++++----- tests/Monolog/Handler/MockRavenClient.php | 2 +- tests/Monolog/Handler/RavenHandlerTest.php | 46 +++++++++++++++++++--- 4 files changed, 79 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index bd253ee6b..0d1f4dbc1 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require-dev": { "phpunit/phpunit": "^6.5", "graylog2/gelf-php": "^1.4.2", - "sentry/sentry": "^0.13", + "sentry/sentry": "^1.9", "ruflin/elastica": ">=0.90 <3.0", "doctrine/couchdb": "~1.0@dev", "aws/aws-sdk-php": "^2.4.9 || ^3.0", diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 801e52c1d..f6cf88a06 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -38,6 +38,11 @@ class RavenHandler extends AbstractProcessingHandler Logger::EMERGENCY => Raven_Client::FATAL, ]; + /** + * @var string the current application environment (staging|preprod|prod) + */ + private $environment; + /** * @var string should represent the current version of the calling * software. Can be any string (git commit, version number) @@ -109,17 +114,15 @@ public function handleBatch(array $records): void * * @param FormatterInterface $formatter */ - public function setBatchFormatter(FormatterInterface $formatter) + public function setBatchFormatter(FormatterInterface $formatter): void { $this->batchFormatter = $formatter; } /** * Gets the formatter for the logs generated by handleBatch(). - * - * @return FormatterInterface */ - public function getBatchFormatter() + public function getBatchFormatter(): FormatterInterface { if (!$this->batchFormatter) { $this->batchFormatter = $this->getDefaultBatchFormatter(); @@ -177,6 +180,10 @@ protected function write(array $record): void $options['extra']['extra'] = $record['extra']; } + if (!empty($this->environment) && !isset($options['environment'])) { + $options['environment'] = $this->environment; + } + if (!empty($this->release) && !isset($options['release'])) { $options['release'] = $this->release; } @@ -190,7 +197,7 @@ protected function write(array $record): void // restore the user context if it was modified if (!is_bool($previousUserContext)) { - $this->ravenClient->user_context($previousUserContext); + $this->ravenClient->user_context($previousUserContext, false); } } @@ -207,7 +214,7 @@ protected function getDefaultFormatter(): FormatterInterface * * @return FormatterInterface */ - protected function getDefaultBatchFormatter() + protected function getDefaultBatchFormatter(): FormatterInterface { return new LineFormatter(); } @@ -217,19 +224,39 @@ protected function getDefaultBatchFormatter() * * @return array */ - protected function getExtraParameters() + protected function getExtraParameters(): array { - return ['checksum', 'release', 'event_id']; + return ['checksum', 'release', 'environment', 'event_id']; } /** * @param string $value * @return self */ - public function setRelease($value) + public function setRelease($value): self { $this->release = $value; return $this; } + + public function setEnvironment($value): self + { + $this->environment = $value; + + return $this; + } + + /** + * @link https://docs.sentry.io/learn/breadcrumbs/ + */ + public function addBreadcrumb(array $crumb): void + { + $this->ravenClient->breadcrumbs->record($crumb); + } + + public function resetBreadcrumbs(): void + { + $this->ravenClient->breadcrumbs->reset(); + } } diff --git a/tests/Monolog/Handler/MockRavenClient.php b/tests/Monolog/Handler/MockRavenClient.php index d344d3427..07434e499 100644 --- a/tests/Monolog/Handler/MockRavenClient.php +++ b/tests/Monolog/Handler/MockRavenClient.php @@ -15,7 +15,7 @@ class MockRavenClient extends Raven_Client { - public function capture($data, $stack, $vars = null) + public function capture($data, $stack = null, $vars = null) { $data = array_merge($this->get_user_data(), $data); $this->lastData = $data; diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php index 082042f0d..c80a57634 100644 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ b/tests/Monolog/Handler/RavenHandlerTest.php @@ -42,9 +42,7 @@ public function testConstruct() protected function getHandler($ravenClient) { - $handler = new RavenHandler($ravenClient); - - return $handler; + return new RavenHandler($ravenClient); } protected function getRavenClient() @@ -144,7 +142,7 @@ public function testUserContext() $this->assertSame('test_user_id', $ravenClient->context->user['id']); // handle with null context - $ravenClient->user_context(null); + $ravenClient->user_context(null, false); $handler->handle($recordWithContext); $this->assertEquals($user, $ravenClient->lastData['user']); @@ -165,7 +163,7 @@ public function testException() $handler->handle($record); } - $this->assertEquals($record['message'], $ravenClient->lastData['message']); + $this->assertEquals('[test] ' . $record['message'], $ravenClient->lastData['message']); } public function testHandleBatch() @@ -256,6 +254,44 @@ public function testRelease() $this->assertEquals($localRelease, $ravenClient->lastData['release']); } + public function testEnvironment() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + $handler->setEnvironment('preprod'); + + $handler->handle($this->getRecord(Logger::INFO, 'Hello 👋 from PREPROD env')); + $this->assertEquals('preprod', $ravenClient->lastData['environment']); + + $handler->handle($this->getRecord(Logger::INFO, 'Hello 👋 from STAGING env', ['environment' => 'staging'])); + $this->assertEquals('staging', $ravenClient->lastData['environment']); + } + + public function testBreadcrumbs() + { + $ravenClient = $this->getRavenClient(); + $handler = $this->getHandler($ravenClient); + + $handler->addBreadcrumb($crumb1 = [ + 'level' => 'info', + 'category' => 'test', + 'message' => 'Step 1: user auth', + ]); + + $handler->addBreadcrumb($crumb2 = [ + 'level' => 'info', + 'category' => 'test', + 'message' => 'Step 2: prepare user redirect', + ]); + + $handler->handle($this->getRecord(Logger::ERROR, 'ERROR 💥')); + $this->assertArraySubset([$crumb1, $crumb2], $ravenClient->breadcrumbs->fetch()); + + $handler->resetBreadcrumbs(); + $handler->handle($this->getRecord(Logger::INFO, 'Hello!')); + $this->assertEmpty($ravenClient->breadcrumbs->fetch()); + } + private function methodThatThrowsAnException() { throw new \Exception('This is an exception'); From 228a763397ac4cb0e90349a5afbd6602cb64467a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 3 Nov 2018 18:02:37 +0100 Subject: [PATCH 038/498] After Logger::toMonologLevel string|int is normalized to int --- .../FingersCrossed/ChannelLevelActivationStrategy.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 56681c11f..31e06a27d 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -36,7 +36,7 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { /** - * @var string|int + * @var int */ private $defaultActionLevel; @@ -46,8 +46,8 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private $channelToActionLevel; /** - * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $channelToActionLevel An array that maps channel names to action levels. + * @param string|int $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $channelToActionLevel An array that maps channel names to action levels. */ public function __construct($defaultActionLevel, array $channelToActionLevel = []) { From bcc4ecfe33c5364de8624cc674b9cc72ce49708f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 3 Nov 2018 18:03:58 +0100 Subject: [PATCH 039/498] Removed useless type hints and make sure level is only an int after normalization --- .../Handler/FingersCrossed/ErrorLevelActivationStrategy.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 7c0eb6ae7..54132b208 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -21,7 +21,7 @@ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { /** - * @var string|int + * @var int */ private $actionLevel; @@ -33,10 +33,6 @@ public function __construct($actionLevel) $this->actionLevel = Logger::toMonologLevel($actionLevel); } - /** - * @param array $record - * @return bool - */ public function isHandlerActivated(array $record): bool { return $record['level'] >= $this->actionLevel; From 0bcaf7a34c09f2740acd82144c13b2d762bda215 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 16:40:21 +0100 Subject: [PATCH 040/498] Type hints for browser console handler --- src/Monolog/Handler/BrowserConsoleHandler.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 37a66d621..925ed3714 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -94,10 +94,8 @@ protected function registerShutdownFunction() /** * Wrapper for echo to allow overriding - * - * @param string $str */ - protected static function writeOutput($str) + protected static function writeOutput(string $str) { echo $str; } From a31ec4034300990b54929cc12fc55f4e80513185 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 16:44:28 +0100 Subject: [PATCH 041/498] Type hints for browser console handler --- src/Monolog/Handler/BrowserConsoleHandler.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 925ed3714..de6f5b711 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -57,7 +57,7 @@ protected function write(array $record): void * Convert records to javascript console commands and send it to the browser. * This method is automatically called on PHP shutdown if output is HTML or Javascript. */ - public static function send() + public static function send(): void { $format = static::getResponseFormat(); if ($format === 'unknown') { @@ -77,7 +77,7 @@ public static function send() /** * Forget all logged records */ - public static function reset() + public static function reset(): void { static::$records = []; } @@ -95,7 +95,7 @@ protected function registerShutdownFunction() /** * Wrapper for echo to allow overriding */ - protected static function writeOutput(string $str) + protected static function writeOutput(string $str): void { echo $str; } @@ -109,7 +109,7 @@ protected static function writeOutput(string $str) * * @return string One of 'js', 'html' or 'unknown' */ - protected static function getResponseFormat() + protected static function getResponseFormat(): string { // Check content type foreach (headers_list() as $header) { @@ -129,7 +129,7 @@ protected static function getResponseFormat() return 'html'; } - private static function generateScript() + private static function generateScript(): string { $script = []; foreach (static::$records as $record) { @@ -152,7 +152,7 @@ private static function generateScript() return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } - private static function handleStyles($formatted) + private static function handleStyles(string $formatted): array { $args = [static::quote('font-weight: normal')]; $format = '%c' . $formatted; @@ -171,12 +171,12 @@ private static function handleStyles($formatted) return $args; } - private static function handleCustomStyles($style, $string) + private static function handleCustomStyles(string $style, string $string): string { static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; static $labels = []; - return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) { + return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) { if (trim($m[1]) === 'autolabel') { // Format the string as a label with consistent auto assigned background color if (!isset($labels[$string])) { @@ -191,7 +191,7 @@ private static function handleCustomStyles($style, $string) }, $style); } - private static function dump($title, array $dict) + private static function dump(string $title, array $dict): array { $script = []; $dict = array_filter($dict); @@ -210,20 +210,19 @@ private static function dump($title, array $dict) return $script; } - private static function quote($arg) + private static function quote(string $arg): string { return '"' . addcslashes($arg, "\"\n\\") . '"'; } - private static function call() + private static function call(...$args): string { - $args = func_get_args(); $method = array_shift($args); return static::call_array($method, $args); } - private static function call_array($method, array $args) + private static function call_array(string $method, array $args): string { return 'c.' . $method . '(' . implode(', ', $args) . ');'; } From 916b034b2b2e33ce4981e0e54389e85eb777bed4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 16:52:06 +0100 Subject: [PATCH 042/498] Add support for passing sentry contexts through monolog context or extra, closes #1214 --- src/Monolog/Handler/RavenHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 34ff0091d..92cc551b7 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -216,7 +216,7 @@ protected function getDefaultBatchFormatter() */ protected function getExtraParameters() { - return array('checksum', 'release', 'event_id'); + return array('contexts', 'checksum', 'release', 'event_id'); } /** From e11012dfdebdf0a046cc702a92b25ff8c1dfef25 Mon Sep 17 00:00:00 2001 From: Ramil Valitov Date: Fri, 2 Nov 2018 02:52:50 +0300 Subject: [PATCH 043/498] [fix] change private vars to protected --- src/Monolog/Handler/RavenHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 92cc551b7..250f0030c 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -27,7 +27,7 @@ class RavenHandler extends AbstractProcessingHandler /** * Translates Monolog log levels to Raven log levels. */ - private $logLevels = array( + protected $logLevels = array( Logger::DEBUG => Raven_Client::DEBUG, Logger::INFO => Raven_Client::INFO, Logger::NOTICE => Raven_Client::INFO, @@ -42,7 +42,7 @@ class RavenHandler extends AbstractProcessingHandler * @var string should represent the current version of the calling * software. Can be any string (git commit, version number) */ - private $release; + protected $release; /** * @var Raven_Client the client object that sends the message to the server From dd144f7fa2f0bf8ea887370aa74d994ad45c0164 Mon Sep 17 00:00:00 2001 From: Matt K Date: Sun, 4 Nov 2018 17:16:31 +0100 Subject: [PATCH 044/498] Added ability to pass in host parameter for LogEntriesHandler, closes #1174, fixes #1173 --- src/Monolog/Handler/LogEntriesHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 494c605bc..ea89fb3ed 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -31,13 +31,13 @@ class LogEntriesHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true) + public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true, $host = 'data.logentries.com') { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); } - $endpoint = $useSSL ? 'ssl://data.logentries.com:443' : 'data.logentries.com:80'; + $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80'; parent::__construct($endpoint, $level, $bubble); $this->logToken = $token; } From 42d84e6a8d94e68ba52e15bbdd58dde1023609ad Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 18:23:20 +0100 Subject: [PATCH 045/498] Move getClass method to a Utils class, refs #1190 --- src/Monolog/ErrorHandler.php | 2 +- src/Monolog/Formatter/JsonFormatter.php | 6 ++--- src/Monolog/Formatter/LineFormatter.php | 8 +++--- src/Monolog/Formatter/MongoDBFormatter.php | 6 ++--- src/Monolog/Formatter/NormalizerFormatter.php | 10 ++++---- .../Processor/PsrLogMessageProcessor.php | 4 +-- src/Monolog/Utils.php | 25 +++++++++++++++++++ 7 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 src/Monolog/Utils.php diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 7c7d48c23..adc55bdf6 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -134,7 +134,7 @@ public function handleException($e) { $this->logger->log( $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel, - sprintf('Uncaught Exception %s: "%s" at %s line %s', Registry::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()), + sprintf('Uncaught Exception %s: "%s" at %s line %s', Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()), array('exception' => $e) ); diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index fcb08474e..9bd305f23 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -12,7 +12,7 @@ namespace Monolog\Formatter; use Exception; -use Monolog\Registry; +use Monolog\Utils; use Throwable; /** @@ -180,11 +180,11 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof Exception && !$e instanceof Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); } $data = array( - 'class' => Registry::getClass($e), + 'class' => Utils::getClass($e), 'message' => $e->getMessage(), 'code' => $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 939cd0438..f98e1a6fc 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Registry; +use Monolog\Utils; /** * Formats incoming records into a one-line string @@ -131,17 +131,17 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof \Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); } $previousText = ''; if ($previous = $e->getPrevious()) { do { - $previousText .= ', '.Registry::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); + $previousText .= ', '.Utils::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); } while ($previous = $previous->getPrevious()); } - $str = '[object] ('.Registry::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; + $str = '[object] ('.Utils::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; if ($this->includeStacktraces) { $str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n"; } diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 46944c533..eb7be849f 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Registry; +use Monolog\Utils; /** * Formats a record for use with the MongoDBHandler. @@ -77,7 +77,7 @@ protected function formatArray(array $record, $nestingLevel = 0) protected function formatObject($value, $nestingLevel) { $objectVars = get_object_vars($value); - $objectVars['class'] = Registry::getClass($value); + $objectVars['class'] = Utils::getClass($value); return $this->formatArray($objectVars, $nestingLevel); } @@ -85,7 +85,7 @@ protected function formatObject($value, $nestingLevel) protected function formatException(\Exception $exception, $nestingLevel) { $formattedException = array( - 'class' => Registry::getClass($exception), + 'class' => Utils::getClass($exception), 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 50b4f50e2..668665789 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -12,7 +12,7 @@ namespace Monolog\Formatter; use Exception; -use Monolog\Registry; +use Monolog\Utils; /** * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets @@ -109,7 +109,7 @@ protected function normalize($data, $depth = 0) $value = $this->toJson($data, true); } - return sprintf("[object] (%s: %s)", Registry::getClass($data), $value); + return sprintf("[object] (%s: %s)", Utils::getClass($data), $value); } if (is_resource($data)) { @@ -123,11 +123,11 @@ protected function normalizeException($e) { // TODO 2.0 only check for Throwable if (!$e instanceof Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Registry::getClass($e)); + throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); } $data = array( - 'class' => Registry::getClass($e), + 'class' => Utils::getClass($e), 'message' => $e->getMessage(), 'code' => $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), @@ -160,7 +160,7 @@ protected function normalizeException($e) // as a class name to avoid any unexpected leak of sensitive information $frame['args'] = array_map(function ($arg) { if (is_object($arg) && !($arg instanceof \DateTime || $arg instanceof \DateTimeInterface)) { - return sprintf("[object] (%s)", Registry::getClass($arg)); + return sprintf("[object] (%s)", Utils::getClass($arg)); } return $arg; diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 543c45843..008850545 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -11,7 +11,7 @@ namespace Monolog\Processor; -use Monolog\Registry; +use Monolog\Utils; /** * Processes a record's message according to PSR-3 rules @@ -37,7 +37,7 @@ public function __invoke(array $record) if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { $replacements['{'.$key.'}'] = $val; } elseif (is_object($val)) { - $replacements['{'.$key.'}'] = '[object '.Registry::getClass($val).']'; + $replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']'; } else { $replacements['{'.$key.'}'] = '['.gettype($val).']'; } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php new file mode 100644 index 000000000..df611a0d8 --- /dev/null +++ b/src/Monolog/Utils.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +class Utils +{ + /** + * @internal + */ + public function getClass($object) + { + $class = \get_class($object); + + return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; + } +} From ceebd568a2ffa1003c6a84fb9c53162bb96fd646 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 18:41:02 +0100 Subject: [PATCH 046/498] Remove getClass func from Registry as it was moved to Utils class --- src/Monolog/Registry.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index b165ccd44..159b751cd 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -131,14 +131,4 @@ public static function __callStatic($name, $arguments) { return self::getInstance($name); } - - /** - * @internal - */ - public function getClass($object) - { - $class = \get_class($object); - - return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; - } } From 712c5dacf6b68003efe335378e346afa4364a3ad Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 19:34:52 +0100 Subject: [PATCH 047/498] Make static method static --- src/Monolog/Utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index df611a0d8..eb9be863b 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -16,7 +16,7 @@ class Utils /** * @internal */ - public function getClass($object) + public static function getClass($object) { $class = \get_class($object); From c5bba4ac642382a0e00fef04aab566860c3e8971 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 19:41:54 +0100 Subject: [PATCH 048/498] Fix test case class name --- tests/Monolog/SignalHandlerTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index 9fa079290..c2c145bb2 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -14,6 +14,7 @@ use Monolog\Handler\StreamHandler; use Monolog\Handler\TestHandler; use Psr\Log\LogLevel; +use Monolog\Test\TestCase; /** * @author Robert Gust-Bardon From 36b767dc02a6db90425b6d99061545fdc68f8da0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 19:47:01 +0100 Subject: [PATCH 049/498] Added some type hints --- src/Monolog/Registry.php | 6 +++--- src/Monolog/SignalHandler.php | 2 +- src/Monolog/Utils.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index 99a434401..78fb97e58 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -52,7 +52,7 @@ class Registry * @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 */ - public static function addLogger(Logger $logger, $name = null, $overwrite = false) + public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false) { $name = $name ?: $logger->getName(); @@ -84,7 +84,7 @@ public static function hasLogger($logger): bool * * @param string|Logger $logger Name or logger instance */ - public static function removeLogger($logger) + public static function removeLogger($logger): void { if ($logger instanceof Logger) { if (false !== ($idx = array_search($logger, self::$loggers, true))) { @@ -98,7 +98,7 @@ public static function removeLogger($logger) /** * Clears the registry */ - public static function clear() + public static function clear(): void { self::$loggers = []; } diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index d5907805a..2a4233192 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -33,7 +33,7 @@ public function __construct(LoggerInterface $logger) $this->logger = $logger; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) + public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, bool $async = true): self { if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { return $this; diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index eb9be863b..769cdc002 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -16,7 +16,7 @@ class Utils /** * @internal */ - public static function getClass($object) + public static function getClass($object): string { $class = \get_class($object); From dddc7ed781145a4846076fc2a135bb35c9c3882a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 19:58:13 +0100 Subject: [PATCH 050/498] Fix some resettableinterface usages --- src/Monolog/ErrorHandler.php | 1 - src/Monolog/Handler/AbstractHandler.php | 8 +++++++- src/Monolog/Handler/AbstractProcessingHandler.php | 4 ++-- src/Monolog/Handler/BrowserConsoleHandler.php | 3 +++ src/Monolog/Handler/FingersCrossedHandler.php | 4 +--- src/Monolog/Handler/GroupHandler.php | 13 ++++++++++--- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 317494a8e..7447f2798 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -13,7 +13,6 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Monolog\Registry; /** * Monolog error handler diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 7c507466e..da5bbc05c 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -12,13 +12,14 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\ResettableInterface; /** * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano */ -abstract class AbstractHandler extends Handler +abstract class AbstractHandler extends Handler implements ResettableInterface { protected $level = Logger::DEBUG; protected $bubble = true; @@ -88,4 +89,9 @@ public function getBubble(): bool { return $this->bubble; } + + public function reset() + { + $this->close(); + } } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 5e9e5837f..b9da89852 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -21,7 +21,7 @@ * @author Jordi Boggiano * @author Christophe Coevoet */ -abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface +abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; use FormattableHandlerTrait; @@ -53,7 +53,7 @@ abstract protected function write(array $record): void; public function reset() { - $this->close(); + parent::reset(); foreach ($this->processors as $processor) { if ($processor instanceof ResettableInterface) { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index a39b0582c..dc12b653d 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\ResettableInterface; /** * Handler sending logs to browser's javascript console with no browser extension required @@ -76,6 +77,8 @@ public static function send(): void public function reset() { + parent::reset(); + self::resetStatic(); } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 305396ff2..90727a04e 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -28,7 +28,7 @@ * * @author Jordi Boggiano */ -class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface +class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { use ProcessableHandlerTrait; @@ -148,8 +148,6 @@ public function close(): void */ public function reset() { - parent::reset(); - $this->buffer = array(); $this->buffering = true; diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 170903117..3c4006319 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -19,7 +19,7 @@ * * @author Lenar Lõhmus */ -class GroupHandler extends Handler implements ProcessableHandlerInterface +class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { use ProcessableHandlerTrait; @@ -93,8 +93,6 @@ public function handleBatch(array $records): void public function reset() { - parent::reset(); - foreach ($this->handlers as $handler) { if ($handler instanceof ResettableInterface) { $handler->reset(); @@ -102,6 +100,15 @@ public function reset() } } + public function close() + { + parent::close(); + + foreach ($this->handlers as $handler) { + $handler->close(); + } + } + /** * {@inheritdoc} */ From b80352368cd79c978a805a76b724618ccb4ba465 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 22:15:25 +0100 Subject: [PATCH 051/498] Add Logger::close and clarify what close and reset do plus --- src/Monolog/Handler/AbstractHandler.php | 2 - src/Monolog/Handler/BrowserConsoleHandler.php | 5 +++ src/Monolog/Handler/BufferHandler.php | 2 + src/Monolog/Handler/FingersCrossedHandler.php | 38 +++++++++++-------- src/Monolog/Handler/RollbarHandler.php | 12 ++++++ src/Monolog/Handler/RotatingFileHandler.php | 12 ++++++ src/Monolog/Logger.php | 29 ++++++++++++++ src/Monolog/ResettableInterface.php | 10 ++++- 8 files changed, 90 insertions(+), 20 deletions(-) diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index b286a01c0..92b9d4580 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -177,8 +177,6 @@ public function __destruct() public function reset() { - $this->close(); - foreach ($this->processors as $processor) { if ($processor instanceof ResettableInterface) { $processor->reset(); diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 14fa0dc70..23cf23ba1 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -73,6 +73,11 @@ public static function send() } } + public function close() + { + self::resetStatic(); + } + public function reset() { self::resetStatic(); diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index ca2c7a799..61d1b50c1 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -118,6 +118,8 @@ public function clear() public function reset() { + $this->flush(); + parent::reset(); if ($this->handler instanceof ResettableInterface) { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index a2d85dde6..275fd5136 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -131,27 +131,14 @@ public function handle(array $record) */ public function close() { - if (null !== $this->passthruLevel) { - $level = $this->passthruLevel; - $this->buffer = array_filter($this->buffer, function ($record) use ($level) { - return $record['level'] >= $level; - }); - if (count($this->buffer) > 0) { - $this->handler->handleBatch($this->buffer); - $this->buffer = array(); - } - } + $this->flushBuffer(); } - /** - * Resets the state of the handler. Stops forwarding records to the wrapped handler. - */ public function reset() { - parent::reset(); + $this->flushBuffer(); - $this->buffer = array(); - $this->buffering = true; + parent::reset(); if ($this->handler instanceof ResettableInterface) { $this->handler->reset(); @@ -168,4 +155,23 @@ public function clear() $this->buffer = array(); $this->reset(); } + + /** + * Resets the state of the handler. Stops forwarding records to the wrapped handler. + */ + private function flushBuffer() + { + if (null !== $this->passthruLevel) { + $level = $this->passthruLevel; + $this->buffer = array_filter($this->buffer, function ($record) use ($level) { + return $record['level'] >= $level; + }); + if (count($this->buffer) > 0) { + $this->handler->handleBatch($this->buffer); + } + } + + $this->buffer = array(); + $this->buffering = true; + } } diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 6c8a3e3ed..65073ffe3 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -129,4 +129,16 @@ public function close() { $this->flush(); } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->flush(); + + parent::reset(); + } + + } diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index cc9fd4d35..ae2309f8a 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -66,6 +66,18 @@ public function close() } } + /** + * {@inheritdoc} + */ + public function reset() + { + parent::reset(); + + if (true === $this->mustRotate) { + $this->rotate(); + } + } + public function setFilenameFormat($filenameFormat, $dateFormat) { if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index d998bb655..05dfc8179 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -354,6 +354,35 @@ public function addRecord($level, $message, array $context = array()) return true; } + /** + * Ends a log cycle and frees all resources used by handlers. + * + * Closing a Handler means flushing all buffers and freeing any open resources/handles. + * Handlers that have been closed should be able to accept log records again and re-open + * themselves on demand, but this may not always be possible depending on implementation. + * + * This is useful at the end of a request and will be called automatically on every handler + * when they get destructed. + */ + public function close() + { + foreach ($this->handlers as $handler) { + if (method_exists($handler, 'close')) { + $handler->close(); + } + } + } + + /** + * Ends a log cycle and resets all handlers and processors to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. + */ public function reset() { foreach ($this->handlers as $handler) { diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php index 5e7bd6f3a..635bc77dc 100644 --- a/src/Monolog/ResettableInterface.php +++ b/src/Monolog/ResettableInterface.php @@ -14,8 +14,14 @@ /** * Handler or Processor implementing this interface will be reset when Logger::reset() is called. * - * Resetting an Handler or a Processor usually means cleaning all buffers or - * resetting in its internal state. + * Resetting ends a log cycle gets them back to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. * * @author Grégoire Pineau */ From 64f6dc944a1b8b05f293f027d568eba97f8670f7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 23:31:55 +0100 Subject: [PATCH 052/498] Type fixes --- src/Monolog/Handler/AmqpHandler.php | 4 ++-- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- src/Monolog/Handler/GroupHandler.php | 2 +- src/Monolog/Logger.php | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index ba45dd51c..33fffccd8 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -32,14 +32,14 @@ class AmqpHandler extends AbstractProcessingHandler /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use - * @param string $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only + * @param string|null $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only * @param string|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($exchange, ?string $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) { if ($exchange instanceof AMQPChannel) { - $this->exchangeName = $exchangeName; + $this->exchangeName = (string) $exchangeName; } elseif (!$exchange instanceof AMQPExchange) { throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required'); } elseif ($exchangeName) { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 620e2e677..7ff2b1608 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -74,7 +74,7 @@ public static function send(): void } } - public function close() + public function close(): void { self::resetStatic(); } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 28b9f162d..309d3be99 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -102,7 +102,7 @@ public function reset() } } - public function close() + public function close(): void { parent::close(); diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 1c05293cb..79b7d8361 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -135,7 +135,7 @@ class Logger implements LoggerInterface, ResettableInterface protected $timezone; /** - * @var ?callable + * @var callable|null */ protected $exceptionHandler; @@ -343,7 +343,7 @@ public function addRecord(int $level, string $message, array $context = []): boo * This is useful at the end of a request and will be called automatically on every handler * when they get destructed. */ - public function close() + public function close(): void { foreach ($this->handlers as $handler) { $handler->close(); @@ -360,7 +360,7 @@ public function close() * have a long running process like a worker or an application server serving multiple requests * in one process. */ - public function reset() + public function reset(): void { foreach ($this->handlers as $handler) { if ($handler instanceof ResettableInterface) { From 6b5a392d876a044e7b6eab0587a72fcb6ccf5f9c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 23:49:26 +0100 Subject: [PATCH 053/498] Update changelog --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ac442b4..9903c19f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ -### 1.24.0 (2018-06-xx) +### 1.24.0 (2018-11-xx) + * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors + * Added a `ProcessorInterface` as an optional way to label a class as being a processor (mostly useful for autowiring dependency containers) + * Added a way to log signals being received using Monolog\SignalHandler * Added ability to customize error handling at the Logger level using Logger::setExceptionHandler * Added InsightOpsHandler to migrate users of the LogEntriesHandler * Added protection to NormalizerHandler against circular and very deep structures, it now stops normalizing at a depth of 9 * Added capture of stack traces to ErrorHandler when logging PHP errors + * Added RavenHandler support for a `contexts` context or extra key to forward that to Sentry's contexts * Added forwarding of context info to FluentdFormatter * Added SocketHandler::setChunkSize to override the default chunk size in case you must send large log lines to rsyslog for example * Added ability to extend/override BrowserConsoleHandler @@ -19,8 +23,8 @@ * Fixed table row styling issues in HtmlFormatter * Fixed RavenHandler dropping the message when logging exception * Fixed WhatFailureGroupHandler skipping processors when using handleBatch - * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors and implement it where possible + * Fixed display of anonymous class names ### 1.23.0 (2017-06-19) From 8ef626db19b42aff4be0b568c62636fc84a39b3a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Nov 2018 23:59:01 +0100 Subject: [PATCH 054/498] SignalHandler cleanups --- src/Monolog/SignalHandler.php | 53 +++++++++++++++-------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 2a4233192..28288c100 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -24,49 +24,45 @@ class SignalHandler { private $logger; - private $previousSignalHandler = array(); - private $signalLevelMap = array(); - private $signalRestartSyscalls = array(); + private $previousSignalHandler = []; + private $signalLevelMap = []; + private $signalRestartSyscalls = []; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, bool $async = true): self + public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self { if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { return $this; } if ($callPrevious) { - if (function_exists('pcntl_signal_get_handler')) { - $handler = pcntl_signal_get_handler($signo); - if ($handler === false) { - return $this; - } - $this->previousSignalHandler[$signo] = $handler; - } else { - $this->previousSignalHandler[$signo] = true; + $handler = pcntl_signal_get_handler($signo); + if ($handler === false) { + return $this; } + $this->previousSignalHandler[$signo] = $handler; } else { unset($this->previousSignalHandler[$signo]); } $this->signalLevelMap[$signo] = $level; $this->signalRestartSyscalls[$signo] = $restartSyscalls; - if (function_exists('pcntl_async_signals') && $async !== null) { + if ($async !== null) { pcntl_async_signals($async); } - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); return $this; } public function handleSignal($signo, array $siginfo = null) { - static $signals = array(); + static $signals = []; if (!$signals && extension_loaded('pcntl')) { $pcntl = new ReflectionExtension('pcntl'); @@ -86,7 +82,7 @@ public function handleSignal($signo, array $siginfo = null) $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; - $context = isset($siginfo) ? $siginfo : array(); + $context = isset($siginfo) ? $siginfo : []; $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); if (!isset($this->previousSignalHandler[$signo])) { @@ -95,21 +91,18 @@ public function handleSignal($signo, array $siginfo = null) if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') - && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { - $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; - pcntl_signal($signo, SIG_DFL, $restartSyscalls); - pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); - posix_kill(posix_getpid(), $signo); - pcntl_signal_dispatch(); - pcntl_sigprocmask(SIG_SETMASK, $oldset); - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); - } - } elseif (is_callable($this->previousSignalHandler[$signo])) { - if (PHP_VERSION_ID >= 70100) { - $this->previousSignalHandler[$signo]($signo, $siginfo); - } else { - $this->previousSignalHandler[$signo]($signo); + && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill') + ) { + $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; + pcntl_signal($signo, SIG_DFL, $restartSyscalls); + pcntl_sigprocmask(SIG_UNBLOCK, [$signo], $oldset); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + pcntl_sigprocmask(SIG_SETMASK, $oldset); + pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); } + } elseif (is_callable($this->previousSignalHandler[$signo])) { + $this->previousSignalHandler[$signo]($signo, $siginfo); } } } From bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Nov 2018 10:00:11 +0100 Subject: [PATCH 055/498] Update changelog date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9903c19f2..bcf679c4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.24.0 (2018-11-xx) +### 1.24.0 (2018-11-05) * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors * Added a `ProcessorInterface` as an optional way to label a class as being a processor (mostly useful for autowiring dependency containers) From 25580ef96197bb3aa55664ca1004c5abbe5a0b0c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Nov 2018 13:13:11 +0100 Subject: [PATCH 056/498] Add BC notice to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcf679c4a..0c5f93bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.24.0 (2018-11-05) + * BC Notice: If you are extending any of the Monolog's Formatters' `normalize` method, make sure you add the new `$depth = 0` argument to your function signature to avoid strict PHP warnings. * Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors * Added a `ProcessorInterface` as an optional way to label a class as being a processor (mostly useful for autowiring dependency containers) * Added a way to log signals being received using Monolog\SignalHandler From 1923c84d1ba4be1716fba43c888383eb2078a7bb Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Mon, 5 Nov 2018 21:26:35 +0100 Subject: [PATCH 057/498] Remove version of Symfony --- README.md | 2 +- doc/01-usage.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32b124889..7bab1f5f4 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) can be used very easily with Monolog since it implements the interface. -- [Symfony2](http://symfony.com) comes out of the box with Monolog. +- [Symfony](http://symfony.com) comes out of the box with Monolog. - [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog. - [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog. - [PPI](http://www.ppi.io/) comes out of the box with Monolog. diff --git a/doc/01-usage.md b/doc/01-usage.md index ec9bbbb1b..da7670ccf 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -18,7 +18,7 @@ composer require monolog/monolog ``` If you do not use Composer, you can grab the code from GitHub, and use any -PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader)) +PSR-0 compatible autoloader (e.g. the [Symfony ClassLoader component](https://github.com/symfony/ClassLoader)) to load Monolog classes. ## Core Concepts @@ -163,7 +163,7 @@ Look at the [dedicated chapter](https://github.com/Seldaek/monolog/blob/master/d Channels are a great way to identify to which part of the application a record is related. This is useful in big applications (and is leveraged by -MonologBundle in Symfony2). +MonologBundle in Symfony). Picture two loggers sharing a handler that writes to a single log file. Channels would allow you to identify the logger that issued every record. From cd203a6f11626b186eca4f59b7dc47b43e4d1dd8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 6 Nov 2018 10:31:08 +0100 Subject: [PATCH 058/498] Remove manual install --- doc/01-usage.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index da7670ccf..7767a6116 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -17,10 +17,6 @@ and as such installable via [Composer](http://getcomposer.org/). composer require monolog/monolog ``` -If you do not use Composer, you can grab the code from GitHub, and use any -PSR-0 compatible autoloader (e.g. the [Symfony ClassLoader component](https://github.com/symfony/ClassLoader)) -to load Monolog classes. - ## Core Concepts Every `Logger` instance has a channel (name) and a stack of handlers. Whenever From 14e38f5ccb60ac7c3f3ce9ac32dc463674469966 Mon Sep 17 00:00:00 2001 From: Ankur Kumar Date: Tue, 13 Nov 2018 19:08:44 +0530 Subject: [PATCH 059/498] Exclude files and folder from release archive This file is same as master branch --- .gitattributes | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 4afe79241..ed6e29a8a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ -.gitattributes export-ignore -.gitignore export-ignore -.travis.yml export-ignore +/doc export-ignore +/tests export-ignore +/.* export-ignore +/phpunit.xml.dist export-ignore From 6f6fc5dc5249187849c90c9704a3e58aec28191d Mon Sep 17 00:00:00 2001 From: Gabriel Machado Date: Fri, 16 Nov 2018 09:57:20 -0200 Subject: [PATCH 060/498] fix typo --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index fb7add9d2..55af6967e 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -59,7 +59,7 @@ - [_RollbarHandler_](../src/Monolog/Handler/RollbarHandler.php): Logs records to a [Rollbar](https://rollbar.com/) account. - [_SyslogUdpHandler_](../src/Monolog/Handler/SyslogUdpHandler.php): Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. - [_LogEntriesHandler_](../src/Monolog/Handler/LogEntriesHandler.php): Logs records to a [LogEntries](http://logentries.com/) account. -- [_InsightOpsHandler_](../src/Monolog/Handler/InsightOpsHandler.php): Logs records to a [InsightOps](https://www.rapid7.com/products/insightops/) account. +- [_InsightOpsHandler_](../src/Monolog/Handler/InsightOpsHandler.php): Logs records to an [InsightOps](https://www.rapid7.com/products/insightops/) account. - [_LogmaticHandler_](../src/Monolog/Handler/LogmaticHandler.php): Logs records to a [Logmatic](http://logmatic.io/) account. - [_SqsHandler_](../src/Monolog/Handler/SqsHandler.php): Logs records to an [AWS SQS](http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-sqs.html) queue. From 9ba4f228321b3c556556e47c7c6ede683cbe7115 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sat, 17 Nov 2018 20:30:52 +0200 Subject: [PATCH 061/498] Reset test handler --- src/Monolog/Handler/TestHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index b6b1343bd..65ef12e34 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -79,6 +79,11 @@ public function clear() $this->recordsByLevel = array(); } + public function reset() + { + $this->clear(); + } + public function hasRecords($level) { return isset($this->recordsByLevel[$level]); From c68b71edeb245928e2474f78386e47dfa1f4616f Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sat, 17 Nov 2018 20:38:51 +0200 Subject: [PATCH 062/498] Add visibility to constants --- src/Monolog/Formatter/GelfMessageFormatter.php | 2 +- src/Monolog/Formatter/JsonFormatter.php | 4 ++-- src/Monolog/Formatter/LineFormatter.php | 2 +- src/Monolog/Formatter/LogmaticFormatter.php | 2 +- src/Monolog/Formatter/NormalizerFormatter.php | 2 +- src/Monolog/Formatter/WildfireFormatter.php | 2 +- src/Monolog/Handler/ChromePHPHandler.php | 6 +++--- src/Monolog/Handler/DynamoDbHandler.php | 2 +- src/Monolog/Handler/ErrorLogHandler.php | 4 ++-- src/Monolog/Handler/FirePHPHandler.php | 8 ++++---- src/Monolog/Handler/FleepHookHandler.php | 4 ++-- src/Monolog/Handler/HipChatHandler.php | 4 ++-- src/Monolog/Handler/LogglyHandler.php | 6 +++--- src/Monolog/Handler/ProcessHandler.php | 2 +- src/Monolog/Handler/RotatingFileHandler.php | 6 +++--- src/Monolog/Handler/Slack/SlackRecord.php | 8 ++++---- src/Monolog/Handler/SqsHandler.php | 4 ++-- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 2 +- src/Monolog/Logger.php | 18 +++++++++--------- .../Processor/PsrLogMessageProcessor.php | 2 +- 20 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 54a2fd0d7..28134809f 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -22,7 +22,7 @@ */ class GelfMessageFormatter extends NormalizerFormatter { - const DEFAULT_MAX_LENGTH = 32766; + public const DEFAULT_MAX_LENGTH = 32766; /** * @var string the name of the system for the Gelf log message diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index c61c90b42..3f6022b6c 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -23,8 +23,8 @@ */ class JsonFormatter extends NormalizerFormatter { - const BATCH_MODE_JSON = 1; - const BATCH_MODE_NEWLINES = 2; + public const BATCH_MODE_JSON = 1; + public const BATCH_MODE_NEWLINES = 2; protected $batchMode; protected $appendNewline; diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 07f92f15b..3b4824cd6 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -23,7 +23,7 @@ */ class LineFormatter extends NormalizerFormatter { - const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; protected $format; protected $allowInlineLineBreaks; diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index 8c6ff2f48..402752aa9 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -18,7 +18,7 @@ */ class LogmaticFormatter extends JsonFormatter { - const MARKERS = ["sourcecode", "php"]; + public const MARKERS = ["sourcecode", "php"]; /** * @var string diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 907efa960..7ee28ffa8 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -22,7 +22,7 @@ */ class NormalizerFormatter implements FormatterInterface { - const SIMPLE_DATE = "Y-m-d\TH:i:sP"; + public const SIMPLE_DATE = "Y-m-d\TH:i:sP"; protected $dateFormat; protected $maxNormalizeDepth = 9; diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index a5812b89b..e17fd3fdd 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -22,7 +22,7 @@ */ class WildfireFormatter extends NormalizerFormatter { - const TABLE = 'table'; + public const TABLE = 'table'; /** * Translates Monolog log levels to Wildfire levels. diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 46ef7d341..648c1a35b 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -29,17 +29,17 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Version of the extension */ - const VERSION = '4.0'; + public const VERSION = '4.0'; /** * Header name */ - const HEADER_NAME = 'X-ChromeLogger-Data'; + public const HEADER_NAME = 'X-ChromeLogger-Data'; /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ - const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; + public const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; protected static $initialized = false; diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index cd2bc64af..297b0fd86 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -26,7 +26,7 @@ */ class DynamoDbHandler extends AbstractProcessingHandler { - const DATE_FORMAT = 'Y-m-d\TH:i:s.uO'; + public const DATE_FORMAT = 'Y-m-d\TH:i:s.uO'; /** * @var DynamoDbClient diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 60f12d11b..920c80e14 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -22,8 +22,8 @@ */ class ErrorLogHandler extends AbstractProcessingHandler { - const OPERATING_SYSTEM = 0; - const SAPI = 4; + public const OPERATING_SYSTEM = 0; + public const SAPI = 4; protected $messageType; protected $expandNewlines; diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 29b4714d9..95f7e2c54 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -26,22 +26,22 @@ class FirePHPHandler extends AbstractProcessingHandler /** * WildFire JSON header message format */ - const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; + public const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; /** * FirePHP structure for parsing messages & their presentation */ - const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; + public const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; /** * Must reference a "known" plugin, otherwise headers won't display in FirePHP */ - const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; + public const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; /** * Header prefix for Wildfire to recognize & parse headers */ - const HEADER_PREFIX = 'X-Wf'; + public const HEADER_PREFIX = 'X-Wf'; /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 2740b8836..162063c82 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -25,9 +25,9 @@ */ class FleepHookHandler extends SocketHandler { - const FLEEP_HOST = 'fleep.io'; + public const FLEEP_HOST = 'fleep.io'; - const FLEEP_HOOK_URI = '/hook/'; + public const FLEEP_HOOK_URI = '/hook/'; /** * @var string Webhook token (specifies the conversation where logs are sent) diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index ce09299db..7e98c8ce9 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -32,12 +32,12 @@ class HipChatHandler extends SocketHandler /** * The maximum allowed length for the name used in the "from" field. */ - const MAXIMUM_NAME_LENGTH = 15; + public const MAXIMUM_NAME_LENGTH = 15; /** * The maximum allowed length for the message. */ - const MAXIMUM_MESSAGE_LENGTH = 9500; + public const MAXIMUM_MESSAGE_LENGTH = 9500; /** * @var string diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 647c7e136..567da41aa 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -24,9 +24,9 @@ */ class LogglyHandler extends AbstractProcessingHandler { - const HOST = 'logs-01.loggly.com'; - const ENDPOINT_SINGLE = 'inputs'; - const ENDPOINT_BATCH = 'bulk'; + public const HOST = 'logs-01.loggly.com'; + public const ENDPOINT_SINGLE = 'inputs'; + public const ENDPOINT_BATCH = 'bulk'; protected $token; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 4478fe1d3..6ced1f221 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -51,7 +51,7 @@ class ProcessHandler extends AbstractProcessingHandler /** * @var array */ - const DESCRIPTOR_SPEC = [ + public const DESCRIPTOR_SPEC = [ 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from 1 => ['pipe', 'w'], // STDOUT is a pipe that the child will write to 2 => ['pipe', 'w'], // STDERR is a pipe to catch the any errors diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 58f6ac11a..ed19bacb2 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -25,9 +25,9 @@ */ class RotatingFileHandler extends StreamHandler { - const FILE_PER_DAY = 'Y-m-d'; - const FILE_PER_MONTH = 'Y-m'; - const FILE_PER_YEAR = 'Y'; + public const FILE_PER_DAY = 'Y-m-d'; + public const FILE_PER_MONTH = 'Y-m'; + public const FILE_PER_YEAR = 'Y'; protected $filename; protected $maxFiles; diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 36f43734b..a4e986781 100755 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -25,13 +25,13 @@ */ class SlackRecord { - const COLOR_DANGER = 'danger'; + public const COLOR_DANGER = 'danger'; - const COLOR_WARNING = 'warning'; + public const COLOR_WARNING = 'warning'; - const COLOR_GOOD = 'good'; + public const COLOR_GOOD = 'good'; - const COLOR_DEFAULT = '#e3e4e6'; + public const COLOR_DEFAULT = '#e3e4e6'; /** * Slack channel (encoded ID or name) diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index f282d023b..52a1c8a28 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -22,9 +22,9 @@ class SqsHandler extends AbstractProcessingHandler { /** 256 KB in bytes - maximum message size in SQS */ - const MAX_MESSAGE_SIZE = 262144; + public const MAX_MESSAGE_SIZE = 262144; /** 100 KB in bytes - head message size for new error log */ - const HEAD_MESSAGE_SIZE = 102400; + public const HEAD_MESSAGE_SIZE = 102400; /** @var SqsClient */ private $client; diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 17e2aef0a..d3e8f627b 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -13,7 +13,7 @@ class UdpSocket { - const DATAGRAM_MAX_LENGTH = 65023; + public const DATAGRAM_MAX_LENGTH = 65023; /** @var string */ protected $ip; diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 79b7d8361..d6eeb9ea7 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -30,19 +30,19 @@ class Logger implements LoggerInterface, ResettableInterface /** * Detailed debug information */ - const DEBUG = 100; + public const DEBUG = 100; /** * Interesting events * * Examples: User logs in, SQL logs. */ - const INFO = 200; + public const INFO = 200; /** * Uncommon events */ - const NOTICE = 250; + public const NOTICE = 250; /** * Exceptional occurrences that are not errors @@ -50,19 +50,19 @@ class Logger implements LoggerInterface, ResettableInterface * Examples: Use of deprecated APIs, poor use of an API, * undesirable things that are not necessarily wrong. */ - const WARNING = 300; + public const WARNING = 300; /** * Runtime errors */ - const ERROR = 400; + public const ERROR = 400; /** * Critical conditions * * Example: Application component unavailable, unexpected exception. */ - const CRITICAL = 500; + public const CRITICAL = 500; /** * Action must be taken immediately @@ -70,12 +70,12 @@ class Logger implements LoggerInterface, ResettableInterface * Example: Entire website down, database unavailable, etc. * This should trigger the SMS alerts and wake you up. */ - const ALERT = 550; + public const ALERT = 550; /** * Urgent alert. */ - const EMERGENCY = 600; + public const EMERGENCY = 600; /** * Monolog API version @@ -85,7 +85,7 @@ class Logger implements LoggerInterface, ResettableInterface * * @var int */ - const API = 2; + public const API = 2; /** * This is a static variable and not a constant to serve as an extension point for custom levels diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 9efff4e29..65eccc6f2 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -22,7 +22,7 @@ */ class PsrLogMessageProcessor implements ProcessorInterface { - const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; + public const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; /** @var ?string */ private $dateFormat; From 1c5b0b8ff4e9f42a74d5066dd684b5ab45e8e6d7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 19 Nov 2018 14:40:44 +0100 Subject: [PATCH 063/498] Update return types --- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- src/Monolog/Handler/BufferHandler.php | 8 +++---- src/Monolog/Handler/ChromePHPHandler.php | 12 ++++------ src/Monolog/Handler/CubeHandler.php | 10 ++++---- src/Monolog/Handler/DeduplicationHandler.php | 14 +++++------ src/Monolog/Handler/DynamoDbHandler.php | 13 +++------- src/Monolog/Handler/ElasticSearchHandler.php | 17 +++++-------- src/Monolog/Handler/ErrorLogHandler.php | 12 +++++----- src/Monolog/Handler/FilterHandler.php | 9 ++++--- src/Monolog/Handler/FingersCrossedHandler.php | 24 +++++++++++-------- src/Monolog/Handler/FirePHPHandler.php | 12 +++------- .../Monolog/Handler/ChromePHPHandlerTest.php | 6 ++--- tests/Monolog/Handler/FirePHPHandlerTest.php | 6 ++--- 13 files changed, 63 insertions(+), 82 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 7ff2b1608..5e46b13bf 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -97,7 +97,7 @@ public static function resetStatic(): void /** * Wrapper for register_shutdown_function to allow overriding */ - protected function registerShutdownFunction() + protected function registerShutdownFunction(): void { if (PHP_SAPI !== 'cli') { register_shutdown_function(['Monolog\Handler\BrowserConsoleHandler', 'send']); diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index a26430fe5..a73a9778b 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -36,11 +36,11 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa /** * @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 int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @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, $bufferLimit = 0, $level = Logger::DEBUG, bool $bubble = true, $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; @@ -82,7 +82,7 @@ public function handle(array $record): bool return false === $this->bubble; } - public function flush() + public function flush(): void { if ($this->bufferSize === 0) { return; @@ -112,7 +112,7 @@ public function close(): void /** * Clears the buffer without flushing any messages down to the wrapped handler. */ - public function clear() + public function clear(): void { $this->bufferSize = 0; $this->buffer = []; diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 46ef7d341..0afc07ef5 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -61,8 +61,8 @@ class ChromePHPHandler extends AbstractProcessingHandler protected static $sendHeaders = true; /** - * @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 + * @param string|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($level = Logger::DEBUG, bool $bubble = true) { @@ -110,7 +110,6 @@ protected function getDefaultFormatter(): FormatterInterface * * @see sendHeader() * @see send() - * @param array $record */ protected function write(array $record): void { @@ -128,7 +127,7 @@ protected function write(array $record): void * * @see sendHeader() */ - protected function send() + protected function send(): void { if (self::$overflowed || !self::$sendHeaders) { return; @@ -171,11 +170,8 @@ protected function send() /** * Send header string to the client - * - * @param string $header - * @param string $content */ - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { if (!headers_sent() && self::$sendHeaders) { header(sprintf('%s: %s', $header, $content)); diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 7de7705a7..8829eafd0 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -35,7 +35,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($url, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $url, $level = Logger::DEBUG, bool $bubble = true) { $urlInfo = parse_url($url); @@ -63,7 +63,7 @@ public function __construct($url, $level = Logger::DEBUG, bool $bubble = true) * @throws \LogicException when unable to connect to the socket * @throws MissingExtensionException when there is no socket extension */ - protected function connectUdp() + protected function connectUdp(): void { if (!extension_loaded('sockets')) { throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); @@ -83,7 +83,7 @@ protected function connectUdp() * Establish a connection to a http server * @throws \LogicException when no curl extension */ - protected function connectHttp() + protected function connectHttp(): void { if (!extension_loaded('curl')) { throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); @@ -126,7 +126,7 @@ protected function write(array $record): void } } - private function writeUdp($data) + private function writeUdp(string $data): void { if (!$this->udpConnection) { $this->connectUdp(); @@ -135,7 +135,7 @@ private function writeUdp($data) socket_send($this->udpConnection, $data, strlen($data), 0); } - private function writeHttp($data) + private function writeHttp(string $data): void { if (!$this->httpConnection) { $this->connectHttp(); diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index ce4b99e27..0c2a3cbdf 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -58,11 +58,11 @@ class DeduplicationHandler extends BufferHandler /** * @param HandlerInterface $handler Handler. * @param string $deduplicationStore The file/path where the deduplication log should be kept - * @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes + * @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 */ - public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $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, Logger::DEBUG, $bubble, false); @@ -71,7 +71,7 @@ public function __construct(HandlerInterface $handler, $deduplicationStore = nul $this->time = $time; } - public function flush() + public function flush(): void { if ($this->bufferSize === 0) { return; @@ -100,7 +100,7 @@ public function flush() } } - private function isDuplicate(array $record) + private function isDuplicate(array $record): bool { if (!file_exists($this->deduplicationStore)) { return false; @@ -130,10 +130,10 @@ private function isDuplicate(array $record) return false; } - private function collectLogs() + private function collectLogs(): void { if (!file_exists($this->deduplicationStore)) { - return false; + return; } $handle = fopen($this->deduplicationStore, 'rw+'); @@ -161,7 +161,7 @@ private function collectLogs() $this->gc = false; } - private function appendRecord(array $record) + private function appendRecord(array $record): void { file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); } diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index cd2bc64af..5bd6fd26b 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -49,12 +49,9 @@ class DynamoDbHandler extends AbstractProcessingHandler protected $marshaler; /** - * @param DynamoDbClient $client - * @param string $table - * @param int $level - * @param bool $bubble + * @param int|string $level */ - public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true) { if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) { $this->version = 3; @@ -87,11 +84,7 @@ protected function write(array $record): void ]); } - /** - * @param array $record - * @return array - */ - protected function filterEmptyFields(array $record) + protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { return !empty($value) || false === $value || 0 === $value; diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index 619e84dc5..a0ec2350e 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -46,10 +46,10 @@ class ElasticSearchHandler extends AbstractProcessingHandler protected $options = []; /** - * @param Client $client Elastica Client object - * @param array $options Handler configuration - * @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 + * @param Client $client Elastica Client object + * @param array $options Handler configuration + * @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 */ public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { @@ -85,11 +85,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter'); } - /** - * Getter options - * @return array - */ - public function getOptions() + public function getOptions(): array { return $this->options; } @@ -113,10 +109,9 @@ public function handleBatch(array $records): void /** * Use Elasticsearch bulk API to send list of documents - * @param array $documents * @throws \RuntimeException */ - protected function bulkSend(array $documents) + protected function bulkSend(array $documents): void { try { $this->client->addDocuments($documents); diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 60f12d11b..01b5008e8 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -29,12 +29,12 @@ class ErrorLogHandler extends AbstractProcessingHandler protected $expandNewlines; /** - * @param int $messageType Says where the error should go. - * @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 - * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries + * @param int $messageType Says where the error should go. + * @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 + * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries */ - public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, bool $bubble = true, $expandNewlines = false) + public function __construct(int $messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, bool $bubble = true, bool $expandNewlines = false) { parent::__construct($level, $bubble); @@ -51,7 +51,7 @@ public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logg /** * @return array With all available types */ - public static function getAvailableTypes() + public static function getAvailableTypes(): array { return [ self::OPERATING_SYSTEM, diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index d4517f296..e62d43fc1 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -50,7 +50,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * @param callable|HandlerInterface $handler Handler or factory callable($record, $this). * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided - * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array + * @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 */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) @@ -64,9 +64,6 @@ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel } } - /** - * @return array - */ public function getAcceptedLevels(): array { return array_flip($this->acceptedLevels); @@ -76,7 +73,7 @@ public function getAcceptedLevels(): 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 */ - public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY) + public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self { if (is_array($minLevelOrList)) { $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList); @@ -88,6 +85,8 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L })); } $this->acceptedLevels = array_flip($acceptedLevels); + + return $this; } /** diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index f7c5fd9ce..aba1b1d7c 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -23,6 +23,10 @@ * Only requests which actually trigger an error (or whatever your actionLevel is) will be * in the logs, but they will contain all records, not only those above the level threshold. * + * You can then have a passthruLevel as well which means that at the end of the request, + * even if it did not get activated, it will still send through log records of e.g. at least a + * warning level. + * * You can find the various activation strategies in the * Monolog\Handler\FingersCrossed\ namespace. * @@ -41,14 +45,14 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $passthruLevel; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). - * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action - * @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 $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * @param callable|HandlerInterface $handler Handler or factory callable($record, $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 */ - public function __construct($handler, $activationStrategy = null, $bufferSize = 0, bool $bubble = true, $stopBuffering = true, $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(Logger::WARNING); @@ -85,7 +89,7 @@ public function isHandling(array $record): bool /** * Manually activate this logger regardless of the activation strategy */ - public function activate() + public function activate(): void { if ($this->stopBuffering) { $this->buffering = false; @@ -152,7 +156,7 @@ public function reset() * * It also resets the handler to its initial buffering state. */ - public function clear() + public function clear(): void { $this->buffer = []; $this->reset(); @@ -161,7 +165,7 @@ public function clear() /** * Resets the state of the handler. Stops forwarding records to the wrapped handler. */ - private function flushBuffer() + private function flushBuffer(): void { if (null !== $this->passthruLevel) { $level = $this->passthruLevel; diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 29b4714d9..f3797fbd1 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -98,9 +98,8 @@ protected function getDefaultFormatter(): FormatterInterface * * @see createHeader() * @see sendHeader() - * @return array */ - protected function getInitHeaders() + protected function getInitHeaders(): array { // Initial payload consists of required headers for Wildfire return array_merge( @@ -112,11 +111,8 @@ protected function getInitHeaders() /** * Send header string to the client - * - * @param string $header - * @param string $content */ - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { if (!headers_sent() && self::$sendHeaders) { header(sprintf('%s: %s', $header, $content)); @@ -158,10 +154,8 @@ protected function write(array $record): void /** * Verifies if the headers are accepted by the current user agent - * - * @return bool */ - protected function headersAccepted() + protected function headersAccepted(): bool { if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) { return true; diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index a876b7dd5..c17a35ac9 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -136,7 +136,7 @@ class TestChromePHPHandler extends ChromePHPHandler { protected $headers = []; - public static function resetStatic() + public static function resetStatic(): void { self::$initialized = false; self::$overflowed = false; @@ -144,12 +144,12 @@ public static function resetStatic() self::$json['rows'] = []; } - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { $this->headers[$header] = $content; } - public function getHeaders() + public function getHeaders(): array { return $this->headers; } diff --git a/tests/Monolog/Handler/FirePHPHandlerTest.php b/tests/Monolog/Handler/FirePHPHandlerTest.php index aceac54be..3ada7cedd 100644 --- a/tests/Monolog/Handler/FirePHPHandlerTest.php +++ b/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -77,19 +77,19 @@ class TestFirePHPHandler extends FirePHPHandler { protected $headers = []; - public static function resetStatic() + public static function resetStatic(): void { self::$initialized = false; self::$sendHeaders = true; self::$messageIndex = 1; } - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { $this->headers[$header] = $content; } - public function getHeaders() + public function getHeaders(): array { return $this->headers; } From 495b2c60495cabd8c9c236851f5d43c2211bc73c Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Mon, 19 Nov 2018 14:03:47 -0200 Subject: [PATCH 064/498] Simplify return --- src/Monolog/Handler/NullHandler.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 93678e8f1..1d292252d 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -46,10 +46,6 @@ public function isHandling(array $record): bool */ public function handle(array $record): bool { - if ($record['level'] < $this->level) { - return false; - } - - return true; + return $record['level'] >= $this->level; } } From 84305769c16881cf617ffdcff9f159abd4d294da Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Mon, 19 Nov 2018 14:04:31 -0200 Subject: [PATCH 065/498] Fix files permissions --- src/Monolog/Handler/BrowserConsoleHandler.php | 0 src/Monolog/Handler/Slack/SlackRecord.php | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/Monolog/Handler/BrowserConsoleHandler.php mode change 100755 => 100644 src/Monolog/Handler/Slack/SlackRecord.php diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php old mode 100755 new mode 100644 diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php old mode 100755 new mode 100644 From 4a33226f25009758cb237b4383589cef023b9494 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 19 Nov 2018 23:28:33 +0100 Subject: [PATCH 066/498] Wrap up type-hint adding to all handlers --- src/Monolog/Formatter/LogmaticFormatter.php | 8 +- src/Monolog/Formatter/NormalizerFormatter.php | 8 +- src/Monolog/Handler/AbstractSyslogHandler.php | 2 +- src/Monolog/Handler/CubeHandler.php | 8 +- src/Monolog/Handler/FleepHookHandler.php | 21 ++--- src/Monolog/Handler/FlowdockHandler.php | 22 ++--- .../Handler/FormattableHandlerTrait.php | 2 - src/Monolog/Handler/GelfHandler.php | 2 +- src/Monolog/Handler/GroupHandler.php | 6 +- src/Monolog/Handler/HandlerWrapper.php | 4 - src/Monolog/Handler/HipChatHandler.php | 48 ++++++----- src/Monolog/Handler/IFTTTHandler.php | 10 +-- src/Monolog/Handler/InsightOpsHandler.php | 17 ++-- src/Monolog/Handler/LogEntriesHandler.php | 16 ++-- src/Monolog/Handler/LogglyHandler.php | 27 +++++-- src/Monolog/Handler/LogmaticHandler.php | 2 +- src/Monolog/Handler/MandrillHandler.php | 4 +- .../Handler/MissingExtensionException.php | 4 +- src/Monolog/Handler/MongoDBHandler.php | 4 +- src/Monolog/Handler/NativeMailerHandler.php | 38 +++------ src/Monolog/Handler/NewRelicHandler.php | 43 ++++------ src/Monolog/Handler/NullHandler.php | 9 ++- src/Monolog/Handler/PHPConsoleHandler.php | 11 +-- .../Handler/ProcessableHandlerInterface.php | 4 +- .../Handler/ProcessableHandlerTrait.php | 2 +- src/Monolog/Handler/PsrHandler.php | 2 +- src/Monolog/Handler/PushoverHandler.php | 51 ++++++++---- src/Monolog/Handler/RavenHandler.php | 12 ++- src/Monolog/Handler/RedisHandler.php | 7 +- src/Monolog/Handler/RollbarHandler.php | 2 +- src/Monolog/Handler/RotatingFileHandler.php | 22 ++--- src/Monolog/Handler/SamplingHandler.php | 4 +- src/Monolog/Handler/SlackHandler.php | 80 +++++-------------- src/Monolog/Handler/SlackWebhookHandler.php | 20 +++-- src/Monolog/Handler/SlackbotHandler.php | 14 ++-- src/Monolog/Handler/SocketHandler.php | 52 +++++++----- src/Monolog/Handler/SqsHandler.php | 2 +- src/Monolog/Handler/StreamHandler.php | 12 +-- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- src/Monolog/Handler/SyslogHandler.php | 12 +-- src/Monolog/Handler/SyslogUdpHandler.php | 22 ++--- src/Monolog/Handler/TestHandler.php | 28 +++++-- src/Monolog/Handler/ZendMonitorHandler.php | 8 +- src/Monolog/Processor/HostnameProcessor.php | 2 +- src/Monolog/Processor/TagProcessor.php | 8 +- tests/Monolog/Handler/NewRelicHandlerTest.php | 4 +- .../Monolog/Handler/SyslogUdpHandlerTest.php | 2 +- 47 files changed, 338 insertions(+), 352 deletions(-) diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index 8c6ff2f48..e0d44980b 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -30,14 +30,18 @@ class LogmaticFormatter extends JsonFormatter */ protected $appname = ''; - public function setHostname(string $hostname) + public function setHostname(string $hostname): self { $this->hostname = $hostname; + + return $this; } - public function setAppname(string $appname) + public function setAppname(string $appname): self { $this->appname = $appname; + + return $this; } /** diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 907efa960..6672bf92a 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -67,9 +67,11 @@ public function getMaxNormalizeDepth(): int return $this->maxNormalizeDepth; } - public function setMaxNormalizeDepth(int $maxNormalizeDepth): void + public function setMaxNormalizeDepth(int $maxNormalizeDepth): self { $this->maxNormalizeDepth = $maxNormalizeDepth; + + return $this; } /** @@ -80,9 +82,11 @@ public function getMaxNormalizeItemCount(): int return $this->maxNormalizeItemCount; } - public function setMaxNormalizeItemCount(int $maxNormalizeItemCount): void + public function setMaxNormalizeItemCount(int $maxNormalizeItemCount): self { $this->maxNormalizeItemCount = $maxNormalizeItemCount; + + return $this; } /** diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 9a9b52383..b7f249d7b 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -54,7 +54,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler ]; /** - * @param mixed $facility + * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant * @param string|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 */ diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 8829eafd0..298e572a2 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -80,13 +80,15 @@ protected function connectUdp(): void } /** - * Establish a connection to a http server - * @throws \LogicException when no curl extension + * Establish a connection to an http server + * + * @throws \LogicException when unable to connect to the socket + * @throws MissingExtensionException when no curl extension */ protected function connectHttp(): void { if (!extension_loaded('curl')) { - throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); + throw new MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler'); } $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 2740b8836..917810037 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -41,11 +41,11 @@ class FleepHookHandler extends SocketHandler * see https://fleep.io/integrations/webhooks/ * * @param string $token Webhook token - * @param bool|int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @throws MissingExtensionException */ - public function __construct($token, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler'); @@ -71,8 +71,6 @@ protected function getDefaultFormatter(): FormatterInterface /** * Handles a log record - * - * @param array $record */ public function write(array $record): void { @@ -82,11 +80,8 @@ public function write(array $record): void /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -95,11 +90,8 @@ protected function generateDataStream($record) /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; $header .= "Host: " . self::FLEEP_HOST . "\r\n"; @@ -112,11 +104,8 @@ private function buildHeader($content) /** * Builds the body of API call - * - * @param array $record - * @return string */ - private function buildContent($record) + private function buildContent(array $record): string { $dataArray = [ 'message' => $record['formatted'], diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index 096666226..be46d0321 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -34,13 +34,12 @@ class FlowdockHandler extends SocketHandler protected $apiToken; /** - * @param string $apiToken - * @param bool|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 + * @param string|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 * * @throws MissingExtensionException if OpenSSL is missing */ - public function __construct($apiToken, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); @@ -84,11 +83,8 @@ protected function write(array $record): void /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -97,22 +93,16 @@ protected function generateDataStream($record) /** * Builds the body of API call - * - * @param array $record - * @return string */ - private function buildContent($record) + private function buildContent(array $record): string { return json_encode($record['formatted']['flowdock']); } /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; $header .= "Host: api.flowdock.com\r\n"; diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index b1f1b588a..00140b4e0 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -53,8 +53,6 @@ public function getFormatter(): FormatterInterface * Gets the default formatter. * * Overwrite this if the LineFormatter is not a good default for your handler. - * - * @return FormatterInterface */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index b5c113559..d6965fa7d 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -31,7 +31,7 @@ class GelfHandler extends AbstractProcessingHandler /** * @param PublisherInterface $publisher a publisher object - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 309d3be99..3aa1201c3 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -26,8 +26,8 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset protected $handlers; /** - * @param array $handlers Array of Handlers. - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param HandlerInterface[] $handlers Array of Handlers. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(array $handlers, bool $bubble = true) { @@ -114,7 +114,7 @@ public function close(): void /** * {@inheritdoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { foreach ($this->handlers as $handler) { $handler->setFormatter($formatter); diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index c44b7036d..dfbc16d19 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -38,10 +38,6 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F */ protected $handler; - /** - * HandlerWrapper constructor. - * @param HandlerInterface $handler - */ public function __construct(HandlerInterface $handler) { $this->handler = $handler; diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index ce09299db..4ef6b253b 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -70,18 +70,27 @@ class HipChatHandler extends SocketHandler private $host; /** - * @param string $token HipChat API Token - * @param string $room The room that should be alerted of the message (Id or Name) - * @param string $name Name used in the "from" field. - * @param bool $notify Trigger a notification in clients or not - * @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 - * @param bool $useSSL Whether to connect via SSL. - * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) - * @param string $host The HipChat server hostname. + * @param string $token HipChat API Token + * @param string $room The room that should be alerted of the message (Id or Name) + * @param string|null $name Name used in the "from" field. + * @param bool $notify Trigger a notification in clients or not + * @param string|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 + * @param bool $useSSL Whether to connect via SSL. + * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) + * @param string $host The HipChat server hostname. */ - public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, bool $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com') - { + public function __construct( + string $token, + string $room, + ?string $name = 'Monolog', + bool $notify = false, + $level = Logger::CRITICAL, + bool $bubble = true, + bool $useSSL = true, + string $format = 'text', + string $host = 'api.hipchat.com' + ) { $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80'; parent::__construct($connectionString, $level, $bubble); @@ -95,11 +104,8 @@ public function __construct($token, $room, $name = 'Monolog', $notify = false, $ /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -108,11 +114,8 @@ protected function generateDataStream($record) /** * Builds the body of API call - * - * @param array $record - * @return string */ - private function buildContent($record) + private function buildContent(array $record): string { $dataArray = [ 'notify' => $this->notify ? 'true' : 'false', @@ -296,13 +299,8 @@ private function combineRecords(array $records): array * Note that this might cause false failures in the specific case of using * a valid name with less than 16 characters, but 16 or more bytes, on a * system where `mb_strlen()` is unavailable. - * - * @param string $str - * @param int $length - * - * @return bool */ - private function validateStringLength($str, $length) + private function validateStringLength(string $str, int $length): bool { if (function_exists('mb_strlen')) { return (mb_strlen($str) <= $length); diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 669b3f36f..21043c502 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -30,12 +30,12 @@ class IFTTTHandler extends AbstractProcessingHandler private $secretKey; /** - * @param string $eventName The name of the IFTTT Maker event that should be triggered - * @param string $secretKey A valid IFTTT secret key - * @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 + * @param string $eventName The name of the IFTTT Maker event that should be triggered + * @param string $secretKey A valid IFTTT secret key + * @param string|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($eventName, $secretKey, $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $eventName, string $secretKey, $level = Logger::ERROR, bool $bubble = true) { $this->eventName = $eventName; $this->secretKey = $secretKey; diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index e211cc753..1f6d41fcc 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -27,15 +27,15 @@ class InsightOpsHandler extends SocketHandler 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 int $level The minimum logging level to trigger this handler - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * @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|int $level The minimum logging level to trigger this handler + * @param bool $bubble Whether or not messages that are handled should bubble up the stack. * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $token, string $region = 'us', bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); @@ -51,11 +51,8 @@ public function __construct($token, $region = 'us', $useSSL = true, $level = Log /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 3af5b2413..66de5f800 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -24,14 +24,15 @@ class LogEntriesHandler extends SocketHandler protected $logToken; /** - * @param string $token Log token supplied by LogEntries - * @param bool $useSSL Whether or not SSL encryption should be used. - * @param int $level The minimum logging level to trigger this handler - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * @param string $token Log token supplied by LogEntries + * @param bool $useSSL Whether or not SSL encryption should be used. + * @param string|int $level The minimum logging level to trigger this handler + * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * @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($token, $useSSL = true, $level = Logger::DEBUG, bool $bubble = true, string $host = 'data.logentries.com') + public function __construct(string $token, bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true, string $host = 'data.logentries.com') { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); @@ -44,11 +45,8 @@ public function __construct($token, $useSSL = true, $level = Logger::DEBUG, bool /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 647c7e136..abec20b84 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -32,10 +32,17 @@ class LogglyHandler extends AbstractProcessingHandler protected $tag = []; - public function __construct($token, $level = Logger::DEBUG, bool $bubble = true) + /** + * @param string $token API token supplied by Loggly + * @param string|int $level The minimum logging level to trigger this handler + * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * + * @throws MissingExtensionException If the curl extension is missing + */ + public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) { if (!extension_loaded('curl')) { - throw new \LogicException('The curl extension is needed to use the LogglyHandler'); + throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler'); } $this->token = $token; @@ -43,18 +50,28 @@ public function __construct($token, $level = Logger::DEBUG, bool $bubble = true) parent::__construct($level, $bubble); } - public function setTag($tag) + /** + * @param string[]|string $tag + */ + public function setTag($tag): self { $tag = !empty($tag) ? $tag : []; $this->tag = is_array($tag) ? $tag : [$tag]; + + return $this; } - public function addTag($tag) + /** + * @param string[]|string $tag + */ + public function addTag($tag): self { if (!empty($tag)) { $tag = is_array($tag) ? $tag : [$tag]; $this->tag = array_unique(array_merge($this->tag, $tag)); } + + return $this; } protected function write(array $record): void @@ -75,7 +92,7 @@ public function handleBatch(array $records): void } } - protected function send($data, $endpoint) + protected function send(string $data, string $endpoint): void { $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token); diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 97472204a..209af161f 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -64,7 +64,7 @@ public function __construct(string $token, string $hostname = '', string $appnam /** * {@inheritdoc} */ - protected function generateDataStream($record): string + protected function generateDataStream(array $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index f84aa8cc1..46b8bff03 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -27,10 +27,10 @@ class MandrillHandler extends MailHandler /** * @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 - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct($apiKey, $message, $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $apiKey, $message, $level = Logger::ERROR, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/MissingExtensionException.php b/src/Monolog/Handler/MissingExtensionException.php index 1554b3453..3965aeea5 100644 --- a/src/Monolog/Handler/MissingExtensionException.php +++ b/src/Monolog/Handler/MissingExtensionException.php @@ -12,9 +12,9 @@ namespace Monolog\Handler; /** - * Exception can be thrown if an extension for an handler is missing + * Exception can be thrown if an extension for a handler is missing * - * @author Christian Bergau + * @author Christian Bergau */ class MissingExtensionException extends \Exception { diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 98a238221..e7539174e 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -43,10 +43,10 @@ class MongoDBHandler extends AbstractProcessingHandler * @param Client|Manager $mongodb MongoDB library or driver client * @param string $database Database name * @param string $collection Collection name - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct($mongodb, $database, $collection, $level = Logger::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'); diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index b6f8dbbb5..cd205611a 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -54,7 +54,7 @@ class NativeMailerHandler extends MailHandler /** * The Content-type for the message - * @var string + * @var string|null */ protected $contentType; @@ -68,11 +68,11 @@ class NativeMailerHandler extends MailHandler * @param string|array $to The receiver of the mail * @param string $subject The subject of the mail * @param string $from The sender of the mail - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int $maxColumnWidth The maximum column width that the message lines will have */ - public function __construct($to, $subject, $from, $level = Logger::ERROR, bool $bubble = true, $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; @@ -84,10 +84,9 @@ public function __construct($to, $subject, $from, $level = Logger::ERROR, bool $ /** * Add headers to the message * - * @param string|array $headers Custom added headers - * @return self + * @param string|array $headers Custom added headers */ - public function addHeader($headers) + public function addHeader($headers): self { foreach ((array) $headers as $header) { if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) { @@ -102,10 +101,9 @@ public function addHeader($headers) /** * Add parameters to the message * - * @param string|array $parameters Custom added parameters - * @return self + * @param string|array $parameters Custom added parameters */ - public function addParameter($parameters) + public function addParameter($parameters): self { $this->parameters = array_merge($this->parameters, (array) $parameters); @@ -141,28 +139,20 @@ protected function send(string $content, array $records): void } } - /** - * @return string $contentType - */ - public function getContentType() + public function getContentType(): ?string { return $this->contentType; } - /** - * @return string $encoding - */ - public function getEncoding() + public function getEncoding(): string { return $this->encoding; } /** - * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML - * messages. - * @return self + * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML messages. */ - public function setContentType($contentType) + public function setContentType(string $contentType): self { if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) { throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection'); @@ -173,11 +163,7 @@ public function setContentType($contentType) return $this; } - /** - * @param string $encoding - * @return self - */ - public function setEncoding($encoding) + public function setEncoding(string $encoding): self { if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) { throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection'); diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index c4540b69b..6d7eb9bb4 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -29,14 +29,14 @@ class NewRelicHandler extends AbstractProcessingHandler /** * Name of the New Relic application that will receive logs from this handler. * - * @var string + * @var string|null */ protected $appName; /** * Name of the current transaction * - * @var string + * @var string|null */ protected $transactionName; @@ -51,16 +51,18 @@ class NewRelicHandler extends AbstractProcessingHandler /** * {@inheritDoc} * - * @param string $appName - * @param bool $explodeArrays - * @param string $transactionName + * @param string|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. + * @param string|null $appName + * @param bool $explodeArrays + * @param string|null $transactionName */ public function __construct( $level = Logger::ERROR, - $bubble = true, - $appName = null, - $explodeArrays = false, - $transactionName = null + bool $bubble = true, + ?string $appName = null, + bool $explodeArrays = false, + ?string $transactionName = null ) { parent::__construct($level, $bubble); @@ -124,7 +126,7 @@ protected function write(array $record): void * * @return bool */ - protected function isNewRelicEnabled() + protected function isNewRelicEnabled(): bool { return extension_loaded('newrelic'); } @@ -132,11 +134,8 @@ protected function isNewRelicEnabled() /** * Returns the appname where this log should be sent. Each log can override the default appname, set in this * handler's constructor, by providing the appname in it's context. - * - * @param array $context - * @return null|string */ - protected function getAppName(array $context) + protected function getAppName(array $context): ?string { if (isset($context['appname'])) { return $context['appname']; @@ -148,12 +147,8 @@ protected function getAppName(array $context) /** * Returns the name of the current transaction. Each log can override the default transaction name, set in this * handler's constructor, by providing the transaction_name in it's context - * - * @param array $context - * - * @return null|string */ - protected function getTransactionName(array $context) + protected function getTransactionName(array $context): ?string { if (isset($context['transaction_name'])) { return $context['transaction_name']; @@ -164,20 +159,16 @@ protected function getTransactionName(array $context) /** * Sets the NewRelic application that should receive this log. - * - * @param string $appName */ - protected function setNewRelicAppName($appName) + protected function setNewRelicAppName(string $appName): void { newrelic_set_appname($appName); } /** * Overwrites the name of the current transaction - * - * @param string $transactionName */ - protected function setNewRelicTransactionName($transactionName) + protected function setNewRelicTransactionName(string $transactionName): void { newrelic_name_transaction($transactionName); } @@ -186,7 +177,7 @@ protected function setNewRelicTransactionName($transactionName) * @param string $key * @param mixed $value */ - protected function setNewRelicParameter($key, $value) + protected function setNewRelicParameter(string $key, $value): void { if (null === $value || is_scalar($value)) { newrelic_add_custom_parameter($key, $value); diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 93678e8f1..bb81f8d23 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -23,14 +23,17 @@ */ class NullHandler extends Handler { + /** + * @var int + */ private $level; /** - * @param int $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 */ - public function __construct(int $level = Logger::DEBUG) + public function __construct($level = Logger::DEBUG) { - $this->level = $level; + $this->level = Logger::toMonologLevel($level); } /** diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index f40e3d5f7..356e07483 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -68,8 +68,8 @@ class PHPConsoleHandler extends AbstractProcessingHandler /** * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param int|string $level - * @param bool $bubble + * @param string|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. * @throws \RuntimeException */ public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) @@ -82,7 +82,7 @@ public function __construct(array $options = [], ?Connector $connector = null, $ $this->connector = $this->initConnector($connector); } - private function initOptions(array $options) + private function initOptions(array $options): array { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); if ($wrongOptions) { @@ -95,7 +95,7 @@ private function initOptions(array $options) /** * @suppress PhanTypeMismatchArgument */ - private function initConnector(Connector $connector = null): Connector + private function initConnector(?Connector $connector = null): Connector { if (!$connector) { if ($this->options['dataStorage']) { @@ -171,9 +171,6 @@ public function handle(array $record): bool /** * Writes the record down to the log of the implementing handler - * - * @param array $record - * @return void */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 9556f9857..27077c62d 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -21,8 +21,8 @@ interface ProcessableHandlerInterface /** * Adds a processor in the stack. * - * @param callable $callback - * @return HandlerInterface self + * @param ProcessorInterface|callable $callback + * @return HandlerInterface self */ public function pushProcessor(callable $callback): HandlerInterface; diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index ee5871b35..c4c38ec5a 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -60,7 +60,7 @@ protected function processRecord(array $record): array return $record; } - protected function resetProcessors() + protected function resetProcessors(): void { foreach ($this->processors as $processor) { if ($processor instanceof ResettableInterface) { diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index b59e99af1..a9780b011 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -30,7 +30,7 @@ class PsrHandler extends AbstractHandler /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index c6cba6e80..3d07e41f2 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -68,19 +68,31 @@ class PushoverHandler extends SocketHandler * @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 $title Title sent to the Pushover API - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @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 $highPriorityLevel The minimum logging level at which this handler will start + * @param string|int $highPriorityLevel The minimum logging level at which this handler will start * sending "high priority" requests to the Pushover API - * @param int $emergencyLevel The minimum logging level at which this handler will start + * @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). + * @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). */ - public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, bool $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) - { + public function __construct( + string $token, + $users, + ?string $title = null, + $level = Logger::CRITICAL, + bool $bubble = true, + bool $useSSL = true, + $highPriorityLevel = Logger::CRITICAL, + $emergencyLevel = Logger::EMERGENCY, + int $retry = 30, + int $expire = 25200 + ) { $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; parent::__construct($connectionString, $level, $bubble); @@ -93,14 +105,14 @@ public function __construct($token, $users, $title = null, $level = Logger::CRIT $this->expire = $expire; } - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } - private function buildContent($record) + private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. $maxMessageLength = 512 - strlen($this->title); @@ -141,7 +153,7 @@ private function buildContent($record) return http_build_query($dataArray); } - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /1/messages.json HTTP/1.1\r\n"; $header .= "Host: api.pushover.net\r\n"; @@ -164,22 +176,27 @@ protected function write(array $record): void $this->user = null; } - public function setHighPriorityLevel($value) + public function setHighPriorityLevel($value): self { - $this->highPriorityLevel = $value; + $this->highPriorityLevel = Logger::toMonologLevel($value); + + return $this; } - public function setEmergencyLevel($value) + public function setEmergencyLevel($value): self { - $this->emergencyLevel = $value; + $this->emergencyLevel = Logger::toMonologLevel($value); + + return $this; } /** * Use the formatted message? - * @param bool $value */ - public function useFormattedMessage($value) + public function useFormattedMessage(bool $value): self { - $this->useFormattedMessage = (bool) $value; + $this->useFormattedMessage = $value; + + return $this; } } diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 204a540e8..6836c488f 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -114,9 +114,11 @@ public function handleBatch(array $records): void * * @param FormatterInterface $formatter */ - public function setBatchFormatter(FormatterInterface $formatter): void + public function setBatchFormatter(FormatterInterface $formatter): self { $this->batchFormatter = $formatter; + + return $this; } /** @@ -250,13 +252,17 @@ public function setEnvironment($value): self /** * @link https://docs.sentry.io/learn/breadcrumbs/ */ - public function addBreadcrumb(array $crumb): void + public function addBreadcrumb(array $crumb): self { $this->ravenClient->breadcrumbs->record($crumb); + + return $this; } - public function resetBreadcrumbs(): void + public function resetBreadcrumbs(): self { $this->ravenClient->breadcrumbs->reset(); + + return $this; } } diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index ede8be318..3894513dd 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -35,7 +35,7 @@ class RedisHandler extends AbstractProcessingHandler /** * @param \Predis\Client|\Redis $redis The redis instance * @param string $key The key name to push records to - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ @@ -67,11 +67,8 @@ protected function write(array $record): void /** * Write and cap the collection * Writes the record to the redis list and caps its - * - * @param array $record associative record array - * @return void */ - protected function writeCapped(array $record) + protected function writeCapped(array $record): void { if ($this->redisClient instanceof \Redis) { $this->redisClient->multi() diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index f23ac2ee6..979d651e3 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -60,7 +60,7 @@ class RollbarHandler extends AbstractProcessingHandler /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 58f6ac11a..f5446087e 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -37,14 +37,14 @@ class RotatingFileHandler extends StreamHandler protected $dateFormat; /** - * @param string $filename - * @param int $maxFiles The maximal amount of files to keep (0 means unlimited) - * @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 - * @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 string|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 + * @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($filename, $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, $filePermission = null, $useLocking = false) + public function __construct(string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { $this->filename = $filename; $this->maxFiles = (int) $maxFiles; @@ -79,7 +79,7 @@ public function reset() } } - public function setFilenameFormat($filenameFormat, $dateFormat) + public function setFilenameFormat(string $filenameFormat, string $dateFormat): self { if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { throw new InvalidArgumentException( @@ -98,6 +98,8 @@ public function setFilenameFormat($filenameFormat, $dateFormat) $this->dateFormat = $dateFormat; $this->url = $this->getTimedFilename(); $this->close(); + + return $this; } /** @@ -158,7 +160,7 @@ protected function rotate(): void $this->mustRotate = false; } - protected function getTimedFilename() + protected function getTimedFilename(): string { $fileInfo = pathinfo($this->filename); $timedFilename = str_replace( @@ -174,7 +176,7 @@ protected function getTimedFilename() return $timedFilename; } - protected function getGlobPattern() + protected function getGlobPattern(): string { $fileInfo = pathinfo($this->filename); $glob = str_replace( diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 8a25cbb72..814c90483 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -41,9 +41,9 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter /** * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). - * @param int $factor Sample factor + * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled) */ - public function __construct($handler, $factor) + public function __construct($handler, int $factor) { parent::__construct(); $this->handler = $handler; diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 30a10fc12..553db40f3 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -48,8 +48,18 @@ class SlackHandler extends SocketHandler * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ - public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, bool $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array()) - { + public function __construct( + string $token, + string $channel, + ?string $username = null, + bool $useAttachment = true, + ?string $iconEmoji = null, + $level = Logger::CRITICAL, + bool $bubble = true, + bool $useShortAttachment = false, + bool $includeContextAndExtra = false, + array $excludeFields = array() + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); } @@ -69,23 +79,20 @@ public function __construct($token, $channel, $username = null, $useAttachment = $this->token = $token; } - public function getSlackRecord() + public function getSlackRecord(): SlackRecord { return $this->slackRecord; } - public function getToken() + public function getToken(): string { return $this->token; } /** * {@inheritdoc} - * - * @param array $record - * @return string */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -94,24 +101,15 @@ protected function generateDataStream($record) /** * Builds the body of API call - * - * @param array $record - * @return string */ - private function buildContent($record) + private function buildContent(array $record): string { $dataArray = $this->prepareContentData($record); return http_build_query($dataArray); } - /** - * Prepares content data - * - * @param array $record - * @return array - */ - protected function prepareContentData($record) + protected function prepareContentData(array $record): array { $dataArray = $this->slackRecord->getSlackData($record); $dataArray['token'] = $this->token; @@ -125,11 +123,8 @@ protected function prepareContentData($record) /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /api/chat.postMessage HTTP/1.1\r\n"; $header .= "Host: slack.com\r\n"; @@ -142,8 +137,6 @@ private function buildHeader($content) /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { @@ -157,7 +150,7 @@ protected function write(array $record): void * If we do not read some but close the socket too early, slack sometimes * drops the request entirely. */ - protected function finalizeWrite() + protected function finalizeWrite(): void { $res = $this->getResource(); if (is_resource($res)) { @@ -166,41 +159,6 @@ protected function finalizeWrite() $this->closeSocket(); } - /** - * Returned a Slack message attachment color associated with - * provided level. - * - * @param int $level - * @return string - * @deprecated Use underlying SlackRecord instead - */ - protected function getAttachmentColor($level) - { - trigger_error( - 'SlackHandler::getAttachmentColor() is deprecated. Use underlying SlackRecord instead.', - E_USER_DEPRECATED - ); - - return $this->slackRecord->getAttachmentColor($level); - } - - /** - * Stringifies an array of key/value pairs to be used in attachment fields - * - * @param array $fields - * @return string - * @deprecated Use underlying SlackRecord instead - */ - protected function stringify($fields) - { - trigger_error( - 'SlackHandler::stringify() is deprecated. Use underlying SlackRecord instead.', - E_USER_DEPRECATED - ); - - return $this->slackRecord->stringify($fields); - } - public function setFormatter(FormatterInterface $formatter): HandlerInterface { parent::setFormatter($formatter); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 9c26486ca..9b19a2e1a 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -43,12 +43,22 @@ class SlackWebhookHandler extends AbstractProcessingHandler * @param string|null $iconEmoji The emoji name to use (or null) * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ - public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, bool $bubble = true, array $excludeFields = array()) - { + public function __construct( + string $webhookUrl, + ?string $channel = null, + ?string $username = null, + bool $useAttachment = true, + ?string $iconEmoji = null, + bool $useShortAttachment = false, + bool $includeContextAndExtra = false, + $level = Logger::CRITICAL, + bool $bubble = true, + array $excludeFields = array() + ) { parent::__construct($level, $bubble); $this->webhookUrl = $webhookUrl; @@ -64,12 +74,12 @@ public function __construct($webhookUrl, $channel = null, $username = null, $use ); } - public function getSlackRecord() + public function getSlackRecord(): SlackRecord { return $this->slackRecord; } - public function getWebhookUrl() + public function getWebhookUrl(): string { return $this->webhookUrl; } diff --git a/src/Monolog/Handler/SlackbotHandler.php b/src/Monolog/Handler/SlackbotHandler.php index 3a1dfa5c6..12f5d17b0 100644 --- a/src/Monolog/Handler/SlackbotHandler.php +++ b/src/Monolog/Handler/SlackbotHandler.php @@ -40,13 +40,13 @@ class SlackbotHandler extends AbstractProcessingHandler private $channel; /** - * @param string $slackTeam Slack team slug - * @param string $token Slackbot token - * @param string $channel Slack channel (encoded ID or name) - * @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 + * @param string $slackTeam Slack team slug + * @param string $token Slackbot token + * @param string $channel Slack channel (encoded ID or name) + * @param string|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($slackTeam, $token, $channel, $level = Logger::CRITICAL, bool $bubble = true) + public function __construct(string $slackTeam, string $token, string $channel, $level = Logger::CRITICAL, bool $bubble = true) { parent::__construct($level, $bubble); @@ -57,8 +57,6 @@ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITI /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 3dc6d9754..2861e67d7 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -38,11 +38,11 @@ class SocketHandler extends AbstractProcessingHandler private $lastWritingAt; /** - * @param string $connectionString Socket connection string - * @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 + * @param string $connectionString Socket connection string + * @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 */ - public function __construct($connectionString, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $connectionString, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); $this->connectionString = $connectionString; @@ -88,9 +88,11 @@ public function closeSocket(): void /** * Set socket connection to be persistent. It only has effect before the connection is initiated. */ - public function setPersistent(bool $persistent): void + public function setPersistent(bool $persistent): self { $this->persistent = $persistent; + + return $this; } /** @@ -98,10 +100,12 @@ public function setPersistent(bool $persistent): void * * @see http://php.net/manual/en/function.fsockopen.php */ - public function setConnectionTimeout(float $seconds): void + public function setConnectionTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->connectionTimeout = (float) $seconds; + $this->connectionTimeout = $seconds; + + return $this; } /** @@ -109,10 +113,12 @@ public function setConnectionTimeout(float $seconds): void * * @see http://php.net/manual/en/function.stream-set-timeout.php */ - public function setTimeout(float $seconds): void + public function setTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->timeout = (float) $seconds; + $this->timeout = $seconds; + + return $this; } /** @@ -120,18 +126,22 @@ public function setTimeout(float $seconds): void * * @param float $seconds 0 for no timeout */ - public function setWritingTimeout(float $seconds): void + public function setWritingTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->writingTimeout = (float) $seconds; + $this->writingTimeout = $seconds; + + return $this; } /** * Set chunk size. Only has effect during connection in the writing cycle. */ - public function setChunkSize(int $bytes): void + public function setChunkSize(int $bytes): self { $this->chunkSize = $bytes; + + return $this; } /** @@ -144,10 +154,8 @@ public function getConnectionString(): string /** * Get persistent setting - * - * @return bool */ - public function isPersistent() + public function isPersistent(): bool { return $this->persistent; } @@ -268,7 +276,7 @@ private function connectIfNotConnected() $this->connect(); } - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { return (string) $record['formatted']; } @@ -281,14 +289,14 @@ protected function getResource() return $this->resource; } - private function connect() + private function connect(): void { $this->createSocketResource(); $this->setSocketTimeout(); $this->setStreamChunkSize(); } - private function createSocketResource() + private function createSocketResource(): void { if ($this->isPersistent()) { $resource = $this->pfsockopen(); @@ -301,21 +309,21 @@ private function createSocketResource() $this->resource = $resource; } - private function setSocketTimeout() + private function setSocketTimeout(): void { if (!$this->streamSetTimeout()) { throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); } } - private function setStreamChunkSize() + private function setStreamChunkSize(): void { if ($this->chunkSize && !$this->streamSetChunkSize()) { throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); } } - private function writeToSocket($data) + private function writeToSocket(string $data): void { $length = strlen($data); $sent = 0; @@ -344,7 +352,7 @@ private function writeToSocket($data) } } - private function writingIsTimedOut($sent) + private function writingIsTimedOut(int $sent): bool { $writingTimeout = (int) floor($this->writingTimeout); if (0 === $writingTimeout) { diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index f282d023b..07c2656eb 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -31,7 +31,7 @@ class SqsHandler extends AbstractProcessingHandler /** @var string */ private $queueUrl; - public function __construct(SqsClient $sqsClient, $queueUrl, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 92ccc04d1..dad7a6dcd 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -33,7 +33,7 @@ class StreamHandler extends AbstractProcessingHandler /** * @param resource|string $stream - * @param int $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @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 @@ -41,7 +41,7 @@ class StreamHandler extends AbstractProcessingHandler * @throws \Exception If a missing directory is not buildable * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, $filePermission = null, $useLocking = false) + public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); if (is_resource($stream)) { @@ -82,7 +82,7 @@ public function getStream() * * @return string|null */ - public function getUrl() + public function getUrl(): ?string { return $this->url; } @@ -128,12 +128,12 @@ protected function write(array $record): void * @param resource $stream * @param array $record */ - protected function streamWrite($stream, array $record) + protected function streamWrite($stream, array $record): void { fwrite($stream, (string) $record['formatted']); } - private function customErrorHandler($code, $msg) + private function customErrorHandler($code, $msg): void { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); } @@ -152,7 +152,7 @@ private function getDirFromStream(string $stream): ?string return null; } - private function createDir() + private function createDir(): void { // Do not try to create dir if it has already been tried. if ($this->dirCreated) { diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 4fa14ca87..88279d118 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -30,7 +30,7 @@ class SwiftMailerHandler extends MailHandler /** * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced - * @param int|string $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 * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, bool $bubble = true) diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index fb7faef63..20594cedd 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -32,13 +32,13 @@ class SyslogHandler extends AbstractSyslogHandler protected $logopts; /** - * @param string $ident - * @param mixed $facility - * @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 - * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID + * @param string $ident + * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant + * @param string|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 + * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ - public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, $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); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 103206bbf..267d49e76 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -25,14 +25,14 @@ class SyslogUdpHandler extends AbstractSyslogHandler protected $ident; /** - * @param string $host - * @param int $port - * @param mixed $facility - * @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 - * @param string $ident Program name or tag for each log message. + * @param string $host + * @param int $port + * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant + * @param string|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 + * @param string $ident Program name or tag for each log message. */ - public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, $ident = 'php') + public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php') { parent::__construct($facility, $level, $bubble); @@ -69,7 +69,7 @@ private function splitMessageIntoLines($message): array /** * Make common syslog header (see rfc5424) */ - protected function makeCommonSyslogHeader($severity): string + protected function makeCommonSyslogHeader(int $severity): string { $priority = $severity + $this->facility; @@ -88,7 +88,7 @@ protected function makeCommonSyslogHeader($severity): string $pid . " - - "; } - protected function getDateTime() + protected function getDateTime(): string { return date(\DateTime::RFC3339); } @@ -96,8 +96,10 @@ protected function getDateTime() /** * Inject your own socket, mainly used for testing */ - public function setSocket(UdpSocket $socket) + public function setSocket(UdpSocket $socket): self { $this->socket = $socket; + + return $this; } } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index db9174e25..b12e28185 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Logger; + /** * Used for testing purposes. * @@ -79,16 +81,19 @@ public function clear() $this->recordsByLevel = []; } - public function hasRecords($level) + /** + * @param string|int $level Logging level value or name + */ + public function hasRecords($level): bool { - return isset($this->recordsByLevel[$level]); + return isset($this->recordsByLevel[Logger::toMonologLevel($level)]); } /** * @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 int $level Logger::LEVEL constant value + * @param string|int $level Logging level value or name */ - public function hasRecord($record, $level) + public function hasRecord($record, $level): bool { if (is_string($record)) { $record = array('message' => $record); @@ -106,22 +111,33 @@ public function hasRecord($record, $level) }, $level); } - public function hasRecordThatContains($message, $level) + /** + * @param string|int $level Logging level value or name + */ + public function hasRecordThatContains(string $message, $level): bool { return $this->hasRecordThatPasses(function ($rec) use ($message) { return strpos($rec['message'], $message) !== false; }, $level); } - public function hasRecordThatMatches($regex, $level) + /** + * @param string|int $level Logging level value or name + */ + public function hasRecordThatMatches(string $regex, $level): bool { return $this->hasRecordThatPasses(function ($rec) use ($regex) { return preg_match($regex, $rec['message']) > 0; }, $level); } + /** + * @param string|int $level Logging level value or name + */ public function hasRecordThatPasses(callable $predicate, $level) { + $level = Logger::toMonologLevel($level); + if (!isset($this->recordsByLevel[$level])) { return false; } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 95eca6d59..0ced70792 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -39,10 +39,8 @@ class ZendMonitorHandler extends AbstractProcessingHandler ]; /** - * Construct - * - * @param int $level - * @param bool $bubble + * @param string|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. * @throws MissingExtensionException */ public function __construct($level = Logger::DEBUG, bool $bubble = true) @@ -65,7 +63,7 @@ protected function write(array $record): void ); } - protected function writeZendMonitorCustomEvent(int $level, string $message, array $formatted) + protected function writeZendMonitorCustomEvent(int $level, string $message, array $formatted): void { zend_monitor_custom_event($level, $message, $formatted); } diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index fef408497..7c23db8b1 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -14,7 +14,7 @@ /** * Injects value of gethostname in all records */ -class HostnameProcessor +class HostnameProcessor implements ProcessorInterface { private static $host; diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index 6c33e4fc4..199760ad8 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -25,14 +25,18 @@ public function __construct(array $tags = []) $this->setTags($tags); } - public function addTags(array $tags = []) + public function addTags(array $tags = []): self { $this->tags = array_merge($this->tags, $tags); + + return $this; } - public function setTags(array $tags = []) + public function setTags(array $tags = []): self { $this->tags = $tags; + + return $this; } public function __invoke(array $record): array diff --git a/tests/Monolog/Handler/NewRelicHandlerTest.php b/tests/Monolog/Handler/NewRelicHandlerTest.php index a71bbf88c..26160094d 100644 --- a/tests/Monolog/Handler/NewRelicHandlerTest.php +++ b/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -163,7 +163,7 @@ public function testTheTransactionNameCanBeOverriddenFromEachLog() class StubNewRelicHandlerWithoutExtension extends NewRelicHandler { - protected function isNewRelicEnabled() + protected function isNewRelicEnabled(): bool { return false; } @@ -171,7 +171,7 @@ protected function isNewRelicEnabled() class StubNewRelicHandler extends NewRelicHandler { - protected function isNewRelicEnabled() + protected function isNewRelicEnabled(): bool { return true; } diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index c35b33183..6656b17f1 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -23,7 +23,7 @@ class SyslogUdpHandlerTest extends TestCase */ public function testWeValidateFacilities() { - $handler = new SyslogUdpHandler("ip", null, "invalidFacility"); + $handler = new SyslogUdpHandler("ip", 514, "invalidFacility"); } public function testWeSplitIntoLines() From a7b16cfc7377d0198ae27303fda612f7f4737e9e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 19 Nov 2018 23:50:49 +0100 Subject: [PATCH 067/498] Allow setting a formatter on the PsrHandler, fixes #1070 --- src/Monolog/Handler/PsrHandler.php | 45 ++++++++++++++++++++++-- tests/Monolog/Handler/PsrHandlerTest.php | 18 ++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index a9780b011..e0c67dcd5 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -13,13 +13,18 @@ use Monolog\Logger; use Psr\Log\LoggerInterface; +use Monolog\Formatter\FormatterInterface; /** * Proxies log messages to an existing PSR-3 compliant logger. * + * If a formatter is configured, the formatter's output MUST be a string and the + * formatted message will be fed to the wrapped PSR logger instead of the original + * log record's message. + * * @author Michael Moussa */ -class PsrHandler extends AbstractHandler +class PsrHandler extends AbstractHandler implements FormattableHandlerInterface { /** * PSR-3 compliant logger @@ -28,6 +33,11 @@ class PsrHandler extends AbstractHandler */ protected $logger; + /** + * @var FormatterInterface + */ + protected $formatter; + /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied * @param string|int $level The minimum logging level at which this handler will be triggered @@ -49,8 +59,39 @@ public function handle(array $record): bool return false; } - $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']); + if ($this->formatter) { + $formatted = $this->formatter->format($record); + $this->logger->log(strtolower($record['level_name']), (string) $formatted, $record['context']); + } else { + $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']); + } return false === $this->bubble; } + + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->formatter = $formatter; + + return $this; + } + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(): FormatterInterface + { + if (!$this->formatter) { + throw new \LogicException('No formatter has been set and this handler does not have a default formatter'); + } + + return $this->formatter; + } } diff --git a/tests/Monolog/Handler/PsrHandlerTest.php b/tests/Monolog/Handler/PsrHandlerTest.php index e371512d9..bebaa71d2 100644 --- a/tests/Monolog/Handler/PsrHandlerTest.php +++ b/tests/Monolog/Handler/PsrHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Logger; +use Monolog\Formatter\LineFormatter; /** * @covers Monolog\Handler\PsrHandler::handle @@ -47,4 +48,21 @@ public function testHandlesAllLevels($levelName, $level) $handler = new PsrHandler($psrLogger); $handler->handle(['level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context]); } + + public function testFormatter() + { + $message = 'Hello, world!'; + $context = ['foo' => 'bar']; + $level = Logger::ERROR; + $levelName = 'error'; + + $psrLogger = $this->createMock('Psr\Log\NullLogger'); + $psrLogger->expects($this->once()) + ->method('log') + ->with(strtolower($levelName), 'dummy', $context); + + $handler = new PsrHandler($psrLogger); + $handler->setFormatter(new LineFormatter('dummy')); + $handler->handle(['level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context, 'extra' => [], 'date' => new \DateTimeImmutable()]); + } } From 7dd453e6944a4c65bdeedff47c54d95d8f72c8cb Mon Sep 17 00:00:00 2001 From: Kris Buist Date: Tue, 20 Nov 2018 20:03:58 +0100 Subject: [PATCH 068/498] Rename ThresholdHandler to OverflowHandler --- doc/02-handlers-formatters-processors.md | 8 ++++---- .../{ThresholdHandler.php => OverflowHandler.php} | 10 +++++----- ...esholdHandlerTest.php => OverflowHandlerTest.php} | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) rename src/Monolog/Handler/{ThresholdHandler.php => OverflowHandler.php} (91%) rename tests/Monolog/Handler/{ThresholdHandlerTest.php => OverflowHandlerTest.php} (88%) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index aeb77efd5..c5f3abac4 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -125,10 +125,10 @@ has accessors to read out the information. - [_HandlerWrapper_](../src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create your own wrappers easily. -- [_ThresholdHandler_](../src/Monolog/Handler/ThresholdHandler.php): This handler will buffer all the log messages it - receives, up until a configured threshold is reached, after it will pass all log messages to the wrapped handler. - Useful for applying in bath processing when you're only interested in significant failures instead of minor, single - erroneous events. +- [_OverflowHandler_](../src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it + receives, up until a configured threshold of number of messages of a certain lever is reached, after it will pass all + log messages to the wrapped handler. Useful for applying in bath processing when you're only interested in significant + failures instead of minor, single erroneous events. ## Formatters diff --git a/src/Monolog/Handler/ThresholdHandler.php b/src/Monolog/Handler/OverflowHandler.php similarity index 91% rename from src/Monolog/Handler/ThresholdHandler.php rename to src/Monolog/Handler/OverflowHandler.php index 2b0949daf..30e81c430 100644 --- a/src/Monolog/Handler/ThresholdHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -15,7 +15,7 @@ /** - * Handler to only pass log messages when a certain threshold of messages is reached. + * Handler to only pass log messages when a certain threshold of number of messages is reached. * * This can be useful in cases of processing a batch of data, but you're for example only interested * in case it fails catastrophically instead of a warning for 1 or 2 events. Worse things can happen, right? @@ -27,14 +27,14 @@ * $handler = new SomeHandler(...) * * // Pass all warnings to the handler when more than 10 & all error messages when more then 5 - * $threshold = new ThresholdHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); + * $overflow = new OverflowHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); * - * $log->pushHandler($threshold); + * $log->pushHandler($overflow); *``` * * @author Kris Buist */ -class ThresholdHandler extends AbstractHandler +class OverflowHandler extends AbstractHandler { /** @var HandlerInterface */ private $handler; @@ -105,7 +105,7 @@ public function handle(array $record): bool } if ($this->thresholdMap[$level] > 0) { - // The threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 + // The overflow threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 $this->thresholdMap[$level]--; $this->buffer[$level][] = $record; return false === $this->bubble; diff --git a/tests/Monolog/Handler/ThresholdHandlerTest.php b/tests/Monolog/Handler/OverflowHandlerTest.php similarity index 88% rename from tests/Monolog/Handler/ThresholdHandlerTest.php rename to tests/Monolog/Handler/OverflowHandlerTest.php index 4ad555d12..c62f441ae 100644 --- a/tests/Monolog/Handler/ThresholdHandlerTest.php +++ b/tests/Monolog/Handler/OverflowHandlerTest.php @@ -16,14 +16,14 @@ /** * @author Kris Buist - * @covers \Monolog\Handler\ThresholdHandler + * @covers \Monolog\Handler\OverflowHandler */ -class ThresholdHandlerTest extends TestCase +class OverflowHandlerTest extends TestCase { public function testNotPassingRecordsBeneathLogLevel() { $testHandler = new TestHandler(); - $handler = new ThresholdHandler($testHandler, [], Logger::INFO); + $handler = new OverflowHandler($testHandler, [], Logger::INFO); $handler->handle($this->getRecord(Logger::DEBUG)); $this->assertFalse($testHandler->hasDebugRecords()); } @@ -31,7 +31,7 @@ public function testNotPassingRecordsBeneathLogLevel() public function testPassThroughWithoutThreshold() { $testHandler = new TestHandler(); - $handler = new ThresholdHandler($testHandler, [], Logger::INFO); + $handler = new OverflowHandler($testHandler, [], Logger::INFO); $handler->handle($this->getRecord(Logger::INFO, 'Info 1')); $handler->handle($this->getRecord(Logger::INFO, 'Info 2')); @@ -48,7 +48,7 @@ public function testPassThroughWithoutThreshold() public function testHoldingMessagesBeneathThreshold() { $testHandler = new TestHandler(); - $handler = new ThresholdHandler($testHandler, [Logger::INFO => 3]); + $handler = new OverflowHandler($testHandler, [Logger::INFO => 3]); $handler->handle($this->getRecord(Logger::DEBUG, 'debug 1')); $handler->handle($this->getRecord(Logger::DEBUG, 'debug 2')); @@ -74,7 +74,7 @@ public function testHoldingMessagesBeneathThreshold() public function testCombinedThresholds() { $testHandler = new TestHandler(); - $handler = new ThresholdHandler($testHandler, [Logger::INFO => 5, Logger::WARNING => 10]); + $handler = new OverflowHandler($testHandler, [Logger::INFO => 5, Logger::WARNING => 10]); $handler->handle($this->getRecord(Logger::DEBUG)); From 05319d9ab51ab330d924890b1d5af4ba5bcba7f7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 21 Nov 2018 11:22:47 +0100 Subject: [PATCH 069/498] Add tidelift to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7bab1f5f4..46ad7f1a0 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,10 @@ $log->error('Bar'); - [Extending Monolog](doc/04-extending.md) - [Log Record Structure](doc/message-structure.md) +## Support + +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=readme) + ## Third Party Packages Third party handlers, formatters and processors are From 75a563a28ffc2599e59af5af23a1a60fa98c1f97 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Wed, 21 Nov 2018 22:36:32 +0200 Subject: [PATCH 070/498] Update to phpunit 7 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0d1f4dbc1..a7b2aaf88 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "psr/log": "^1.0.1" }, "require-dev": { - "phpunit/phpunit": "^6.5", + "phpunit/phpunit": "^7.3", "graylog2/gelf-php": "^1.4.2", "sentry/sentry": "^1.9", "ruflin/elastica": ">=0.90 <3.0", From bff59f76428caf9bf685f62f5d9b7dc4cc750751 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Wed, 21 Nov 2018 22:58:31 +0200 Subject: [PATCH 071/498] Fix failing tests --- tests/Monolog/Processor/IntrospectionProcessorTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Monolog/Processor/IntrospectionProcessorTest.php b/tests/Monolog/Processor/IntrospectionProcessorTest.php index 5f5d9aea9..5dabbc51a 100644 --- a/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ b/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -90,8 +90,8 @@ public function testLevelEqual() $expected['extra'] = [ 'file' => null, 'line' => null, - 'class' => 'ReflectionMethod', - 'function' => 'invokeArgs', + 'class' => 'PHPUnit\Framework\TestCase', + 'function' => 'runTest', ]; $processor = new IntrospectionProcessor(Logger::CRITICAL); @@ -111,8 +111,8 @@ public function testLevelHigher() $expected['extra'] = [ 'file' => null, 'line' => null, - 'class' => 'ReflectionMethod', - 'function' => 'invokeArgs', + 'class' => 'PHPUnit\Framework\TestCase', + 'function' => 'runTest', ]; $processor = new IntrospectionProcessor(Logger::CRITICAL); From 2483a8d24f5b2d3c41f1125a9cbeddd58b7b1d06 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Wed, 21 Nov 2018 23:24:05 +0200 Subject: [PATCH 072/498] Fix tests for phpunit 7 --- tests/Monolog/Handler/RavenHandlerTest.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php index c80a57634..5ebfbcff9 100644 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ b/tests/Monolog/Handler/RavenHandlerTest.php @@ -273,20 +273,28 @@ public function testBreadcrumbs() $handler = $this->getHandler($ravenClient); $handler->addBreadcrumb($crumb1 = [ - 'level' => 'info', 'category' => 'test', + 'level' => 'info', 'message' => 'Step 1: user auth', ]); $handler->addBreadcrumb($crumb2 = [ - 'level' => 'info', 'category' => 'test', + 'level' => 'info', 'message' => 'Step 2: prepare user redirect', ]); $handler->handle($this->getRecord(Logger::ERROR, 'ERROR 💥')); - $this->assertArraySubset([$crumb1, $crumb2], $ravenClient->breadcrumbs->fetch()); - + $breadcrumbs = $ravenClient->breadcrumbs->fetch(); + $this->assertCount(2, $breadcrumbs); + $this->assertSame('test', $breadcrumbs[0]['category']); + $this->assertSame('info', $breadcrumbs[0]['level']); + $this->assertSame('Step 1: user auth', $breadcrumbs[0]['message']); + + $this->assertSame('test', $breadcrumbs[1]['category']); + $this->assertSame('info', $breadcrumbs[1]['level']); + $this->assertSame('Step 2: prepare user redirect', $breadcrumbs[1]['message']); + $handler->resetBreadcrumbs(); $handler->handle($this->getRecord(Logger::INFO, 'Hello!')); $this->assertEmpty($ravenClient->breadcrumbs->fetch()); From bb99e4c699bd5abe2609cace3c2daf0e45fdb673 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 29 Nov 2018 20:05:19 +0100 Subject: [PATCH 073/498] Tweak const visibility, refs #1228 --- src/Monolog/Formatter/GelfMessageFormatter.php | 2 +- src/Monolog/Formatter/LogmaticFormatter.php | 4 ++-- src/Monolog/Formatter/WildfireFormatter.php | 6 ++---- src/Monolog/Handler/ChromePHPHandler.php | 10 +++++----- src/Monolog/Handler/FirePHPHandler.php | 16 ++++++++-------- src/Monolog/Handler/FleepHookHandler.php | 10 +++++----- src/Monolog/Handler/HipChatHandler.php | 7 +------ src/Monolog/Handler/LogglyHandler.php | 12 ++++++------ src/Monolog/Handler/ProcessHandler.php | 4 ++-- src/Monolog/Handler/RotatingFileHandler.php | 2 +- src/Monolog/Handler/Slack/SlackRecord.php | 8 ++++---- src/Monolog/Handler/SqsHandler.php | 8 ++++---- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 4 ++-- .../Monolog/Formatter/WildfireFormatterTest.php | 2 +- tests/Monolog/Handler/ChromePHPHandlerTest.php | 6 +++--- tests/Monolog/Handler/FleepHookHandlerTest.php | 2 +- 16 files changed, 48 insertions(+), 55 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 28134809f..faf268d3e 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -22,7 +22,7 @@ */ class GelfMessageFormatter extends NormalizerFormatter { - public const DEFAULT_MAX_LENGTH = 32766; + protected const DEFAULT_MAX_LENGTH = 32766; /** * @var string the name of the system for the Gelf log message diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index 8f59b7323..b0451aba7 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -18,7 +18,7 @@ */ class LogmaticFormatter extends JsonFormatter { - public const MARKERS = ["sourcecode", "php"]; + protected const MARKERS = ["sourcecode", "php"]; /** * @var string @@ -59,7 +59,7 @@ public function format(array $record): string $record["appname"] = $this->appname; } - $record["@marker"] = self::MARKERS; + $record["@marker"] = static::MARKERS; return parent::format($record); } diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index e17fd3fdd..2d96739e3 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -22,8 +22,6 @@ */ class WildfireFormatter extends NormalizerFormatter { - public const TABLE = 'table'; - /** * Translates Monolog log levels to Wildfire levels. */ @@ -69,10 +67,10 @@ public function format(array $record): string $message = reset($message); } - if (isset($record['context'][self::TABLE])) { + if (isset($record['context']['table'])) { $type = 'TABLE'; $label = $record['channel'] .': '. $record['message']; - $message = $record['context'][self::TABLE]; + $message = $record['context']['table']; } else { $type = $this->logLevels[$record['level']]; $label = $record['channel']; diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index e832a8908..8f35e1991 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -29,17 +29,17 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Version of the extension */ - public const VERSION = '4.0'; + protected const VERSION = '4.0'; /** * Header name */ - public const HEADER_NAME = 'X-ChromeLogger-Data'; + protected const HEADER_NAME = 'X-ChromeLogger-Data'; /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ - public const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; + protected const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; protected static $initialized = false; @@ -164,7 +164,7 @@ protected function send(): void } if (trim($data) !== '') { - $this->sendHeader(self::HEADER_NAME, $data); + $this->sendHeader(static::HEADER_NAME, $data); } } @@ -187,6 +187,6 @@ protected function headersAccepted(): bool return false; } - return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']) === 1; + return preg_match(static::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']) === 1; } } diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 2ffe26898..c96386304 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -26,22 +26,22 @@ class FirePHPHandler extends AbstractProcessingHandler /** * WildFire JSON header message format */ - public const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; + protected const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; /** * FirePHP structure for parsing messages & their presentation */ - public const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; + protected const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; /** * Must reference a "known" plugin, otherwise headers won't display in FirePHP */ - public const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; + protected const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; /** * Header prefix for Wildfire to recognize & parse headers */ - public const HEADER_PREFIX = 'X-Wf'; + protected const HEADER_PREFIX = 'X-Wf'; /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet @@ -65,7 +65,7 @@ class FirePHPHandler extends AbstractProcessingHandler */ protected function createHeader(array $meta, string $message): array { - $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); + $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta)); return [$header => $message]; } @@ -103,9 +103,9 @@ protected function getInitHeaders(): array { // Initial payload consists of required headers for Wildfire return array_merge( - $this->createHeader(['Protocol', 1], self::PROTOCOL_URI), - $this->createHeader([1, 'Structure', 1], self::STRUCTURE_URI), - $this->createHeader([1, 'Plugin', 1], self::PLUGIN_URI) + $this->createHeader(['Protocol', 1], static::PROTOCOL_URI), + $this->createHeader([1, 'Structure', 1], static::STRUCTURE_URI), + $this->createHeader([1, 'Plugin', 1], static::PLUGIN_URI) ); } diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index db017a76d..5087009ff 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -25,9 +25,9 @@ */ class FleepHookHandler extends SocketHandler { - public const FLEEP_HOST = 'fleep.io'; + protected const FLEEP_HOST = 'fleep.io'; - public const FLEEP_HOOK_URI = '/hook/'; + protected const FLEEP_HOOK_URI = '/hook/'; /** * @var string Webhook token (specifies the conversation where logs are sent) @@ -53,7 +53,7 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble $this->token = $token; - $connectionString = 'ssl://' . self::FLEEP_HOST . ':443'; + $connectionString = 'ssl://' . static::FLEEP_HOST . ':443'; parent::__construct($connectionString, $level, $bubble); } @@ -93,8 +93,8 @@ protected function generateDataStream(array $record): string */ private function buildHeader(string $content): string { - $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; - $header .= "Host: " . self::FLEEP_HOST . "\r\n"; + $header = "POST " . static::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; + $header .= "Host: " . static::FLEEP_HOST . "\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index 8948e574b..65b698f66 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -29,15 +29,10 @@ */ class HipChatHandler extends SocketHandler { - /** - * The maximum allowed length for the name used in the "from" field. - */ - public const MAXIMUM_NAME_LENGTH = 15; - /** * The maximum allowed length for the message. */ - public const MAXIMUM_MESSAGE_LENGTH = 9500; + protected const MAXIMUM_MESSAGE_LENGTH = 9500; /** * @var string diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index f4359d196..ca37a0881 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -24,9 +24,9 @@ */ class LogglyHandler extends AbstractProcessingHandler { - public const HOST = 'logs-01.loggly.com'; - public const ENDPOINT_SINGLE = 'inputs'; - public const ENDPOINT_BATCH = 'bulk'; + protected const HOST = 'logs-01.loggly.com'; + protected const ENDPOINT_SINGLE = 'inputs'; + protected const ENDPOINT_BATCH = 'bulk'; protected $token; @@ -76,7 +76,7 @@ public function addTag($tag): self protected function write(array $record): void { - $this->send($record["formatted"], self::ENDPOINT_SINGLE); + $this->send($record["formatted"], static::ENDPOINT_SINGLE); } public function handleBatch(array $records): void @@ -88,13 +88,13 @@ public function handleBatch(array $records): void }); if ($records) { - $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH); + $this->send($this->getFormatter()->formatBatch($records), static::ENDPOINT_BATCH); } } protected function send(string $data, string $endpoint): void { - $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token); + $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); $headers = ['Content-Type: application/json']; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 6ced1f221..dd13ee4ef 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -51,7 +51,7 @@ class ProcessHandler extends AbstractProcessingHandler /** * @var array */ - public const DESCRIPTOR_SPEC = [ + protected const DESCRIPTOR_SPEC = [ 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from 1 => ['pipe', 'w'], // STDOUT is a pipe that the child will write to 2 => ['pipe', 'w'], // STDERR is a pipe to catch the any errors @@ -115,7 +115,7 @@ private function ensureProcessIsStarted(): void */ private function startProcess(): void { - $this->process = proc_open($this->command, self::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); + $this->process = proc_open($this->command, static::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); foreach ($this->pipes as $pipe) { stream_set_blocking($pipe, false); diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 24ffbb792..387c89ade 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -50,7 +50,7 @@ public function __construct(string $filename, int $maxFiles = 0, $level = Logger $this->maxFiles = (int) $maxFiles; $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; - $this->dateFormat = self::FILE_PER_DAY; + $this->dateFormat = static::FILE_PER_DAY; parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking); } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index a4e986781..f18fbe803 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -182,13 +182,13 @@ public function getAttachmentColor(int $level): string { switch (true) { case $level >= Logger::ERROR: - return self::COLOR_DANGER; + return static::COLOR_DANGER; case $level >= Logger::WARNING: - return self::COLOR_WARNING; + return static::COLOR_WARNING; case $level >= Logger::INFO: - return self::COLOR_GOOD; + return static::COLOR_GOOD; default: - return self::COLOR_DEFAULT; + return static::COLOR_DEFAULT; } } diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 8522dbdb1..2c89a33de 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -22,9 +22,9 @@ class SqsHandler extends AbstractProcessingHandler { /** 256 KB in bytes - maximum message size in SQS */ - public const MAX_MESSAGE_SIZE = 262144; + protected const MAX_MESSAGE_SIZE = 262144; /** 100 KB in bytes - head message size for new error log */ - public const HEAD_MESSAGE_SIZE = 102400; + protected const HEAD_MESSAGE_SIZE = 102400; /** @var SqsClient */ private $client; @@ -51,8 +51,8 @@ protected function write(array $record): void } $messageBody = $record['formatted']; - if (strlen($messageBody) >= self::MAX_MESSAGE_SIZE) { - $messageBody = substr($messageBody, 0, self::HEAD_MESSAGE_SIZE); + if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { + $messageBody = substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); } $this->client->sendMessage([ diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index d3e8f627b..ad7bb2d9b 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -13,7 +13,7 @@ class UdpSocket { - public const DATAGRAM_MAX_LENGTH = 65023; + protected const DATAGRAM_MAX_LENGTH = 65023; /** @var string */ protected $ip; @@ -52,7 +52,7 @@ protected function send(string $chunk): void protected function assembleMessage(string $line, string $header): string { - $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header); + $chunkSize = static::DATAGRAM_MAX_LENGTH - strlen($header); return $header . substr($line, 0, $chunkSize); } diff --git a/tests/Monolog/Formatter/WildfireFormatterTest.php b/tests/Monolog/Formatter/WildfireFormatterTest.php index 137494752..d06620203 100644 --- a/tests/Monolog/Formatter/WildfireFormatterTest.php +++ b/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -120,7 +120,7 @@ public function testTableFormat() 'level_name' => 'ERROR', 'channel' => 'table-channel', 'context' => [ - WildfireFormatter::TABLE => [ + 'table' => [ ['col1', 'col2', 'col3'], ['val1', 'val2', 'val3'], ['foo1', 'foo2', 'foo3'], diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index c17a35ac9..aff518471 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -39,7 +39,7 @@ public function testHeaders($agent) $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ - 'version' => ChromePHPHandler::VERSION, + 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ 'test', @@ -73,7 +73,7 @@ public function testHeadersOverflow() $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ - 'version' => ChromePHPHandler::VERSION, + 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ [ @@ -116,7 +116,7 @@ public function testConcurrentHandlers() $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ - 'version' => ChromePHPHandler::VERSION, + 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ 'test', diff --git a/tests/Monolog/Handler/FleepHookHandlerTest.php b/tests/Monolog/Handler/FleepHookHandlerTest.php index 11b5a6541..fe44e360a 100644 --- a/tests/Monolog/Handler/FleepHookHandlerTest.php +++ b/tests/Monolog/Handler/FleepHookHandlerTest.php @@ -80,6 +80,6 @@ public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays() */ public function testConnectionStringisConstructedCorrectly() { - $this->assertEquals('ssl://' . FleepHookHandler::FLEEP_HOST . ':443', $this->handler->getConnectionString()); + $this->assertEquals('ssl://fleep.io:443', $this->handler->getConnectionString()); } } From a335f6f1a564f43d2c63f2eeeca381e6c78f9006 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 30 Nov 2018 08:43:17 +0100 Subject: [PATCH 074/498] Fix tests for TestHandler reset support --- src/Monolog/Handler/TestHandler.php | 10 ++++++++- .../Handler/FingersCrossedHandlerTest.php | 1 + tests/Monolog/LoggerTest.php | 21 ++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 65ef12e34..478db0ac0 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -67,6 +67,7 @@ class TestHandler extends AbstractProcessingHandler { protected $records = array(); protected $recordsByLevel = array(); + private $skipReset = false; public function getRecords() { @@ -81,7 +82,14 @@ public function clear() public function reset() { - $this->clear(); + if (!$this->skipReset) { + $this->clear(); + } + } + + public function setSkipReset($skipReset) + { + $this->skipReset = $skipReset; } public function hasRecords($level) diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index 0ec36531a..5d51de1f8 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -61,6 +61,7 @@ public function testHandleStopsBufferingAfterTrigger() public function testHandleResetBufferingAfterReset() { $test = new TestHandler(); + $test->setSkipReset(true); $handler = new FingersCrossedHandler($test); $handler->handle($this->getRecord(Logger::WARNING)); $handler->handle($this->getRecord(Logger::DEBUG)); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 442e87dea..d96c7b1d8 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -620,6 +620,7 @@ public function testReset() $logger = new Logger('app'); $testHandler = new Handler\TestHandler(); + $testHandler->setSkipReset(true); $bufferHandler = new Handler\BufferHandler($testHandler); $groupHandler = new Handler\GroupHandler(array($bufferHandler)); $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler); @@ -649,7 +650,7 @@ public function testReset() $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); }; - $logger->debug('debug'); + $logger->debug('debug1'); $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasDebugRecords()); @@ -657,16 +658,16 @@ public function testReset() $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); - $logger->debug('debug'); - $logger->error('error'); + $logger->debug('debug2'); + $logger->error('error2'); $logger->reset(); $assertBuffersEmpty(); - $this->assertTrue($testHandler->hasDebugRecords()); - $this->assertTrue($testHandler->hasErrorRecords()); + $this->assertTrue($testHandler->hasRecordThatContains('debug2', Logger::DEBUG)); + $this->assertTrue($testHandler->hasRecordThatContains('error2', Logger::ERROR)); $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); - $logger->info('info'); + $logger->info('info3'); $this->assertNotEmpty($getProperty($fingersCrossedHandler, 'buffer')); $assertBufferOfBufferHandlerEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); @@ -677,13 +678,13 @@ public function testReset() $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); - $logger->notice('notice'); - $logger->emergency('emergency'); + $logger->notice('notice4'); + $logger->emergency('emergency4'); $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); - $this->assertTrue($testHandler->hasNoticeRecords()); - $this->assertTrue($testHandler->hasEmergencyRecords()); + $this->assertTrue($testHandler->hasRecordThatContains('notice4', Logger::NOTICE)); + $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Logger::EMERGENCY)); $this->assertNotSame($uid1, $processorUid1->getUid()); $this->assertNotSame($uid2, $processorUid2->getUid()); } From daed05c3e5ed303ce3423a8afbb54e590e795fdb Mon Sep 17 00:00:00 2001 From: Mponos George Date: Tue, 4 Dec 2018 11:30:41 +0200 Subject: [PATCH 075/498] Enable JSON encode pretty print (#1236) --- src/Monolog/Formatter/NormalizerFormatter.php | 20 +++++++++- tests/Monolog/Formatter/JsonFormatterTest.php | 30 ++++++++++++++ .../Formatter/NormalizerFormatterTest.php | 39 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index e3b5ebc6c..ea5a2a65a 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -11,9 +11,9 @@ namespace Monolog\Formatter; -use Throwable; use Monolog\DateTimeImmutable; use Monolog\Utils; +use Throwable; /** * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets @@ -28,6 +28,8 @@ class NormalizerFormatter implements FormatterInterface protected $maxNormalizeDepth = 9; protected $maxNormalizeItemCount = 1000; + private $jsonEncodeOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION; + /** * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format */ @@ -89,6 +91,20 @@ public function setMaxNormalizeItemCount(int $maxNormalizeItemCount): self return $this; } + /** + * Enables `json_encode` pretty print. + */ + public function setJsonPrettyPrint(bool $enable): self + { + if ($enable) { + $this->jsonEncodeOptions |= JSON_PRETTY_PRINT; + } else { + $this->jsonEncodeOptions ^= JSON_PRETTY_PRINT; + } + + return $this; + } + /** * @param mixed $data * @return int|bool|string|null|array @@ -247,7 +263,7 @@ protected function toJson($data, bool $ignoreErrors = false) */ private function jsonEncode($data) { - return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION); + return json_encode($data, $this->jsonEncodeOptions); } /** diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 7ccf5bc84..2208393cc 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -46,6 +46,36 @@ public function testFormat() $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } + /** + * @covers Monolog\Formatter\JsonFormatter::format + */ + public function testFormatWithPrettyPrint() + { + $formatter = new JsonFormatter(); + $formatter->setJsonPrettyPrint(true); + $record = $this->getRecord(); + $record['context'] = $record['extra'] = new \stdClass; + $this->assertEquals(json_encode($record, JSON_PRETTY_PRINT)."\n", $formatter->format($record)); + + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); + $formatter->setJsonPrettyPrint(true); + $record = $this->getRecord(); + $this->assertEquals( + '{ + "message": "test", + "context": {}, + "level": 300, + "level_name": "WARNING", + "channel": "test", + "datetime": "'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'", + "extra": {} +}', $formatter->format($record)); + + $formatter->setJsonPrettyPrint(false); + $record = $this->getRecord(); + $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); + } + /** * @covers Monolog\Formatter\JsonFormatter::formatBatch * @covers Monolog\Formatter\JsonFormatter::formatBatchJson diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 01bf36d2b..8f3499a50 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -418,6 +418,45 @@ public function testExceptionTraceWithArgs() ); } + /** + * This test was copied from `testExceptionTraceWithArgs` in order to ensure that pretty prints works + */ + public function testPrettyPrint() + { + try { + // This will contain $resource and $wrappedResource as arguments in the trace item + $resource = fopen('php://memory', 'rw+'); + fwrite($resource, 'test_resource'); + $wrappedResource = new TestFooNorm; + $wrappedResource->foo = $resource; + // Just do something stupid with a resource/wrapped resource as argument + $arr = [$wrappedResource, $resource]; + // modifying the array inside throws a "usort(): Array was modified by the user comparison function" + usort($arr, function ($a, $b) { + throw new \ErrorException('Foo'); + }); + } catch (\Throwable $e) { + } + + $formatter = new NormalizerFormatter(); + $record = ['context' => ['exception' => $e]]; + $formatter->setJsonPrettyPrint(true); + $result = $formatter->format($record); + + $this->assertSame( + '{ + "function": "Monolog\\\\Formatter\\\\{closure}", + "class": "Monolog\\\\Formatter\\\\NormalizerFormatterTest", + "type": "->", + "args": [ + "[object] (Monolog\\\\Formatter\\\\TestFooNorm)", + "[resource(stream)]" + ] +}', + $result['context']['exception']['trace'][0] + ); + } + /** * @param NormalizerFormatter $formatter * @param \Throwable $exception From 1d821e6e40d031f8f352c1e0f5f95d8e382a9757 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 8 Dec 2018 17:51:12 +0100 Subject: [PATCH 076/498] Update changelog/upgrade files, fixes #1232 --- CHANGELOG.md | 22 ++++++++++++++++++++++ UPGRADE.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e55909c84..d3fb85e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +### 2.0.0-beta1 (2018-12-08) + + * BC Break: This is a major release, see [UPGRADE.md] for details if you are coming from a 1.x release + * BC Break: PHP 7.1 is now the minimum required PHP version. + * BC Break: Quite a few interface changes, only relevant if you implemented your own handlers/processors/formatters + * BC Break: Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) methods as well as `emerg`, `crit`, `err` and `warn` + * BC Break: The record timezone is now set per Logger instance and not statically anymore + * BC Break: There is no more default handler configured on empty Logger instances + * BC Break: Various handler-specific breaks, see [UPGRADE.md] for details + * Added scalar type hints and return hints in all the places it was possible. Switched strict_types on for more reliability. + * Added DateTimeImmutable support, all record datetime are now immutable, and will toString/json serialize with the correct date format, including microseconds (unless disabled) + * Added timezone and microseconds to the default date format + * Added SendGridHandler to use the SendGrid API to send emails + * Added LogmaticHandler to use the Logmatic.io API to store log records + * Added SqsHandler to send log records to an AWS SQS queue + * Added NoopHandler which is similar to the NullHandle but does not prevent the bubbling of log records to handlers further down the configuration, useful for temporarily disabling a handler in configuration files + * Added ProcessHandler to write log output to the STDIN of a given process + * Added HostnameProcessor that adds the machine's hostname to log records + * Added a `$dateFormat` option to the PsrLogMessageProcessor which lets you format DateTime instances nicely + * Added support for the PHP 7.x `mongodb` extension in the MongoDBHandler + * Fixed many minor issues in various handlers, and probably added a few regressions too + ### 1.24.0 (2018-11-05) * BC Notice: If you are extending any of the Monolog's Formatters' `normalize` method, make sure you add the new `$depth = 0` argument to your function signature to avoid strict PHP warnings. diff --git a/UPGRADE.md b/UPGRADE.md index 81b6e90b2..9949fa180 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,12 +1,22 @@ ### 2.0.0 -- The timezone is now set per Logger instance and not statically, either - via ->setTimezone or passed in the constructor. Calls to Logger::setTimezone - should be converted. +- `Monolog\Logger::API` can be used to distinguish between a Monolog `1` and `2` + install of Monolog when writing integration code. - Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) methods as well as `emerg`, `crit`, `err` and `warn`. +- DateTime are not formatted with a timezone and microseconds (unless disabled). + Various formatters and log output might be affected, which may mess with log parsing + in some cases. + +- The `datetime` in every record array is now a DateTimeImmutable, not that you + should have been modifying these anyway. + +- The timezone is now set per Logger instance and not statically, either + via ->setTimezone or passed in the constructor. Calls to Logger::setTimezone + should be converted. + - `HandlerInterface` has been split off and two new interfaces now exist for more granular controls: `ProcessableHandlerInterface` and `FormattableHandlerInterface`. Handlers not extending `AbstractHandler` @@ -14,4 +24,36 @@ - `HandlerInterface` now requires the `close` method to be implemented. This only impacts you if you implement the interface yourself, but you can extend - the new `Monolog\Handler\Handler` base class. + the new `Monolog\Handler\Handler` base class too. + +- There is no more default handler configured on empty Logger instances, if + you were relying on that you will not get any output anymore, make sure to + configure the handler you need. + +#### LogglyFormatter + +- The records' `datetime` is not sent anymore. Only `timestamp` is sent to Loggly. + +#### AmqpHandler + +- Log levels are not shortened to 4 characters anymore. e.g. a warning record + will be sent using the `warning.channel` routing key instead of `warn.channel` + as in 1.x. +- The exchange name does not default to 'log' anymore, and it is completely ignored + now for the AMQP extension users. Only PHPAmqpLib uses it if provided. + +#### RotatingFileHandler + +- The file name format must now contain `{date}` and the date format must be set + to one of the predefined FILE_PER_* constants to avoid issues with file rotation. + See `setFilenameFormat`. + +#### LogstashFormatter + +- Removed Logstash V0 support +- Context/extra prefix has been removed in favor of letting users configure the exact key being sent +- Context/extra data are now sent as an object instead of single keys + +#### HipChatHandler + +- Removed HipChat API v1 support From 0ad73a526f4b5e67312e94fb7f60c1bdefc284b9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 8 Dec 2018 18:16:32 +0100 Subject: [PATCH 077/498] CS fixes --- src/Monolog/Formatter/ElasticaFormatter.php | 2 +- src/Monolog/Formatter/ElasticsearchFormatter.php | 2 +- src/Monolog/Handler/ElasticaHandler.php | 1 + src/Monolog/Handler/ElasticsearchHandler.php | 3 ++- src/Monolog/Handler/ZendMonitorHandler.php | 4 ++-- src/Monolog/Processor/ProcessorInterface.php | 2 +- src/Monolog/ResettableInterface.php | 2 +- src/Monolog/SignalHandler.php | 2 +- src/Monolog/Utils.php | 2 +- tests/Monolog/Formatter/JsonFormatterTest.php | 4 +++- tests/Monolog/Handler/ElasticaHandlerTest.php | 1 + tests/Monolog/Handler/ElasticsearchHandlerTest.php | 6 +++--- tests/Monolog/Handler/InsightOpsHandlerTest.php | 4 ++-- tests/Monolog/Handler/RavenHandlerTest.php | 2 +- tests/Monolog/LoggerTest.php | 2 +- tests/Monolog/SignalHandlerTest.php | 7 +++---- 16 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 128e07ab8..c6f3c8e12 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -65,7 +65,7 @@ public function getType(): string /** * Convert a log message into an Elastica Document - * @param array $record + * @param array $record * @return Document */ protected function getDocument(array $record): Document diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 1667f2cc7..84affef35 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -32,7 +32,7 @@ class ElasticsearchFormatter extends NormalizerFormatter /** * @param string $index Elasticsearch index name - * @param string $type Elasticsearch record type + * @param string $type Elasticsearch record type */ public function __construct(string $index, string $type) { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 4a444b858..78a8d1ea7 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -81,6 +81,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface if ($formatter instanceof ElasticaFormatter) { return parent::setFormatter($formatter); } + throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); } diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 7d5d3a877..6d0021b9e 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -89,6 +89,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface if ($formatter instanceof ElasticsearchFormatter) { return parent::setFormatter($formatter); } + throw new InvalidArgumentException('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); } @@ -122,7 +123,7 @@ public function handleBatch(array $records): void /** * Use Elasticsearch bulk API to send list of documents * - * @param array $records + * @param array $records * @throws \RuntimeException */ protected function bulkSend(array $records): void diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 0ced70792..236472ee3 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -39,8 +39,8 @@ class ZendMonitorHandler extends AbstractProcessingHandler ]; /** - * @param string|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. + * @param string|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. * @throws MissingExtensionException */ public function __construct($level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index 7e64d4dfa..c58639b82 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -1,4 +1,4 @@ -format('Y-m-d\TH:i:s.uP').'", "extra": {} -}', $formatter->format($record)); +}', + $formatter->format($record) + ); $formatter->setJsonPrettyPrint(false); $record = $this->getRecord(); diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index fb64e6574..423adbe6a 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -183,6 +183,7 @@ public function testHandleIntegration() $client = new Client(); $handler = new ElasticaHandler($client, $this->options); + try { $handler->handleBatch([$msg]); } catch (\RuntimeException $e) { diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 943a67eed..7895332be 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -80,7 +80,7 @@ public function testHandle() ], ], $data, - ] + ], ]; // setup ES client mock @@ -229,7 +229,7 @@ public function testHandleIntegration() /** * Return last created document id from ES response * - * @param array $info Elasticsearch last request info + * @param array $info Elasticsearch last request info * @return string|null */ protected function getCreatedDocId(array $info) @@ -255,7 +255,7 @@ protected function getDocSourceFromElastic(Client $client, $index, $type, $docum $params = [ 'index' => $index, 'type' => $type, - 'id' => $documentId + 'id' => $documentId, ]; $data = $client->get($params); diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index 209858aee..db6b1e051 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -12,9 +12,9 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; - use Monolog\Logger; +use Monolog\Logger; - /** +/** * @author Robert Kaufmann III * @author Gabriel Machado */ diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php index 5ebfbcff9..cff5f5436 100644 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ b/tests/Monolog/Handler/RavenHandlerTest.php @@ -294,7 +294,7 @@ public function testBreadcrumbs() $this->assertSame('test', $breadcrumbs[1]['category']); $this->assertSame('info', $breadcrumbs[1]['level']); $this->assertSame('Step 2: prepare user redirect', $breadcrumbs[1]['message']); - + $handler->resetBreadcrumbs(); $handler->handle($this->getRecord(Logger::INFO, 'Hello!')); $this->assertEmpty($ravenClient->breadcrumbs->fetch()); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 7dce79ba0..f94882db0 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -666,7 +666,7 @@ public function testReset() $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) { $that->assertEmpty($getProperty($bufferHandler, 'buffer')); }; - $assertBuffersEmpty = function() use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) { + $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) { $assertBufferOfBufferHandlerEmpty(); $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); }; diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index c2c145bb2..5169705a1 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -1,4 +1,4 @@ -signalHandlers[$signo] = pcntl_signal_get_handler($signo); } else { @@ -284,5 +284,4 @@ public function asyncProvider() array(true, true, 1, 1), ); } - } From 4215c238c832746fa3c9558959290b1bb8214f20 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 8 Dec 2018 18:23:31 +0100 Subject: [PATCH 078/498] Fix upgrade link --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0b906b82..4a2f8e043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,13 @@ ### 2.0.0-beta1 (2018-12-08) - * BC Break: This is a major release, see [UPGRADE.md] for details if you are coming from a 1.x release + * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release * BC Break: PHP 7.1 is now the minimum required PHP version. * BC Break: Quite a few interface changes, only relevant if you implemented your own handlers/processors/formatters * BC Break: Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) methods as well as `emerg`, `crit`, `err` and `warn` * BC Break: The record timezone is now set per Logger instance and not statically anymore * BC Break: There is no more default handler configured on empty Logger instances * BC Break: ElasticSearchHandler renamed to ElasticaHandler - * BC Break: Various handler-specific breaks, see [UPGRADE.md] for details + * BC Break: Various handler-specific breaks, see [UPGRADE.md](UPGRADE.md) for details * Added scalar type hints and return hints in all the places it was possible. Switched strict_types on for more reliability. * Added DateTimeImmutable support, all record datetime are now immutable, and will toString/json serialize with the correct date format, including microseconds (unless disabled) * Added timezone and microseconds to the default date format From 04fe4cdec15f3c8d45641b29fc3a2c93d2984d68 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 21:04:20 +0200 Subject: [PATCH 079/498] Make CURL util final and internal --- src/Monolog/Handler/Curl/Util.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index f1d0c17d9..5a8abef3f 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -11,7 +11,12 @@ namespace Monolog\Handler\Curl; -class Util +/** + * This class is marked as internal and it is not under the BC promise of the package. + * + * @internal + */ +final class Util { private static $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, From 61021a535d4c2143070f3f2d0655f32e87fcee0f Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 21:32:59 +0200 Subject: [PATCH 080/498] Added missing bubble property --- src/Monolog/Handler/FingersCrossedHandler.php | 1 + src/Monolog/Handler/GroupHandler.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index aba1b1d7c..11f3b5057 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -43,6 +43,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $buffer = []; protected $stopBuffering; protected $passthruLevel; + protected $bubble; /** * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 3aa1201c3..0d0c9c9a8 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -24,6 +24,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset use ProcessableHandlerTrait; protected $handlers; + protected $bubble; /** * @param HandlerInterface[] $handlers Array of Handlers. From 73f263923797f42550124889e54f5ae7945a7f48 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 21:46:17 +0200 Subject: [PATCH 081/498] Docblock fixes --- src/Monolog/Handler/ProcessHandler.php | 4 ++-- src/Monolog/Processor/WebProcessor.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index dd13ee4ef..36e30b87a 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -39,7 +39,7 @@ class ProcessHandler extends AbstractProcessingHandler private $command; /** - * @var ?string + * @var string|null */ private $cwd; @@ -62,7 +62,7 @@ class ProcessHandler extends AbstractProcessingHandler * especially if you do not use the $cwd parameter. * @param string|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. - * @param ?string $cwd "Current working directory" (CWD) for the process to be executed in. + * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in. * @throws \InvalidArgumentException */ public function __construct(string $command, $level = Logger::DEBUG, bool $bubble = true, ?string $cwd = null) diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 6b0a8d426..7b95b0e18 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -39,8 +39,8 @@ class WebProcessor implements ProcessorInterface ]; /** - * @param array|\ArrayAccess $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer + * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data + * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer */ public function __construct($serverData = null, array $extraFields = null) { From 5c8e68b6dec63a531f7a8fbfd307b7f32132d4db Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 21:57:40 +0200 Subject: [PATCH 082/498] Fix mockobjects docblocks in tests --- tests/Monolog/Handler/PHPConsoleHandlerTest.php | 8 ++++---- tests/Monolog/Handler/RollbarHandlerTest.php | 2 +- tests/Monolog/Handler/SwiftMailerHandlerTest.php | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 0836b9958..9c479da6f 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -19,7 +19,7 @@ use PhpConsole\Dispatcher\Debug as DebugDispatcher; use PhpConsole\Dispatcher\Errors as ErrorDispatcher; use PhpConsole\Handler as VendorPhpConsoleHandler; -use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit\Framework\MockObject\MockObject; /** * @covers Monolog\Handler\PHPConsoleHandler @@ -27,11 +27,11 @@ */ class PHPConsoleHandlerTest extends TestCase { - /** @var Connector|PHPUnit_Framework_MockObject_MockObject */ + /** @var Connector|MockObject */ protected $connector; - /** @var DebugDispatcher|PHPUnit_Framework_MockObject_MockObject */ + /** @var DebugDispatcher|MockObject */ protected $debugDispatcher; - /** @var ErrorDispatcher|PHPUnit_Framework_MockObject_MockObject */ + /** @var ErrorDispatcher|MockObject */ protected $errorDispatcher; protected function setUp() diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 67a0eb683..5d8c1fc29 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -14,7 +14,7 @@ use Exception; use Monolog\Test\TestCase; use Monolog\Logger; -use PHPUnit_Framework_MockObject_MockObject as MockObject; +use PHPUnit\Framework\MockObject\MockObject; use Rollbar\RollbarLogger; /** diff --git a/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/tests/Monolog/Handler/SwiftMailerHandlerTest.php index 3c77127b4..d8ff39bc7 100644 --- a/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ b/tests/Monolog/Handler/SwiftMailerHandlerTest.php @@ -13,10 +13,11 @@ use Monolog\Logger; use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; class SwiftMailerHandlerTest extends TestCase { - /** @var \Swift_Mailer|\PHPUnit_Framework_MockObject_MockObject */ + /** @var \Swift_Mailer|MockObject */ private $mailer; public function setUp() From 045f8218dddbdd20e906ac6f289b09c7e5d4c9a6 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 22:15:55 +0200 Subject: [PATCH 083/498] Docblock fixes --- src/Monolog/Handler/ProcessableHandlerInterface.php | 2 ++ src/Monolog/Handler/PsrHandler.php | 2 +- src/Monolog/Handler/RavenHandler.php | 2 +- src/Monolog/Handler/RotatingFileHandler.php | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 27077c62d..2c9557b40 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Processor\ProcessorInterface; + /** * Interface to describe loggers that have processors * diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index e0c67dcd5..cba96a556 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -34,7 +34,7 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface protected $logger; /** - * @var FormatterInterface + * @var FormatterInterface|null */ protected $formatter; diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 6836c488f..6c3c32bf7 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -55,7 +55,7 @@ class RavenHandler extends AbstractProcessingHandler protected $ravenClient; /** - * @var LineFormatter The formatter to use for the logs generated via handleBatch() + * @var FormatterInterface The formatter to use for the logs generated via handleBatch() */ protected $batchFormatter; diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 387c89ade..3e2810ba7 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -47,7 +47,7 @@ class RotatingFileHandler extends StreamHandler public function __construct(string $filename, int $maxFiles = 0, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { $this->filename = $filename; - $this->maxFiles = (int) $maxFiles; + $this->maxFiles = $maxFiles; $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; $this->dateFormat = static::FILE_PER_DAY; From e2a3122e10c5bffe76e4c6cc6f41d46355effc66 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 22:17:36 +0200 Subject: [PATCH 084/498] Parameter formatter was never set.. would cause fatal --- src/Monolog/Handler/HandlerWrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index dfbc16d19..3f2c7a1a7 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -119,7 +119,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface public function getFormatter(): FormatterInterface { if ($this->handler instanceof FormattableHandlerInterface) { - return $this->handler->getFormatter($formatter); + return $this->handler->getFormatter(); } throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); From 966c2f64b351e117930998832301ba6f06da0d95 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 22:22:04 +0200 Subject: [PATCH 085/498] Remove not needed cast --- src/Monolog/Handler/BufferHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index a73a9778b..d9505b792 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -44,7 +44,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $le { parent::__construct($level, $bubble); $this->handler = $handler; - $this->bufferLimit = (int) $bufferLimit; + $this->bufferLimit = $bufferLimit; $this->flushOnOverflow = $flushOnOverflow; } From 790ff7fd1dd832b24d856eb75c24e7b199a1d6b1 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 22:31:46 +0200 Subject: [PATCH 086/498] Docblock fixes --- src/Monolog/Formatter/HtmlFormatter.php | 3 ++- src/Monolog/Formatter/LineFormatter.php | 8 ++++---- src/Monolog/Formatter/LogstashFormatter.php | 8 ++++---- src/Monolog/Formatter/NormalizerFormatter.php | 2 +- src/Monolog/Handler/Slack/SlackRecord.php | 4 ++-- src/Monolog/Processor/PsrLogMessageProcessor.php | 6 +++--- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 0f8db9a7b..7489d6485 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -37,7 +37,7 @@ class HtmlFormatter extends NormalizerFormatter ]; /** - * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ public function __construct(?string $dateFormat = null) { @@ -50,6 +50,7 @@ public function __construct(?string $dateFormat = null) * @param string $th Row header content * @param string $td Row standard cell content * @param bool $escapeTd false if td content must not be html escaped + * @return string */ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): string { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 3b4824cd6..64f57bece 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -31,10 +31,10 @@ class LineFormatter extends NormalizerFormatter protected $includeStacktraces; /** - * @param ?string $format The format of the message - * @param ?string $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 + * @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) { diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index 6404acf0c..563d97dbb 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -42,10 +42,10 @@ class LogstashFormatter extends NormalizerFormatter protected $contextKey; /** - * @param string $applicationName the application that sends the data, used as the "type" field of logstash - * @param ?string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine - * @param string $extraKey the key for extra keys inside logstash "fields", defaults to extra - * @param string $contextKey the key for context keys inside logstash "fields", defaults to context + * @param string $applicationName The application that sends the data, used as the "type" field of logstash + * @param string|null $systemName The system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine + * @param string $extraKey The key for extra keys inside logstash "fields", defaults to extra + * @param string $contextKey The key for context keys inside logstash "fields", defaults to context */ public function __construct(string $applicationName, ?string $systemName = null, string $extraKey = 'extra', string $contextKey = 'context') { diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index ea5a2a65a..4bd13b197 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -31,7 +31,7 @@ class NormalizerFormatter implements FormatterInterface private $jsonEncodeOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION; /** - * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ public function __construct(?string $dateFormat = null) { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index f18fbe803..e2f664926 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -35,13 +35,13 @@ class SlackRecord /** * Slack channel (encoded ID or name) - * @var ?string + * @var string|null */ private $channel; /** * Name of a bot - * @var ?string + * @var string|null */ private $username; diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 65eccc6f2..909fc4fdc 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -24,15 +24,15 @@ class PsrLogMessageProcessor implements ProcessorInterface { public const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; - /** @var ?string */ + /** @var string|null */ private $dateFormat; /** @var bool */ private $removeUsedContextFields; /** - * @param ?string $dateFormat The format of the timestamp: one supported by DateTime::format - * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format + * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset */ public function __construct(?string $dateFormat = null, bool $removeUsedContextFields = false) { From 208381d43ec1500b79e5475550992765fb2fc8cb Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 22:48:48 +0200 Subject: [PATCH 087/498] added more docblock fixes --- src/Monolog/Processor/GitProcessor.php | 3 +++ src/Monolog/Processor/IntrospectionProcessor.php | 3 +++ src/Monolog/Processor/MercurialProcessor.php | 3 +++ src/Monolog/Processor/UidProcessor.php | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index b72944c74..1367ee6fc 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -24,6 +24,9 @@ class GitProcessor implements ProcessorInterface private $level; private static $cache; + /** + * @param string|int $level The minimum logging level at which this Processor will be triggered + */ public function __construct($level = Logger::DEBUG) { $this->level = Logger::toMonologLevel($level); diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 691d573c3..c0cc014e4 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -37,6 +37,9 @@ class IntrospectionProcessor implements ProcessorInterface 'call_user_func_array', ]; + /** + * @param string|int $level The minimum logging level at which this Processor will be triggered + */ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { $this->level = Logger::toMonologLevel($level); diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index b7fcd7842..d50f71386 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -23,6 +23,9 @@ class MercurialProcessor implements ProcessorInterface private $level; private static $cache; + /** + * @param string|int $level The minimum logging level at which this Processor will be triggered + */ public function __construct($level = Logger::DEBUG) { $this->level = Logger::toMonologLevel($level); diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 1089e690a..b8e8f60c0 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -24,7 +24,7 @@ class UidProcessor implements ProcessorInterface, ResettableInterface public function __construct(int $length = 7) { - if (!is_int($length) || $length > 32 || $length < 1) { + if ($length > 32 || $length < 1) { throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); } From ee221811100f14dafbffffef2fa77c5b207fa679 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 23:22:56 +0200 Subject: [PATCH 088/498] Mark Utils of getclass as final --- src/Monolog/Utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index ed2d45bb1..14b76661b 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -11,7 +11,7 @@ namespace Monolog; -class Utils +final class Utils { /** * @internal From b373504d87951e925b8f88f935a7ee248e7b0f44 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 9 Dec 2018 23:32:39 +0200 Subject: [PATCH 089/498] Add docblock to ResettableInterface --- src/Monolog/ResettableInterface.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php index 081081f75..772c1d8e0 100644 --- a/src/Monolog/ResettableInterface.php +++ b/src/Monolog/ResettableInterface.php @@ -27,5 +27,10 @@ */ interface ResettableInterface { + /** + * Function that executes the resetting of a Processor + * + * @return void + */ public function reset(); } From befa91fa36f99186759172b80e62c91579e4f6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Mon, 10 Dec 2018 11:13:24 +0100 Subject: [PATCH 090/498] Enhancement: Keep packages sorted in composer.json (#1248) --- composer.json | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 2545c1648..76ff33ad2 100644 --- a/composer.json +++ b/composer.json @@ -17,20 +17,20 @@ "psr/log": "^1.0.1" }, "require-dev": { - "phpunit/phpunit": "^7.3", - "graylog2/gelf-php": "^1.4.2", - "sentry/sentry": "^1.9", - "ruflin/elastica": ">=0.90 <3.0", - "doctrine/couchdb": "~1.0@dev", "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^6.0", + "graylog2/gelf-php": "^1.4.2", + "jakub-onderka/php-parallel-lint": "^0.9", "php-amqplib/php-amqplib": "~2.4", - "swiftmailer/swiftmailer": "^5.3|^6.0", "php-console/php-console": "^3.1.3", - "jakub-onderka/php-parallel-lint": "^0.9", - "predis/predis": "^1.1", "phpspec/prophecy": "^1.6.1", - "elasticsearch/elasticsearch": "^6.0", - "rollbar/rollbar": "^1.3" + "phpunit/phpunit": "^7.3", + "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^1.9", + "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", @@ -65,5 +65,8 @@ "parallel-lint . --exclude vendor", "phpunit" ] + }, + "config": { + "sort-packages": true } } From b46967e74ca067c059f2753a586ca981cac8ee39 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Mon, 10 Dec 2018 12:13:43 +0200 Subject: [PATCH 091/498] Add 7.3 to v1 also (#1246) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 07bad617a..9adcf749f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 - nightly matrix: From b7c0e7142df01a66bc86c12e1ef66e04d24fa120 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 10 Dec 2018 11:49:48 +0100 Subject: [PATCH 092/498] Bump phpunit minimum version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 76ff33ad2..868b378eb 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^7.3", + "phpunit/phpunit": "^7.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", From a774caa99f7a82493894843db30cfefcc785b4b8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 10 Dec 2018 11:53:00 +0100 Subject: [PATCH 093/498] Remove invalid ext from travis build --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0bc3dc928..a3a715a80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,6 @@ matrix: before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "extension = mongodb.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - - echo "extension = amqp.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - if [ "$deps" == "low" ]; then composer update --prefer-dist --prefer-lowest --prefer-stable; fi - if [ "$deps" != "low" ]; then composer install --prefer-dist; fi From c99682466f3cee2e8358fef08e7203b0cdd261cc Mon Sep 17 00:00:00 2001 From: George Mponos Date: Mon, 10 Dec 2018 21:07:13 +0200 Subject: [PATCH 094/498] Fix docblocks --- src/Monolog/Formatter/HtmlFormatter.php | 3 +-- src/Monolog/Processor/UidProcessor.php | 5 +---- src/Monolog/ResettableInterface.php | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 7489d6485..3c4e84798 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -50,7 +50,6 @@ public function __construct(?string $dateFormat = null) * @param string $th Row header content * @param string $td Row standard cell content * @param bool $escapeTd false if td content must not be html escaped - * @return string */ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): string { @@ -69,7 +68,7 @@ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): * @param int $level Error level * @return string */ - protected function addTitle(string $title, int $level) + protected function addTitle(string $title, int $level): string { $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8'); diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index b8e8f60c0..0c97ab6cd 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -38,9 +38,6 @@ public function __invoke(array $record): array return $record; } - /** - * @return string - */ public function getUid(): string { return $this->uid; @@ -51,7 +48,7 @@ public function reset() $this->uid = $this->generateUid(strlen($this->uid)); } - private function generateUid($length) + private function generateUid(int $length): string { return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); } diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php index 772c1d8e0..2c5fd7851 100644 --- a/src/Monolog/ResettableInterface.php +++ b/src/Monolog/ResettableInterface.php @@ -28,8 +28,6 @@ interface ResettableInterface { /** - * Function that executes the resetting of a Processor - * * @return void */ public function reset(); From ef83e0647e685cc71b99e08cd88563b90958fb81 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Mon, 10 Dec 2018 22:27:29 +0200 Subject: [PATCH 095/498] Fix a wrong check on Error Handler and removed an old bug --- src/Monolog/ErrorHandler.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 7447f2798..3d386606e 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -58,9 +58,6 @@ public function __construct(LoggerInterface $logger) */ public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self { - //Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929 - class_exists('\\Psr\\Log\\LogLevel', true); - $handler = new static($logger); if ($errorLevelMap !== false) { $handler->registerErrorHandler($errorLevelMap); @@ -150,6 +147,7 @@ protected function defaultErrorLevelMap(): array /** * @private + * @param \Exception $e */ public function handleException($e) { @@ -171,7 +169,7 @@ public function handleException($e) call_user_func($this->previousExceptionHandler, $e); } - if (!headers_sent() && ini_get('display_errors') === 0) { + if (!headers_sent() && !ini_get('display_errors')) { http_response_code(500); } From ee26edfd8c5cc49780fa331f16b23fb0acbf59b1 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Mon, 10 Dec 2018 23:38:46 +0200 Subject: [PATCH 096/498] fix more docblocks --- src/Monolog/Handler/PushoverHandler.php | 2 +- src/Monolog/Logger.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 3d07e41f2..2689de1c6 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -67,7 +67,7 @@ class PushoverHandler extends SocketHandler /** * @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 $title Title sent to the Pushover API + * @param string|null $title Title sent to the Pushover API * @param string|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 * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index d6eeb9ea7..6d48c135c 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -143,7 +143,7 @@ class Logger implements LoggerInterface, ResettableInterface * @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 $timezone Optional timezone, if not provided date_default_timezone_get() will be used + * @param DateTimeZone|null $timezone Optional timezone, if not provided date_default_timezone_get() will be used */ public function __construct(string $name, array $handlers = [], array $processors = [], ?DateTimeZone $timezone = null) { From 67c33c347e29c48a2d36dfe15afe9094b9540e3e Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Tue, 11 Dec 2018 03:45:54 -0500 Subject: [PATCH 097/498] Fix the property for restarting syscalls (#1251) Credit goes to @gmponos for reporting the problem. --- src/Monolog/SignalHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index d5907805a..d87018fed 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -96,7 +96,7 @@ public function handleSignal($signo, array $siginfo = null) if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { - $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; + $restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true; pcntl_signal($signo, SIG_DFL, $restartSyscalls); pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); posix_kill(posix_getpid(), $signo); From 66c292f4a49057a3aad088a274e26bf8f7be8521 Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Tue, 11 Dec 2018 04:04:23 -0500 Subject: [PATCH 098/498] Use more PHP 7.1 in the SignalHandler --- src/Monolog/SignalHandler.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 918dc97dc..6cad7ed90 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -60,29 +60,23 @@ public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool return $this; } - public function handleSignal($signo, array $siginfo = null) + public function handleSignal($signo, array $siginfo = null): void { static $signals = []; if (!$signals && extension_loaded('pcntl')) { $pcntl = new ReflectionExtension('pcntl'); - $constants = $pcntl->getConstants(); - if (!$constants) { - // HHVM 3.24.2 returns an empty array. - $constants = get_defined_constants(true); - $constants = $constants['Core']; - } - foreach ($constants 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; } } - unset($constants); } - $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; - $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; - $context = isset($siginfo) ? $siginfo : []; + $level = $this->signalLevelMap[$signo] ?? LogLevel::CRITICAL; + $signal = $signals[$signo] ?? $signo; + $context = $siginfo ?? []; $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); if (!isset($this->previousSignalHandler[$signo])) { From db54e30a8682902301eff42cd8e830c67406789a Mon Sep 17 00:00:00 2001 From: Robert Gust-Bardon Date: Tue, 11 Dec 2018 04:05:15 -0500 Subject: [PATCH 099/498] Fix the property for restarting syscalls (#1251) Credit goes to @gmponos for reporting the problem. --- src/Monolog/SignalHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 6cad7ed90..4a79fe663 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -87,7 +87,7 @@ public function handleSignal($signo, array $siginfo = null): void if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill') ) { - $restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true; + $restartSyscalls = $this->signalRestartSyscalls[$signo] ?? true; pcntl_signal($signo, SIG_DFL, $restartSyscalls); pcntl_sigprocmask(SIG_UNBLOCK, [$signo], $oldset); posix_kill(posix_getpid(), $signo); From e855ad8923872150f79f4674638d988f4d32389a Mon Sep 17 00:00:00 2001 From: George Mponos Date: Tue, 11 Dec 2018 17:01:05 +0200 Subject: [PATCH 100/498] Remove not needed checks for PHP version --- src/Monolog/Handler/NewRelicHandler.php | 2 +- tests/Monolog/LoggerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 6d7eb9bb4..5efd4e6a3 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -89,7 +89,7 @@ protected function write(array $record): void unset($record['formatted']['context']['transaction_name']); } - if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { newrelic_notice_error($record['message'], $record['context']['exception']); unset($record['formatted']['context']['exception']); } else { diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index f94882db0..c3c5e94ae 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -573,7 +573,7 @@ public function useMicrosecondTimestampsProvider() // this has a very small chance of a false negative (1/10^6) 'with microseconds' => [true, 'assertNotSame', 'Y-m-d\TH:i:s.uP'], // php 7.1 always includes microseconds, so we keep them in, but we format the datetime without - 'without microseconds' => [false, PHP_VERSION_ID >= 70100 ? 'assertNotSame' : 'assertSame', 'Y-m-d\TH:i:sP'], + 'without microseconds' => [false, 'assertNotSame', 'Y-m-d\TH:i:sP'], ]; } From fb48686cccdc2f1c114ec1d55eb9e7d2a37d3831 Mon Sep 17 00:00:00 2001 From: Jos Ahrens Date: Thu, 13 Dec 2018 09:52:31 +0100 Subject: [PATCH 101/498] Update README link of Python Logbook The old URL is no longer in use, serving "Logbook's documentation is maintained elsewhere." and a redirect. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d75694465..a578eb228 100644 --- a/README.md +++ b/README.md @@ -90,5 +90,5 @@ Monolog is licensed under the MIT License - see the `LICENSE` file for details ### Acknowledgements -This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/) +This library is heavily inspired by Python's [Logbook](https://logbook.readthedocs.io/en/stable/) library, although most concepts have been adjusted to fit to the PHP world. From 4e7dab4ffedcaddc95d3d3af05f91207d124faaf Mon Sep 17 00:00:00 2001 From: George Mponos Date: Thu, 13 Dec 2018 19:47:06 +0200 Subject: [PATCH 102/498] Deprecate slackbot handler --- src/Monolog/Handler/SlackbotHandler.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SlackbotHandler.php b/src/Monolog/Handler/SlackbotHandler.php index baead5252..d3352ea0f 100644 --- a/src/Monolog/Handler/SlackbotHandler.php +++ b/src/Monolog/Handler/SlackbotHandler.php @@ -16,8 +16,11 @@ /** * Sends notifications through Slack's Slackbot * - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot + * @author Haralan Dobrev + * @see https://slack.com/apps/A0F81R8ET-slackbot + * @deprecated According to Slack the API used on this handler it is deprecated. + * Therefore this handler will be removed on 2.x + * Slack suggests to use webhooks instead. Please contact slack for more information. */ class SlackbotHandler extends AbstractProcessingHandler { @@ -48,6 +51,7 @@ class SlackbotHandler extends AbstractProcessingHandler */ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true) { + @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED); parent::__construct($level, $bubble); $this->slackTeam = $slackTeam; From 546708f23a676c65a5cf4739b6bb61815139543e Mon Sep 17 00:00:00 2001 From: andyexeter Date: Sat, 15 Dec 2018 13:55:51 +0000 Subject: [PATCH 103/498] Add SoapFault details to formatted exception --- src/Monolog/Formatter/LineFormatter.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 64f57bece..8a7b390b4 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -170,7 +170,22 @@ protected function replaceNewlines(string $str): string private function formatException(\Throwable $e): string { - $str = '[object] (' . Utils::getClass($e) . '(code: ' . $e->getCode() . '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; + $str = '[object] (' . Utils::getClass($e) . '(code: ' . $e->getCode(); + if ($e instanceof \SoapFault) { + if (isset($e->faultcode)) { + $str .= ' faultcode: ' . $e->faultcode; + } + + if (isset($e->faultactor)) { + $str .= ' faultactor: ' . $e->faultactor; + } + + if (isset($e->detail)) { + $str .= ' detail: ' . $e->detail; + } + } + $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; + if ($this->includeStacktraces) { $str .= "\n[stacktrace]\n" . $e->getTraceAsString() . "\n"; } From 897fca0d9b6d012bd6e09d286f033a27c4cf72ed Mon Sep 17 00:00:00 2001 From: andyexeter Date: Sat, 15 Dec 2018 13:56:25 +0000 Subject: [PATCH 104/498] Add SoapFault exception formatting test --- tests/Monolog/Formatter/LineFormatterTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index e19cde1e4..1b115b9f9 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -173,6 +173,27 @@ public function testDefFormatWithPreviousException() $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).')\n[previous exception] [object] (LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__ - 12).')"} []'."\n", $message); } + public function testDefFormatWithSoapFaultException() + { + if (!class_exists('SoapFault')) { + $this->markTestSkipped('Requires the soap extension'); + } + + $formatter = new LineFormatter(null, 'Y-m-d'); + $message = $formatter->format([ + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => ['exception' => new \SoapFault('foo', 'bar', 'hello', 'world')], + 'datetime' => new \DateTimeImmutable, + 'extra' => [], + 'message' => 'foobar', + ]); + + $path = str_replace('\\/', '/', json_encode(__FILE__)); + + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: world): bar at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); + } + public function testBatchFormat() { $formatter = new LineFormatter(null, 'Y-m-d'); From ee350961da80d27c2ecbf87a468520e61b7dcd5c Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 16 Dec 2018 23:46:26 +0200 Subject: [PATCH 105/498] Remove assertInternalType that it is deprecated --- tests/Monolog/Formatter/ElasticsearchFormatterTest.php | 2 +- tests/Monolog/Formatter/MongoDBFormatterTest.php | 6 +++--- tests/Monolog/Handler/NativeMailerHandlerTest.php | 4 ++-- tests/Monolog/Handler/RavenHandlerTest.php | 2 +- tests/Monolog/Handler/Slack/SlackRecordTest.php | 4 ++-- tests/Monolog/Handler/SocketHandlerTest.php | 5 +++-- tests/Monolog/Processor/HostnameProcessorTest.php | 2 +- tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php | 2 +- tests/Monolog/Processor/MemoryUsageProcessorTest.php | 2 +- tests/Monolog/Processor/ProcessIdProcessorTest.php | 2 +- 10 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php index d68c8f110..2cd868992 100644 --- a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php @@ -45,7 +45,7 @@ public function testFormat() // Format log message $formatter = new ElasticsearchFormatter('my_index', 'doc_type'); $doc = $formatter->format($msg); - $this->assertInternalType('array', $doc); + $this->assertIsArray($doc); // Record parameters $this->assertEquals('my_index', $doc['_index']); diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 8759c0163..f9494f3d3 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -122,9 +122,9 @@ public function testRecursiveFormat() $this->assertCount(5, $formattedRecord['context']['except']); $this->assertEquals('exception message', $formattedRecord['context']['except']['message']); $this->assertEquals(987, $formattedRecord['context']['except']['code']); - $this->assertInternalType('string', $formattedRecord['context']['except']['file']); - $this->assertInternalType('integer', $formattedRecord['context']['except']['code']); - $this->assertInternalType('string', $formattedRecord['context']['except']['trace']); + $this->assertIsString($formattedRecord['context']['except']['file']); + $this->assertIsInt($formattedRecord['context']['except']['code']); + $this->assertIsString($formattedRecord['context']['except']['trace']); $this->assertEquals('Exception', $formattedRecord['context']['except']['class']); } diff --git a/tests/Monolog/Handler/NativeMailerHandlerTest.php b/tests/Monolog/Handler/NativeMailerHandlerTest.php index d4aef95ec..9e17cd3fb 100644 --- a/tests/Monolog/Handler/NativeMailerHandlerTest.php +++ b/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -87,7 +87,7 @@ public function testSend() // non-empty batch $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); $this->assertNotEmpty($GLOBALS['mail']); - $this->assertInternalType('array', $GLOBALS['mail']); + $this->assertIsArray($GLOBALS['mail']); $this->assertArrayHasKey('0', $GLOBALS['mail']); $params = $GLOBALS['mail'][0]; $this->assertCount(5, $params); @@ -103,7 +103,7 @@ public function testMessageSubjectFormatting() $mailer = new NativeMailerHandler('to@example.org', 'Alert: %level_name% %message%', 'from@example.org'); $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); $this->assertNotEmpty($GLOBALS['mail']); - $this->assertInternalType('array', $GLOBALS['mail']); + $this->assertIsArray($GLOBALS['mail']); $this->assertArrayHasKey('0', $GLOBALS['mail']); $params = $GLOBALS['mail'][0]; $this->assertCount(5, $params); diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php index cff5f5436..491d84ac2 100644 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ b/tests/Monolog/Handler/RavenHandlerTest.php @@ -138,7 +138,7 @@ public function testUserContext() // check to see if its reset $handler->handle($recordWithNoContext); - $this->assertInternalType('array', $ravenClient->context->user); + $this->assertIsArray($ravenClient->context->user); $this->assertSame('test_user_id', $ravenClient->context->user['id']); // handle with null context diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index eaa15571d..9f23c7ce5 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -157,7 +157,7 @@ public function testAddsOneAttachment() $this->assertArrayHasKey('attachments', $data); $this->assertArrayHasKey(0, $data['attachments']); - $this->assertInternalType('array', $data['attachments'][0]); + $this->assertIsArray($data['attachments'][0]); } public function testTextEqualsMessageIfNoAttachment() @@ -362,7 +362,7 @@ public function testContextHasException() $record = $this->getRecord(Logger::CRITICAL, 'This is a critical message.', array('exception' => new \Exception())); $slackRecord = new SlackRecord(null, null, true, null, false, true); $data = $slackRecord->getSlackData($record); - $this->assertInternalType('string', $data['attachments'][0]['fields'][1]['value']); + $this->assertIsString($data['attachments'][0]['fields'][1]['value']); } public function testExcludeExtraAndContextFields() diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 5f76048cc..a003cb7f3 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Logger; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Pablo de Leon Belloc @@ -20,7 +21,7 @@ class SocketHandlerTest extends TestCase { /** - * @var Monolog\Handler\SocketHandler + * @var \Monolog\Handler\SocketHandler|MockObject */ private $handler; @@ -247,7 +248,7 @@ public function testClose() { $this->setMockHandler(); $this->writeRecord('Hello world'); - $this->assertInternalType('resource', $this->res); + $this->assertIsResource($this->res); $this->handler->close(); $this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler"); } diff --git a/tests/Monolog/Processor/HostnameProcessorTest.php b/tests/Monolog/Processor/HostnameProcessorTest.php index 1659851b0..c5745751e 100644 --- a/tests/Monolog/Processor/HostnameProcessorTest.php +++ b/tests/Monolog/Processor/HostnameProcessorTest.php @@ -23,7 +23,7 @@ public function testProcessor() $processor = new HostnameProcessor(); $record = $processor($this->getRecord()); $this->assertArrayHasKey('hostname', $record['extra']); - $this->assertInternalType('string', $record['extra']['hostname']); + $this->assertIsString($record['extra']['hostname']); $this->assertNotEmpty($record['extra']['hostname']); $this->assertEquals(gethostname(), $record['extra']['hostname']); } diff --git a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php index cd8052763..bf9cbedb2 100644 --- a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php @@ -36,7 +36,7 @@ public function testProcessorWithoutFormatting() $processor = new MemoryPeakUsageProcessor(true, false); $record = $processor($this->getRecord()); $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertInternalType('int', $record['extra']['memory_peak_usage']); + $this->assertIsInt($record['extra']['memory_peak_usage']); $this->assertGreaterThan(0, $record['extra']['memory_peak_usage']); } } diff --git a/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/tests/Monolog/Processor/MemoryUsageProcessorTest.php index a4809cbea..d16439baa 100644 --- a/tests/Monolog/Processor/MemoryUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryUsageProcessorTest.php @@ -36,7 +36,7 @@ public function testProcessorWithoutFormatting() $processor = new MemoryUsageProcessor(true, false); $record = $processor($this->getRecord()); $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertInternalType('int', $record['extra']['memory_usage']); + $this->assertIsInt($record['extra']['memory_usage']); $this->assertGreaterThan(0, $record['extra']['memory_usage']); } } diff --git a/tests/Monolog/Processor/ProcessIdProcessorTest.php b/tests/Monolog/Processor/ProcessIdProcessorTest.php index ec39e8eec..0b3446faa 100644 --- a/tests/Monolog/Processor/ProcessIdProcessorTest.php +++ b/tests/Monolog/Processor/ProcessIdProcessorTest.php @@ -23,7 +23,7 @@ public function testProcessor() $processor = new ProcessIdProcessor(); $record = $processor($this->getRecord()); $this->assertArrayHasKey('process_id', $record['extra']); - $this->assertInternalType('int', $record['extra']['process_id']); + $this->assertIsInt($record['extra']['process_id']); $this->assertGreaterThan(0, $record['extra']['process_id']); $this->assertEquals(getmypid(), $record['extra']['process_id']); } From 655b4284d80fcfa71f4d5f9c2c972b72be8b81b4 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Wed, 26 Dec 2018 16:38:36 +0200 Subject: [PATCH 106/498] Delete slackbot handler --- src/Monolog/Handler/SlackbotHandler.php | 82 ------------------- tests/Monolog/Handler/SlackbotHandlerTest.php | 47 ----------- 2 files changed, 129 deletions(-) delete mode 100644 src/Monolog/Handler/SlackbotHandler.php delete mode 100644 tests/Monolog/Handler/SlackbotHandlerTest.php diff --git a/src/Monolog/Handler/SlackbotHandler.php b/src/Monolog/Handler/SlackbotHandler.php deleted file mode 100644 index 10a273254..000000000 --- a/src/Monolog/Handler/SlackbotHandler.php +++ /dev/null @@ -1,82 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; - -/** - * Sends notifications through Slack's Slackbot - * - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot - * @deprecated According to Slack the API used on this handler it is deprecated. - * Therefore this handler will be removed on 2.x - * Slack suggests to use webhooks instead. Please contact slack for more information. - */ -class SlackbotHandler extends AbstractProcessingHandler -{ - /** - * The slug of the Slack team - * @var string - */ - private $slackTeam; - - /** - * Slackbot token - * @var string - */ - private $token; - - /** - * Slack channel name - * @var string - */ - private $channel; - - /** - * @param string $slackTeam Slack team slug - * @param string $token Slackbot token - * @param string $channel Slack channel (encoded ID or name) - * @param string|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(string $slackTeam, string $token, string $channel, $level = Logger::CRITICAL, bool $bubble = true) - { - @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED); - parent::__construct($level, $bubble); - - $this->slackTeam = $slackTeam; - $this->token = $token; - $this->channel = $channel; - } - - /** - * {@inheritdoc} - */ - protected function write(array $record): void - { - $slackbotUrl = sprintf( - 'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s', - $this->slackTeam, - $this->token, - $this->channel - ); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $slackbotUrl); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $record['message']); - - Curl\Util::execute($ch); - } -} diff --git a/tests/Monolog/Handler/SlackbotHandlerTest.php b/tests/Monolog/Handler/SlackbotHandlerTest.php deleted file mode 100644 index 340c4c65e..000000000 --- a/tests/Monolog/Handler/SlackbotHandlerTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Test\TestCase; -use Monolog\Logger; - -/** - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot - * @coversDefaultClass Monolog\Handler\SlackbotHandler - */ -class SlackbotHandlerTest extends TestCase -{ - /** - * @covers ::__construct - */ - public function testConstructorMinimal() - { - $handler = new SlackbotHandler('test-team', 'test-token', 'test-channel'); - $this->assertInstanceOf('Monolog\Handler\AbstractProcessingHandler', $handler); - } - - /** - * @covers ::__construct - */ - public function testConstructorFull() - { - $handler = new SlackbotHandler( - 'test-team', - 'test-token', - 'test-channel', - Logger::DEBUG, - false - ); - $this->assertInstanceOf('Monolog\Handler\AbstractProcessingHandler', $handler); - } -} From 1adbed5c9272b683f0c246c9518b5689bfcad318 Mon Sep 17 00:00:00 2001 From: GreYY <> Date: Fri, 25 Jan 2019 13:06:55 +0200 Subject: [PATCH 107/498] Fix create duplicate records in *GroupHandler --- src/Monolog/Handler/GroupHandler.php | 3 ++- src/Monolog/Handler/WhatFailureGroupHandler.php | 3 ++- tests/Monolog/Handler/GroupHandlerTest.php | 7 +++++++ tests/Monolog/Handler/WhatFailureGroupHandlerTest.php | 7 +++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 28e5c5648..0d461f9c7 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -80,8 +80,9 @@ public function handleBatch(array $records) $processed = array(); foreach ($records as $record) { foreach ($this->processors as $processor) { - $processed[] = call_user_func($processor, $record); + $record = call_user_func($processor, $record); } + $processed[] = $record; } $records = $processed; } diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 6bc4671c7..7d7622a39 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -52,8 +52,9 @@ public function handleBatch(array $records) $processed = array(); foreach ($records as $record) { foreach ($this->processors as $processor) { - $processed[] = call_user_func($processor, $record); + $record = call_user_func($processor, $record); } + $processed[] = $record; } $records = $processed; } diff --git a/tests/Monolog/Handler/GroupHandlerTest.php b/tests/Monolog/Handler/GroupHandlerTest.php index a1b86176d..e20be64bf 100644 --- a/tests/Monolog/Handler/GroupHandlerTest.php +++ b/tests/Monolog/Handler/GroupHandlerTest.php @@ -99,6 +99,11 @@ public function testHandleBatchUsesProcessors() return $record; }); + $handler->pushProcessor(function ($record) { + $record['extra']['foo2'] = true; + + return $record; + }); $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); @@ -107,6 +112,8 @@ public function testHandleBatchUsesProcessors() $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); $this->assertTrue($records[1]['extra']['foo']); + $this->assertTrue($records[0]['extra']['foo2']); + $this->assertTrue($records[1]['extra']['foo2']); } } } diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 0594a232b..1eb3f55f8 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -99,6 +99,11 @@ public function testHandleBatchUsesProcessors() return $record; }); + $handler->pushProcessor(function ($record) { + $record['extra']['foo2'] = true; + + return $record; + }); $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); @@ -107,6 +112,8 @@ public function testHandleBatchUsesProcessors() $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); $this->assertTrue($records[1]['extra']['foo']); + $this->assertTrue($records[0]['extra']['foo2']); + $this->assertTrue($records[1]['extra']['foo2']); } } From 0b76b0b36aeaf6ae6822e5e87b47248fd473170f Mon Sep 17 00:00:00 2001 From: The Digital Orchard Date: Fri, 25 Jan 2019 17:44:25 -0800 Subject: [PATCH 108/498] avoid function call when not needed; use single variable instead of two --- src/Monolog/Processor/MemoryPeakUsageProcessor.php | 9 ++++++--- src/Monolog/Processor/MemoryUsageProcessor.php | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index b6f8acc19..a1eef61ab 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -21,10 +21,13 @@ class MemoryPeakUsageProcessor extends MemoryProcessor { public function __invoke(array $record): array { - $bytes = memory_get_peak_usage($this->realUsage); - $formatted = $this->formatBytes($bytes); + $usage = memory_get_peak_usage($this->realUsage); - $record['extra']['memory_peak_usage'] = $formatted; + if ($this->useFormatting) { + $usage = $this->formatBytes($usage); + } + + $record['extra']['memory_peak_usage'] = $usage; return $record; } diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index 31c9396ff..653c76d10 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -21,10 +21,13 @@ class MemoryUsageProcessor extends MemoryProcessor { public function __invoke(array $record): array { - $bytes = memory_get_usage($this->realUsage); - $formatted = $this->formatBytes($bytes); + $usage = memory_get_usage($this->realUsage); - $record['extra']['memory_usage'] = $formatted; + if ($this->useFormatting) { + $usage = $this->formatBytes($usage); + } + + $record['extra']['memory_usage'] = $usage; return $record; } From b351406bb3b4fb571bbffe62e3a5cec68e8043f0 Mon Sep 17 00:00:00 2001 From: Carl Vuorinen Date: Mon, 4 Feb 2019 09:07:35 +0200 Subject: [PATCH 109/498] Check file was opened successfully before trying to read/write Fixes #1286 --- src/Monolog/Handler/DeduplicationHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 0c2a3cbdf..864c29ae0 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -137,6 +137,11 @@ private function collectLogs(): void } $handle = fopen($this->deduplicationStore, 'rw+'); + + if (!$handle) { + throw new \RuntimeException('Failed to open file for reading and writing: ' . $this->deduplicationStore); + } + flock($handle, LOCK_EX); $validLogs = []; From de90f03fa5dff96a154ee1e4c769b38c12cbc216 Mon Sep 17 00:00:00 2001 From: Joey Gallegos Date: Wed, 13 Feb 2019 23:32:46 -0600 Subject: [PATCH 110/498] Bump year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 713dc045c..5170c6df4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2018 Jordi Boggiano +Copyright (c) 2011-2019 Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 95ff458b443e21e6c2677674587a4649ce338f8b Mon Sep 17 00:00:00 2001 From: Gregory Goijaerts Date: Thu, 21 Feb 2019 10:53:12 +0100 Subject: [PATCH 111/498] Replace logrotate link with alternative page The current link no longer exists --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 169001102..01715028c 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -18,7 +18,7 @@ - [_StreamHandler_](../src/Monolog/Handler/StreamHandler.php): Logs records into any PHP stream, use this for log files. - [_RotatingFileHandler_](../src/Monolog/Handler/RotatingFileHandler.php): Logs records to a file and creates one logfile per day. It will also delete files older than `$maxFiles`. You should use - [logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile + [logrotate](https://linux.die.net/man/8/logrotate) for high profile setups though, this is just meant as a quick and dirty solution. - [_SyslogHandler_](../src/Monolog/Handler/SyslogHandler.php): Logs records to the syslog. - [_ErrorLogHandler_](../src/Monolog/Handler/ErrorLogHandler.php): Logs records to PHP's From 8b879fe6fae3f83c42c0342b2e4ac6b8be1f6fca Mon Sep 17 00:00:00 2001 From: Shrey Puranik Date: Fri, 8 Mar 2019 15:15:58 +0000 Subject: [PATCH 112/498] Readability updates Fixes docblock, minor formatting tweak for readbility, and adds a new docblock for getSlackData record. --- src/Monolog/Handler/Slack/SlackRecord.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index e2f664926..ccade4c92 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -85,8 +85,16 @@ class SlackRecord */ private $normalizerFormatter; - public function __construct(?string $channel = null, ?string $username = null, bool $useAttachment = true, ?string $userIcon = null, bool $useShortAttachment = false, bool $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) - { + public function __construct( + ?string $channel = null, + ?string $username = null, + bool $useAttachment = true, + ?string $userIcon = null, + bool $useShortAttachment = false, + bool $includeContextAndExtra = false, + array $excludeFields = array(), + FormatterInterface $formatter = null + ) { $this->channel = $channel; $this->username = $username; $this->userIcon = $userIcon !== null ? trim($userIcon, ':') : null; @@ -101,6 +109,10 @@ public function __construct(?string $channel = null, ?string $username = null, b } } + /** + * Returns required data in format that Slack + * is expecting. + */ public function getSlackData(array $record): array { $dataArray = array(); @@ -175,7 +187,7 @@ public function getSlackData(array $record): array } /** - * Returned a Slack message attachment color associated with + * Returns a Slack message attachment color associated with * provided level. */ public function getAttachmentColor(int $level): string From c08ef35508a4b7b89b3a90744ee74e2f41710dc7 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Wed, 13 Mar 2019 13:38:28 +0100 Subject: [PATCH 113/498] Test on php 7.4 only --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a3a715a80..6a0989745 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: - 7.1 - 7.2 - 7.3 - - nightly + - 7.4snapshot cache: directories: From 1985d1ee0c136ca17fe9afa53ec23f3700e98bba Mon Sep 17 00:00:00 2001 From: Jochen Staerk Date: Thu, 21 Mar 2019 16:58:24 +0100 Subject: [PATCH 114/498] support two digit years With this change you can use two digit years, i.e. $fileHandler->setFilenameFormat('{date}_{filename}', 'y-m-d'); for 19-03-21 --- src/Monolog/Handler/RotatingFileHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 3e2810ba7..c1ff25b56 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -81,7 +81,7 @@ public function reset() public function setFilenameFormat(string $filenameFormat, string $dateFormat): self { - if (!preg_match('{^Y(([/_.-]?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") '. From 80e8b0d575b169d2065d95992f77bf29e272fd8d Mon Sep 17 00:00:00 2001 From: Dominik Kukacka Date: Fri, 22 Mar 2019 22:40:59 +0100 Subject: [PATCH 115/498] Add possibility to use RFC3164 for udp syslog --- src/Monolog/Handler/SyslogUdpHandler.php | 37 +++++++++++++++---- .../Monolog/Handler/SyslogUdpHandlerTest.php | 30 +++++++++++++++ 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index e14b378ce..4dfd5f5ec 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -18,11 +18,21 @@ * A Handler for logging to a remote syslogd server. * * @author Jesper Skovgaard Nielsen + * @author Dominik Kukacka */ class SyslogUdpHandler extends AbstractSyslogHandler { + const RFC3164 = 0; + const RFC5424 = 1; + + private $dateFormats = array( + self::RFC3164 => 'M d H:i:s', + self::RFC5424 => \DateTime::RFC3339, + ); + protected $socket; protected $ident; + protected $rfc; /** * @param string $host @@ -31,12 +41,14 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @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 * @param string $ident Program name or tag for each log message. + * @param int $rfc RFC to format the message for. */ - public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php') + public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424) { parent::__construct($facility, $level, $bubble); $this->ident = $ident; + $this->rfc = $rfc; $this->socket = new UdpSocket($host, $port ?: 514); } @@ -67,7 +79,7 @@ private function splitMessageIntoLines($message) } /** - * Make common syslog header (see rfc5424) + * Make common syslog header (see rfc5424 or rfc3164) */ protected function makeCommonSyslogHeader($severity) { @@ -81,16 +93,25 @@ protected function makeCommonSyslogHeader($severity) $hostname = '-'; } - return "<$priority>1 " . - $this->getDateTime() . " " . - $hostname . " " . - $this->ident . " " . - $pid . " - - "; + $date = $this->getDateTime(); + + if ($this->rfc === self::RFC3164) { + return "<$priority>" . + $date . " " . + $hostname . " " . + $this->ident . "[" . $pid . "]: "; + } else { + return "<$priority>1 " . + $date . " " . + $hostname . " " . + $this->ident . " " . + $pid . " - - "; + } } protected function getDateTime() { - return date(\DateTime::RFC3339); + return date($this->dateFormats[$this->rfc]); } /** diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 7ee8a9853..a1ea9d03e 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -69,6 +69,36 @@ public function testSplitWorksOnEmptyMsg() $handler->handle($this->getRecordWithMessage(null)); } + + public function testRfc() + { + $time = 'Mar 22 21:16:47'; + $pid = getmypid(); + $host = gethostname(); + + $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') + ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", null, null, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) + ->setMethods(array('getDateTime')) + ->getMock(); + + $handler->method('getDateTime') + ->willReturn($time); + + $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); + + $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol')); + $socket->expects($this->at(0)) + ->method('write') + ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: "); + $socket->expects($this->at(1)) + ->method('write') + ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: "); + + $handler->setSocket($socket); + + $handler->handle($this->getRecordWithMessage("hej\nlol")); + } + protected function getRecordWithMessage($msg) { return array('message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => array(), 'channel' => 'lol'); From 93eca5639d667b1c88052d4da5337e87d8d2641d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Fla=C3=B1o?= Date: Wed, 27 Mar 2019 13:02:40 -0300 Subject: [PATCH 116/498] Enable adding/removing options to json_encode() Sometimes you want to add some options. In my case I wanted to encode the data using JSON_FORCE_OBJECT, but there was no way to do it --- src/Monolog/Formatter/NormalizerFormatter.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 4bd13b197..93e77bd5b 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -375,4 +375,14 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } + + protected function addJsonEncodeOption($option) + { + $this->jsonEncodeOptions |= $option; + } + + protected function removeJsonEncodeOption($option) + { + $this->jsonEncodeOptions ^= $option; + } } From b95129216de208be0deb069bacfc7316d1ea66d8 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 4 Apr 2019 13:46:58 +0200 Subject: [PATCH 117/498] Dont use more than 2000 chars for slack attachments field --- src/Monolog/Handler/Slack/SlackRecord.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index e2f664926..e6c481e41 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -223,7 +223,7 @@ public function setFormatter(FormatterInterface $formatter): self private function generateAttachmentField(string $title, $value): array { $value = is_array($value) - ? sprintf('```%s```', $this->stringify($value)) + ? sprintf('```%s```', substr($this->stringify($value), 0, 1990)) : $value; return array( From b40fec3b7e6e6758a911608d937ecf98b95924d9 Mon Sep 17 00:00:00 2001 From: Alex Calinescu Date: Wed, 3 Apr 2019 12:13:47 +0300 Subject: [PATCH 118/498] Check for JsonSerializable in normalizeException --- src/Monolog/Formatter/NormalizerFormatter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 4bd13b197..7b32f28b3 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -182,6 +182,10 @@ protected function normalize($data, int $depth = 0) */ protected function normalizeException(Throwable $e, int $depth = 0) { + if ($e instanceof \JsonSerializable) { + return (array) $e->jsonSerialize(); + } + $data = [ 'class' => Utils::getClass($e), 'message' => $e->getMessage(), From c5cacaa121f403f955999268850802dd860e3e4f Mon Sep 17 00:00:00 2001 From: Ondrej Exner Date: Wed, 17 Apr 2019 16:06:03 +0200 Subject: [PATCH 119/498] fix ProcessorInterface --- src/Monolog/Processor/ProcessorInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index c58639b82..9e2ded19b 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -19,7 +19,7 @@ interface ProcessorInterface { /** - * @return array The processed records + * @return array The processed record */ - public function __invoke(array $records); + public function __invoke(array $record); } From 2b0c2dbb2601868c80c9e1f9ce8d6e929cdf4145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Lange?= Date: Mon, 22 Apr 2019 15:30:20 +0200 Subject: [PATCH 120/498] Adding curl sharing to fix #1313 This change caches the curl handlers for every endoint and reuses them. This makes the logglyHandler two to three times faster. --- src/Monolog/Handler/LogglyHandler.php | 53 +++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index ca37a0881..c8befc28d 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; +use function array_key_exists; /** * Sends errors to Loggly. @@ -28,6 +29,13 @@ class LogglyHandler extends AbstractProcessingHandler protected const ENDPOINT_SINGLE = 'inputs'; protected const ENDPOINT_BATCH = 'bulk'; + /** + * Caches the curl handlers for every given endpoint. + * + * @var array + */ + protected $curlHandlers = []; + protected $token; protected $tag = []; @@ -50,6 +58,42 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble parent::__construct($level, $bubble); } + /** + * Loads and returns the shared curl handler for the given endpoint. + * + * @param string $endpoint + * + * @return resource + */ + protected function getCurlHandler(string $endpoint) + { + if (!array_key_exists($endpoint, $this->curlHandlers)) { + $this->curlHandlers[$endpoint] = $this->loadCurlHandler($endpoint); + } + + return $this->curlHandlers[$endpoint]; + } + + /** + * Starts a fresh curl session for the given endpoint and returns its handler. + * + * @param string $endpoint + * + * @return resource + */ + private function loadCurlHandler(string $endpoint) + { + $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + return $ch; + } + /** * @param string[]|string $tag */ @@ -94,7 +138,7 @@ public function handleBatch(array $records): void protected function send(string $data, string $endpoint): void { - $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); + $ch = $this->getCurlHandler($endpoint); $headers = ['Content-Type: application/json']; @@ -102,15 +146,10 @@ protected function send(string $data, string $endpoint): void $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag); } - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - Curl\Util::execute($ch); + Curl\Util::execute($ch, 5, false); } protected function getDefaultFormatter(): FormatterInterface From 8d24527a0296f5e1609dbfcf46c64eed61a971e6 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Tue, 23 Apr 2019 10:15:50 +1200 Subject: [PATCH 121/498] Add SilverStripe as a framework integration to readme SilverStripe ^4.0 and future 5.x ship with monolog out of the box --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6fcbfa891..f1d32412a 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Equip Framework](https://github.com/equip/framework) comes out of the box with Monolog. - [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. - [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. +- [SilverStripe 4](https://www.silverstripe.org/) come out of the box with Monolog. ### Author From 10dcbc90f4a819c77c6b955d4b8ef07d6cb510ea Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 17 May 2019 11:38:07 +1200 Subject: [PATCH 122/498] Fix grammar error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1d32412a..ac31a8575 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Equip Framework](https://github.com/equip/framework) comes out of the box with Monolog. - [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. - [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. -- [SilverStripe 4](https://www.silverstripe.org/) come out of the box with Monolog. +- [SilverStripe 4](https://www.silverstripe.org/) comes out of the box with Monolog. ### Author From c2335059dd9177cfec5a9b861f7e85b9dd4a75f7 Mon Sep 17 00:00:00 2001 From: Nikita Krasnikov Date: Tue, 28 May 2019 02:55:38 +0300 Subject: [PATCH 123/498] Fixed gelf formatter --- src/Monolog/Formatter/GelfMessageFormatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index faf268d3e..e56267944 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -116,7 +116,7 @@ public function format(array $record): Message $len = strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); - break; + continue; } $message->setAdditional($this->extraPrefix . $key, $val); } @@ -126,7 +126,7 @@ public function format(array $record): Message $len = strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); - break; + continue; } $message->setAdditional($this->contextPrefix . $key, $val); } From aca061ec6251cc05a1b2d762c6b6107115bf18fb Mon Sep 17 00:00:00 2001 From: Rodion Date: Wed, 5 Jun 2019 11:19:00 +0300 Subject: [PATCH 124/498] Delete SlackbotHandler from docs --- doc/02-handlers-formatters-processors.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 169001102..66f575af0 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -33,7 +33,6 @@ - [_PushoverHandler_](../src/Monolog/Handler/PushoverHandler.php): Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. - [_HipChatHandler_](../src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. - [_FlowdockHandler_](../src/Monolog/Handler/FlowdockHandler.php): Logs records to a [Flowdock](https://www.flowdock.com/) account. -- [_SlackbotHandler_](../src/Monolog/Handler/SlackbotHandler.php): Logs records to a [Slack](https://www.slack.com/) account using the Slackbot incoming hook. - [_SlackWebhookHandler_](../src/Monolog/Handler/SlackWebhookHandler.php): Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks. - [_SlackHandler_](../src/Monolog/Handler/SlackHandler.php): Logs records to a [Slack](https://www.slack.com/) account using the Slack API (complex setup). - [_SendGridHandler_](../src/Monolog/Handler/SendGridHandler.php): Sends emails via the SendGrid API. From c9a4e5fb48aa27a6b31cec6692cb64f77732c3e0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 30 Jun 2019 18:35:22 +0200 Subject: [PATCH 125/498] Fix typo --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index c5f3abac4..5e08d0772 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -127,7 +127,7 @@ your own wrappers easily. - [_OverflowHandler_](../src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it receives, up until a configured threshold of number of messages of a certain lever is reached, after it will pass all - log messages to the wrapped handler. Useful for applying in bath processing when you're only interested in significant + log messages to the wrapped handler. Useful for applying in batch processing when you're only interested in significant failures instead of minor, single erroneous events. ## Formatters From ab7e54e7df2a798bec317734a332642e88f9127a Mon Sep 17 00:00:00 2001 From: yasutomog Date: Fri, 5 Apr 2019 19:10:59 +0900 Subject: [PATCH 126/498] For when the date changes during a long process. --- src/Monolog/Handler/StreamHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index a35b7e4c3..27d90e064 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -63,6 +63,7 @@ public function close() fclose($this->stream); } $this->stream = null; + $this->dirCreated = null; } /** From e6883175c20e597eaacf4b40bacb0d9616f2c719 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 2 Jul 2019 16:15:41 +0200 Subject: [PATCH 127/498] Bump PHP requirement to 7.2, fixes #1337 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 868b378eb..426628c03 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": "^7.1", + "php": "^7.2", "psr/log": "^1.0.1" }, "require-dev": { From 319f4d79059e9df8cb97e796d291f4b39548d743 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Wed, 13 Mar 2019 13:38:28 +0100 Subject: [PATCH 128/498] Test on php 7.4 only --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9adcf749f..c258b68cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ php: - 7.1 - 7.2 - 7.3 - - nightly + - 7.4snapshot matrix: include: From 33ae80beebd7478c23b46a10d487dc3e15e51e2a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 3 Jul 2019 16:32:46 +0200 Subject: [PATCH 129/498] Remove 7.1 build --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a0989745..e29ab2bfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ sudo: false dist: trusty php: - - 7.1 - 7.2 - 7.3 - 7.4snapshot @@ -15,7 +14,7 @@ cache: matrix: include: - - php: 7.1 + - php: 7.2 env: deps=low fast_finish: true From c2249121dc8d6e3cc6e19a64bdf3bf3baf6a62b8 Mon Sep 17 00:00:00 2001 From: Alexandr Mazur Date: Thu, 4 Jul 2019 00:47:00 +0300 Subject: [PATCH 130/498] Change Curl\Util for return response from cURL request. --- src/Monolog/Handler/Curl/Util.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 5a8abef3f..91e81bb68 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -31,13 +31,16 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param resource $ch curl handler - * @throws \RuntimeException + * @param resource $ch curl handler + * @param int $retries + * @param bool $closeAfterDone + * @return bool|string @see curl_exec */ - public static function execute($ch, int $retries = 5, bool $closeAfterDone = true): void + public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) { while ($retries--) { - if (curl_exec($ch) === false) { + $curlResponse = curl_exec($ch); + if ($curlResponse === false) { $curlErrno = curl_errno($ch); if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) { @@ -56,7 +59,10 @@ public static function execute($ch, int $retries = 5, bool $closeAfterDone = tru if ($closeAfterDone) { curl_close($ch); } - break; + + return $curlResponse; } + + return false; } -} +} \ No newline at end of file From 1284105074d302239fe86656c79d0e2cfc554220 Mon Sep 17 00:00:00 2001 From: Alexandr Mazur Date: Tue, 25 Jun 2019 20:19:02 +0300 Subject: [PATCH 131/498] Add telegram bot handler. --- src/Monolog/Handler/TelegramBotHandler.php | 90 +++++++++++++++++++ .../Handler/TelegramBotHandlerTest.php | 42 +++++++++ 2 files changed, 132 insertions(+) create mode 100644 src/Monolog/Handler/TelegramBotHandler.php create mode 100644 tests/Monolog/Handler/TelegramBotHandlerTest.php diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php new file mode 100644 index 000000000..8c532164d --- /dev/null +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -0,0 +1,90 @@ + + */ +class TelegramBotHandler extends AbstractProcessingHandler +{ + private const BOT_API = 'https://api.telegram.org/bot'; + + /** + * Telegram bot access token provided by BotFather. + * Create telegram bot with https://telegram.me/BotFather and use access token from it. + * @var string + */ + private $apiKey; + + /** + * Telegram channel name. + * Since to start with '@' symbol as prefix. + * @var string + */ + private $channel; + + /** + * @param string $apiKey Telegram bot access token provided by BotFather + * @param string $channel Telegram channel name + * @inheritDoc + */ + public function __construct( + string $apiKey, + string $channel, + $level = Logger::DEBUG, + bool $bubble = true + ) { + parent::__construct($level, $bubble); + + $this->apiKey = $apiKey; + $this->channel = $channel; + $this->level = $level; + $this->bubble = $bubble; + } + + /** + * @inheritDoc + */ + protected function write(array $record): void + { + $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 + { + $ch = curl_init(); + $url = self::BOT_API . $this->apiKey . '/SendMessage'; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ + 'text' => $message, + 'chat_id' => $this->channel, + ])); + + $result = curl_exec($ch); + $result = json_decode($result, true); + + if ($result['ok'] === false) { + throw new RuntimeException('Telegram API error. Description: ' . $result['description']); + } + } +} \ No newline at end of file diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php new file mode 100644 index 000000000..c9f22f0b3 --- /dev/null +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -0,0 +1,42 @@ + + * @link https://core.telegram.org/bots/api + */ +class TelegramBotHandlerTest extends TestCase +{ + /** + * @var TelegramBotHandler + */ + private $handler; + + public function testSendTelegramRequest(): void + { + $this->createHandler(); + $this->handler->handle($this->getRecord()); + } + + /** + * @param string $apiKey + * @param string $channel + */ + private function createHandler(string $apiKey = 'testKey', string $channel = 'testChannel'): void + { + $constructorArgs = [$apiKey, $channel, Logger::DEBUG, true]; + + $this->handler = $this->getMockBuilder(TelegramBotHandler::class) + ->setConstructorArgs($constructorArgs) + ->setMethods(['send']) + ->getMock(); + + $this->handler->expects($this->atLeast(1)) + ->method('send') + ->willReturn(null); + } +} \ No newline at end of file From 636ca43ddfe4b45a815ee12e2fac6ff7f63a84e1 Mon Sep 17 00:00:00 2001 From: Alexandr Mazur Date: Fri, 5 Jul 2019 19:24:39 +0300 Subject: [PATCH 132/498] Change curl_exec($ch) call to Curl\Util::execute($ch) call, according to pull request. --- src/Monolog/Handler/TelegramBotHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 8c532164d..34a87da55 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -80,7 +80,7 @@ protected function send(string $message): void 'chat_id' => $this->channel, ])); - $result = curl_exec($ch); + $result = Curl\Util::execute($ch); $result = json_decode($result, true); if ($result['ok'] === false) { From 447fb7b391bd5d72bf9b8ab5514d9ab49b81a753 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:16:00 +0200 Subject: [PATCH 133/498] Deprecate RavenHandler, fixes #1340, refs #1298, refs #1331 --- src/Monolog/Handler/RavenHandler.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 10d7f43bf..1929f25fd 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -61,6 +61,8 @@ class RavenHandler extends AbstractProcessingHandler */ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) { + @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED); + parent::__construct($level, $bubble); $this->ravenClient = $ravenClient; From 0c3811c8b161f146dbfb319f3bb6b8767f932154 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:23:58 +0200 Subject: [PATCH 134/498] Remove RavenHandler as it is deprecated in 1.x --- composer.json | 2 - doc/02-handlers-formatters-processors.md | 12 +- src/Monolog/Handler/RavenHandler.php | 270 --------------- .../Handler/MockRavenClient-gte-0-16-0.php | 27 -- tests/Monolog/Handler/MockRavenClient.php | 27 -- tests/Monolog/Handler/RavenHandlerTest.php | 307 ------------------ 6 files changed, 6 insertions(+), 639 deletions(-) delete mode 100644 src/Monolog/Handler/RavenHandler.php delete mode 100644 tests/Monolog/Handler/MockRavenClient-gte-0-16-0.php delete mode 100644 tests/Monolog/Handler/MockRavenClient.php delete mode 100644 tests/Monolog/Handler/RavenHandlerTest.php diff --git a/composer.json b/composer.json index 426628c03..f34517429 100644 --- a/composer.json +++ b/composer.json @@ -29,12 +29,10 @@ "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^1.9", "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "sentry/sentry": "Allow sending log messages to a Sentry server", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 2baf97318..1169473bc 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -45,13 +45,11 @@ - [_SocketHandler_](../src/Monolog/Handler/SocketHandler.php): Logs records to [sockets](http://php.net/fsockopen), use this for UNIX and TCP sockets. See an [example](sockets.md). - [_AmqpHandler_](../src/Monolog/Handler/AmqpHandler.php): Logs records to an [AMQP](http://www.amqp.org/) compatible - server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+) or + server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+) or [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. - [_GelfHandler_](../src/Monolog/Handler/GelfHandler.php): Logs records to a [Graylog2](http://www.graylog2.org) server. Requires package [graylog2/gelf-php](https://github.com/bzikarsky/gelf-php). - [_CubeHandler_](../src/Monolog/Handler/CubeHandler.php): Logs records to a [Cube](http://square.github.com/cube/) server. -- [_RavenHandler_](../src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using - [raven](https://packagist.org/packages/raven/raven). - [_ZendMonitorHandler_](../src/Monolog/Handler/ZendMonitorHandler.php): Logs records to the Zend Monitor present in Zend Server. - [_NewRelicHandler_](../src/Monolog/Handler/NewRelicHandler.php): Logs records to a [NewRelic](http://newrelic.com/) application. - [_LogglyHandler_](../src/Monolog/Handler/LogglyHandler.php): Logs records to a [Loggly](http://www.loggly.com/) account. @@ -61,6 +59,8 @@ - [_InsightOpsHandler_](../src/Monolog/Handler/InsightOpsHandler.php): Logs records to an [InsightOps](https://www.rapid7.com/products/insightops/) account. - [_LogmaticHandler_](../src/Monolog/Handler/LogmaticHandler.php): Logs records to a [Logmatic](http://logmatic.io/) account. - [_SqsHandler_](../src/Monolog/Handler/SqsHandler.php): Logs records to an [AWS SQS](http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-sqs.html) queue. +- [_RavenHandler_](../src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using + [raven](https://packagist.org/packages/raven/raven). **Deprecated** and removed in Monolog 2.0, use sentry/sentry 2.x and the [Sentry\Monolog\Handler](https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php) class instead. ### Logging in development @@ -128,9 +128,9 @@ - [_HandlerWrapper_](../src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create your own wrappers easily. - [_OverflowHandler_](../src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it - receives, up until a configured threshold of number of messages of a certain lever is reached, after it will pass all - log messages to the wrapped handler. Useful for applying in batch processing when you're only interested in significant - failures instead of minor, single erroneous events. + receives, up until a configured threshold of number of messages of a certain lever is reached, after it will pass all + log messages to the wrapped handler. Useful for applying in batch processing when you're only interested in significant + failures instead of minor, single erroneous events. ## Formatters diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php deleted file mode 100644 index d4c261ca1..000000000 --- a/src/Monolog/Handler/RavenHandler.php +++ /dev/null @@ -1,270 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\LineFormatter; -use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; -use Raven_Client; - -/** - * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server - * using sentry-php (https://github.com/getsentry/sentry-php) - * - * @author Marc Abramowitz - */ -class RavenHandler extends AbstractProcessingHandler -{ - /** - * Translates Monolog log levels to Raven log levels. - */ - protected $logLevels = [ - Logger::DEBUG => Raven_Client::DEBUG, - Logger::INFO => Raven_Client::INFO, - Logger::NOTICE => Raven_Client::INFO, - Logger::WARNING => Raven_Client::WARNING, - Logger::ERROR => Raven_Client::ERROR, - Logger::CRITICAL => Raven_Client::FATAL, - Logger::ALERT => Raven_Client::FATAL, - Logger::EMERGENCY => Raven_Client::FATAL, - ]; - - /** - * @var string the current application environment (staging|preprod|prod) - */ - protected $environment; - - /** - * @var string should represent the current version of the calling - * software. Can be any string (git commit, version number) - */ - protected $release; - - /** - * @var Raven_Client the client object that sends the message to the server - */ - protected $ravenClient; - - /** - * @var FormatterInterface The formatter to use for the logs generated via handleBatch() - */ - protected $batchFormatter; - - /** - * @param Raven_Client $ravenClient - * @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(Raven_Client $ravenClient, $level = Logger::DEBUG, bool $bubble = true) - { - @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED); - - parent::__construct($level, $bubble); - - $this->ravenClient = $ravenClient; - } - - /** - * {@inheritdoc} - */ - public function handleBatch(array $records): void - { - $level = $this->level; - - // filter records based on their level - $records = array_filter($records, function ($record) use ($level) { - return $record['level'] >= $level; - }); - - if (!$records) { - return; - } - - // the record with the highest severity is the "main" one - $record = array_reduce($records, function ($highest, $record) { - if ($record['level'] > $highest['level']) { - return $record; - } - - return $highest; - }); - - // the other ones are added as a context item - $logs = []; - foreach ($records as $r) { - $logs[] = $this->processRecord($r); - } - - if ($logs) { - $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs); - } - - $this->handle($record); - } - - /** - * Sets the formatter for the logs generated by handleBatch(). - * - * @param FormatterInterface $formatter - */ - public function setBatchFormatter(FormatterInterface $formatter): self - { - $this->batchFormatter = $formatter; - - return $this; - } - - /** - * Gets the formatter for the logs generated by handleBatch(). - */ - public function getBatchFormatter(): FormatterInterface - { - if (!$this->batchFormatter) { - $this->batchFormatter = $this->getDefaultBatchFormatter(); - } - - return $this->batchFormatter; - } - - /** - * {@inheritdoc} - * @suppress PhanTypeMismatchArgument - */ - protected function write(array $record): void - { - /** @var bool|null|array This is false, unless set below to null or an array of data, when we read the current user context */ - $previousUserContext = false; - $options = []; - $options['level'] = $this->logLevels[$record['level']]; - $options['tags'] = []; - if (!empty($record['extra']['tags'])) { - $options['tags'] = array_merge($options['tags'], $record['extra']['tags']); - unset($record['extra']['tags']); - } - if (!empty($record['context']['tags'])) { - $options['tags'] = array_merge($options['tags'], $record['context']['tags']); - unset($record['context']['tags']); - } - if (!empty($record['context']['fingerprint'])) { - $options['fingerprint'] = $record['context']['fingerprint']; - unset($record['context']['fingerprint']); - } - if (!empty($record['context']['logger'])) { - $options['logger'] = $record['context']['logger']; - unset($record['context']['logger']); - } else { - $options['logger'] = $record['channel']; - } - foreach ($this->getExtraParameters() as $key) { - foreach (['extra', 'context'] as $source) { - if (!empty($record[$source][$key])) { - $options[$key] = $record[$source][$key]; - unset($record[$source][$key]); - } - } - } - if (!empty($record['context'])) { - $options['extra']['context'] = $record['context']; - if (!empty($record['context']['user'])) { - $previousUserContext = $this->ravenClient->context->user; - $this->ravenClient->user_context($record['context']['user']); - unset($options['extra']['context']['user']); - } - } - if (!empty($record['extra'])) { - $options['extra']['extra'] = $record['extra']; - } - - if (!empty($this->environment) && !isset($options['environment'])) { - $options['environment'] = $this->environment; - } - - if (!empty($this->release) && !isset($options['release'])) { - $options['release'] = $this->release; - } - - if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { - $options['message'] = $record['formatted']; - $this->ravenClient->captureException($record['context']['exception'], $options); - } else { - $this->ravenClient->captureMessage($record['formatted'], [], $options); - } - - // restore the user context if it was modified - if (!is_bool($previousUserContext)) { - $this->ravenClient->user_context($previousUserContext, false); - } - } - - /** - * {@inheritDoc} - */ - protected function getDefaultFormatter(): FormatterInterface - { - return new LineFormatter('[%channel%] %message%'); - } - - /** - * Gets the default formatter for the logs generated by handleBatch(). - * - * @return FormatterInterface - */ - protected function getDefaultBatchFormatter(): FormatterInterface - { - return new LineFormatter(); - } - - /** - * Gets extra parameters supported by Raven that can be found in "extra" and "context" - * - * @return array - */ - protected function getExtraParameters(): array - { - return ['contexts', 'checksum', 'release', 'environment', 'event_id']; - } - - /** - * @param string $value - * @return self - */ - public function setRelease($value): self - { - $this->release = $value; - - return $this; - } - - public function setEnvironment($value): self - { - $this->environment = $value; - - return $this; - } - - /** - * @link https://docs.sentry.io/learn/breadcrumbs/ - */ - public function addBreadcrumb(array $crumb): self - { - $this->ravenClient->breadcrumbs->record($crumb); - - return $this; - } - - public function resetBreadcrumbs(): self - { - $this->ravenClient->breadcrumbs->reset(); - - return $this; - } -} diff --git a/tests/Monolog/Handler/MockRavenClient-gte-0-16-0.php b/tests/Monolog/Handler/MockRavenClient-gte-0-16-0.php deleted file mode 100644 index 07434e499..000000000 --- a/tests/Monolog/Handler/MockRavenClient-gte-0-16-0.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Raven_Client; - -class MockRavenClient extends Raven_Client -{ - public function capture($data, $stack = null, $vars = null) - { - $data = array_merge($this->get_user_data(), $data); - $this->lastData = $data; - $this->lastStack = $stack; - } - - public $lastData; - public $lastStack; -} diff --git a/tests/Monolog/Handler/MockRavenClient.php b/tests/Monolog/Handler/MockRavenClient.php deleted file mode 100644 index 07434e499..000000000 --- a/tests/Monolog/Handler/MockRavenClient.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Raven_Client; - -class MockRavenClient extends Raven_Client -{ - public function capture($data, $stack = null, $vars = null) - { - $data = array_merge($this->get_user_data(), $data); - $this->lastData = $data; - $this->lastStack = $stack; - } - - public $lastData; - public $lastStack; -} diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php deleted file mode 100644 index 491d84ac2..000000000 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ /dev/null @@ -1,307 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Test\TestCase; -use Monolog\Logger; -use Monolog\Formatter\LineFormatter; -use Raven_Client; - -class RavenHandlerTest extends TestCase -{ - public function setUp() - { - if (!class_exists('Raven_Client')) { - $this->markTestSkipped('sentry/sentry not installed'); - } - - if (version_compare(Raven_Client::VERSION, '0.16.0', '>=')) { - require_once __DIR__ . '/MockRavenClient-gte-0-16-0.php'; - } else { - require_once __DIR__ . '/MockRavenClient.php'; - } - } - - /** - * @covers Monolog\Handler\RavenHandler::__construct - */ - public function testConstruct() - { - $handler = new RavenHandler($this->getRavenClient()); - $this->assertInstanceOf('Monolog\Handler\RavenHandler', $handler); - } - - protected function getHandler($ravenClient) - { - return new RavenHandler($ravenClient); - } - - protected function getRavenClient() - { - $dsn = 'http://43f6017361224d098402974103bfc53d:a6a0538fc2934ba2bed32e08741b2cd3@marca.python.live.cheggnet.com:9000/1'; - - return new MockRavenClient($dsn); - } - - public function testDebug() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $record = $this->getRecord(Logger::DEBUG, 'A test debug message'); - $handler->handle($record); - - $this->assertEquals($ravenClient::DEBUG, $ravenClient->lastData['level']); - $this->assertContains($record['message'], $ravenClient->lastData['message']); - } - - public function testWarning() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $record = $this->getRecord(Logger::WARNING, 'A test warning message'); - $handler->handle($record); - - $this->assertEquals($ravenClient::WARNING, $ravenClient->lastData['level']); - $this->assertContains($record['message'], $ravenClient->lastData['message']); - } - - public function testTag() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $tags = [1, 2, 'foo']; - $record = $this->getRecord(Logger::INFO, 'test', ['tags' => $tags]); - $handler->handle($record); - - $this->assertEquals($tags, $ravenClient->lastData['tags']); - } - - public function testExtraParameters() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $checksum = '098f6bcd4621d373cade4e832627b4f6'; - $release = '05a671c66aefea124cc08b76ea6d30bb'; - $eventId = '31423'; - $record = $this->getRecord(Logger::INFO, 'test', ['checksum' => $checksum, 'release' => $release, 'event_id' => $eventId]); - $handler->handle($record); - - $this->assertEquals($checksum, $ravenClient->lastData['checksum']); - $this->assertEquals($release, $ravenClient->lastData['release']); - $this->assertEquals($eventId, $ravenClient->lastData['event_id']); - } - - public function testFingerprint() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $fingerprint = ['{{ default }}', 'other value']; - $record = $this->getRecord(Logger::INFO, 'test', ['fingerprint' => $fingerprint]); - $handler->handle($record); - - $this->assertEquals($fingerprint, $ravenClient->lastData['fingerprint']); - } - - public function testUserContext() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $recordWithNoContext = $this->getRecord(Logger::INFO, 'test with default user context'); - // set user context 'externally' - - $user = [ - 'id' => '123', - 'email' => 'test@test.com', - ]; - - $recordWithContext = $this->getRecord(Logger::INFO, 'test', ['user' => $user]); - - $ravenClient->user_context(['id' => 'test_user_id']); - // handle context - $handler->handle($recordWithContext); - $this->assertEquals($user, $ravenClient->lastData['user']); - - // check to see if its reset - $handler->handle($recordWithNoContext); - $this->assertIsArray($ravenClient->context->user); - $this->assertSame('test_user_id', $ravenClient->context->user['id']); - - // handle with null context - $ravenClient->user_context(null, false); - $handler->handle($recordWithContext); - $this->assertEquals($user, $ravenClient->lastData['user']); - - // check to see if its reset - $handler->handle($recordWithNoContext); - $this->assertNull($ravenClient->context->user); - } - - public function testException() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - try { - $this->methodThatThrowsAnException(); - } catch (\Exception $e) { - $record = $this->getRecord(Logger::ERROR, $e->getMessage(), ['exception' => $e]); - $handler->handle($record); - } - - $this->assertEquals('[test] ' . $record['message'], $ravenClient->lastData['message']); - } - - public function testHandleBatch() - { - $records = $this->getMultipleRecords(); - $records[] = $this->getRecord(Logger::WARNING, 'warning'); - $records[] = $this->getRecord(Logger::WARNING, 'warning'); - - $logFormatter = $this->createMock('Monolog\\Formatter\\FormatterInterface'); - $logFormatter->expects($this->once())->method('formatBatch'); - - $formatter = $this->createMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) { - return $record['level'] == 400; - })); - - $handler = $this->getHandler($this->getRavenClient()); - $handler->setBatchFormatter($logFormatter); - $handler->setFormatter($formatter); - $handler->handleBatch($records); - } - - public function testHandleBatchDoNothingIfRecordsAreBelowLevel() - { - $records = [ - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information'), - ]; - - $handler = $this->getMockBuilder('Monolog\Handler\RavenHandler') - ->setMethods(['handle']) - ->setConstructorArgs([$this->getRavenClient()]) - ->getMock(); - $handler->expects($this->never())->method('handle'); - $handler->setLevel(Logger::ERROR); - $handler->handleBatch($records); - } - - public function testHandleBatchPicksProperMessage() - { - $records = array( - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information 1'), - $this->getRecord(Logger::ERROR, 'error 1'), - $this->getRecord(Logger::WARNING, 'warning'), - $this->getRecord(Logger::ERROR, 'error 2'), - $this->getRecord(Logger::INFO, 'information 2'), - ); - - $logFormatter = $this->createMock('Monolog\\Formatter\\FormatterInterface'); - $logFormatter->expects($this->once())->method('formatBatch'); - - $formatter = $this->createMock('Monolog\\Formatter\\FormatterInterface'); - $formatter->expects($this->once())->method('format')->with($this->callback(function ($record) use ($records) { - return $record['message'] == 'error 1'; - })); - - $handler = $this->getHandler($this->getRavenClient()); - $handler->setBatchFormatter($logFormatter); - $handler->setFormatter($formatter); - $handler->handleBatch($records); - } - - public function testGetSetBatchFormatter() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $handler->setBatchFormatter($formatter = new LineFormatter()); - $this->assertSame($formatter, $handler->getBatchFormatter()); - } - - public function testRelease() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - $release = 'v42.42.42'; - $handler->setRelease($release); - $record = $this->getRecord(Logger::INFO, 'test'); - $handler->handle($record); - $this->assertEquals($release, $ravenClient->lastData['release']); - - $localRelease = 'v41.41.41'; - $record = $this->getRecord(Logger::INFO, 'test', ['release' => $localRelease]); - $handler->handle($record); - $this->assertEquals($localRelease, $ravenClient->lastData['release']); - } - - public function testEnvironment() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - $handler->setEnvironment('preprod'); - - $handler->handle($this->getRecord(Logger::INFO, 'Hello 👋 from PREPROD env')); - $this->assertEquals('preprod', $ravenClient->lastData['environment']); - - $handler->handle($this->getRecord(Logger::INFO, 'Hello 👋 from STAGING env', ['environment' => 'staging'])); - $this->assertEquals('staging', $ravenClient->lastData['environment']); - } - - public function testBreadcrumbs() - { - $ravenClient = $this->getRavenClient(); - $handler = $this->getHandler($ravenClient); - - $handler->addBreadcrumb($crumb1 = [ - 'category' => 'test', - 'level' => 'info', - 'message' => 'Step 1: user auth', - ]); - - $handler->addBreadcrumb($crumb2 = [ - 'category' => 'test', - 'level' => 'info', - 'message' => 'Step 2: prepare user redirect', - ]); - - $handler->handle($this->getRecord(Logger::ERROR, 'ERROR 💥')); - $breadcrumbs = $ravenClient->breadcrumbs->fetch(); - $this->assertCount(2, $breadcrumbs); - $this->assertSame('test', $breadcrumbs[0]['category']); - $this->assertSame('info', $breadcrumbs[0]['level']); - $this->assertSame('Step 1: user auth', $breadcrumbs[0]['message']); - - $this->assertSame('test', $breadcrumbs[1]['category']); - $this->assertSame('info', $breadcrumbs[1]['level']); - $this->assertSame('Step 2: prepare user redirect', $breadcrumbs[1]['message']); - - $handler->resetBreadcrumbs(); - $handler->handle($this->getRecord(Logger::INFO, 'Hello!')); - $this->assertEmpty($ravenClient->breadcrumbs->fetch()); - } - - private function methodThatThrowsAnException() - { - throw new \Exception('This is an exception'); - } -} From 81108d4e8a047430dc7c20f4291ea0594c4e5cdd Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:29:30 +0200 Subject: [PATCH 135/498] Fix SyslogUdpHandler tests --- src/Monolog/Logger.php | 4 ++++ tests/Monolog/Handler/SyslogUdpHandlerTest.php | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 6d48c135c..517e99960 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -415,6 +415,10 @@ public static function toMonologLevel($level): int throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); } + if (!is_int($level)) { + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + } + return $level; } diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 4c7159204..4ef2390ce 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -83,7 +83,7 @@ public function testRfc() $host = gethostname(); $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') - ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", null, null, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) + ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", 'debug', true, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) ->setMethods(array('getDateTime')) ->getMock(); @@ -92,7 +92,10 @@ public function testRfc() $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); - $socket = $this->getMock('\Monolog\Handler\SyslogUdp\UdpSocket', array('write'), array('lol', 'lol')); + $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') + ->setConstructorArgs(array('lol', 999)) + ->setMethods(array('write')) + ->getMock(); $socket->expects($this->at(0)) ->method('write') ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: "); From 4c36499971d94bfd8fb8994b49b8012081f6a42b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:33:01 +0200 Subject: [PATCH 136/498] Allow 7.4 builds to fail for now --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e29ab2bfb..30770bb52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,8 @@ matrix: - php: 7.2 env: deps=low fast_finish: true + allow_failures: + - 7.4snapshot before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From e1e1f2779a392b281caeb404430bca174dd0014f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:40:06 +0200 Subject: [PATCH 137/498] Add TelegramBotHandler to docs --- doc/02-handlers-formatters-processors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 1169473bc..808b49974 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -39,6 +39,7 @@ - [_MandrillHandler_](../src/Monolog/Handler/MandrillHandler.php): Sends emails via the Mandrill API using a [`Swift_Message`](http://swiftmailer.org/) instance. - [_FleepHookHandler_](../src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. - [_IFTTTHandler_](../src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. +- [_TelegramBotHandler_](../src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. ### Log specific servers and networked logging From 25049eea82fa476c3e2a8714005218cfeed69532 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:55:54 +0200 Subject: [PATCH 138/498] Fix travis config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 30770bb52..aeb3978c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ matrix: env: deps=low fast_finish: true allow_failures: - - 7.4snapshot + - php: 7.4snapshot before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From b0355add1d90f8e4557efec5d0347ab1d97a2fa4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 13:59:26 +0200 Subject: [PATCH 139/498] Deprecate HipChatHandler, fixes #1271 --- doc/02-handlers-formatters-processors.md | 2 +- src/Monolog/Handler/HipChatHandler.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index af45913af..95bb209f9 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -30,7 +30,6 @@ [`mail()`](http://php.net/manual/en/function.mail.php) function. - _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. - _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. -- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API. - _FlowdockHandler_: Logs records to a [Flowdock](https://www.flowdock.com/) account. - _SlackHandler_: Logs records to a [Slack](https://www.slack.com/) account using the Slack API. - _SlackbotHandler_: Logs records to a [Slack](https://www.slack.com/) account using the Slackbot incoming hook. @@ -38,6 +37,7 @@ - _MandrillHandler_: Sends emails via the Mandrill API using a [`Swift_Message`](http://swiftmailer.org/) instance. - _FleepHookHandler_: Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. - _IFTTTHandler_: Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. +- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated**: Use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) ### Log specific servers and networked logging diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index 73233c95e..179d62686 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -97,6 +97,8 @@ class HipChatHandler extends SocketHandler */ public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1) { + @trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED); + if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); } From 17cbfb8b9ccf56c03a32cb72d4a5ec466961eaa3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 6 Jul 2019 15:03:00 +0200 Subject: [PATCH 140/498] Update changelog for 1.x --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5f93bbb..5f2fe55e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### 1.25.0 (xx) + + * Deprecated SlackbotHandler, use SlackWebhookHandler or SlackHandler instead + * Deprecated RavenHandler, use sentry/sentry 2.x and their Sentry\Monolog\Handler instead + * Deprecated HipChatHandler, migrate to Slack and use SlackWebhookHandler or SlackHandler instead + * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler + * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records + * Fixed issue in SignalHandler restarting syscalls functionality + ### 1.24.0 (2018-11-05) * BC Notice: If you are extending any of the Monolog's Formatters' `normalize` method, make sure you add the new `$depth = 0` argument to your function signature to avoid strict PHP warnings. From 27bb55b5083c7c2e8691182b998d06aa5923878f Mon Sep 17 00:00:00 2001 From: Joshua Gigg Date: Sat, 6 Jul 2019 17:47:47 +0100 Subject: [PATCH 141/498] Fix typo in Upgrade Guide now instead of not --- UPGRADE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index 096071aa7..84e15e6b7 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -6,7 +6,7 @@ - Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) methods as well as `emerg`, `crit`, `err` and `warn`. -- DateTime are not formatted with a timezone and microseconds (unless disabled). +- DateTime are now formatted with a timezone and microseconds (unless disabled). Various formatters and log output might be affected, which may mess with log parsing in some cases. From 16ba72a48c36a9b048e121d83fceeb3bf27783d0 Mon Sep 17 00:00:00 2001 From: tacman Date: Sat, 6 Jul 2019 15:03:37 -0400 Subject: [PATCH 142/498] bump php version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac31a8575..49b19bf26 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ can also add your own there if you publish one. ### Requirements -- Monolog 2.x works with PHP 7.1 or above, use Monolog `^1.0` for PHP 5.3+ support. +- Monolog 2.x works with PHP 7.2 or above, use Monolog `^1.0` for PHP 5.3+ support. ### Submitting bugs and feature requests From ada57dd4a1aa672a74ef4763f54670d4cb7ba2b9 Mon Sep 17 00:00:00 2001 From: vershinin_so Date: Thu, 14 Feb 2019 10:32:48 +0300 Subject: [PATCH 143/498] use mb_ functions in GelfFormatter --- .../Formatter/GelfMessageFormatter.php | 12 +++++------ .../Formatter/GelfMessageFormatterTest.php | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index e56267944..6e5e33f2f 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -93,10 +93,10 @@ public function format(array $record): Message ->setLevel($this->logLevels[$record['level']]); // message length + system name length + 200 for padding / metadata - $len = 200 + strlen((string) $record['message']) + strlen($this->systemName); + $len = 200 + mb_strlen((string) $record['message']) + mb_strlen($this->systemName); if ($len > $this->maxLength) { - $message->setShortMessage(substr($record['message'], 0, $this->maxLength)); + $message->setShortMessage(mb_substr($record['message'], 0, $this->maxLength)); } if (isset($record['channel'])) { @@ -113,9 +113,9 @@ public function format(array $record): Message foreach ($record['extra'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = strlen($this->extraPrefix . $key . $val); + $len = mb_strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); + $message->setAdditional($this->extraPrefix . $key, mb_substr($val, 0, $this->maxLength)); continue; } $message->setAdditional($this->extraPrefix . $key, $val); @@ -123,9 +123,9 @@ public function format(array $record): Message foreach ($record['context'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = strlen($this->contextPrefix . $key . $val); + $len = mb_strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); + $message->setAdditional($this->contextPrefix . $key, mb_substr($val, 0, $this->maxLength)); continue; } $message->setAdditional($this->contextPrefix . $key, $val); diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index 012de3cd1..bfefd6a96 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -251,6 +251,26 @@ public function testFormatWithUnlimitedLength() $this->assertGreaterThanOrEqual(131289, $length, 'The message should not be truncated'); } + public function testFormatWithLargeCyrillicData() + { + $formatter = new GelfMessageFormatter(); + $record = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['exception' => str_repeat('а', 32767)], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => ['key' => str_repeat('б', 32767)], + 'message' => str_repeat('в', 32767), + ]; + $message = $formatter->format($record); + $messageArray = $message->toArray(); + + $messageString = json_encode($messageArray); + + $this->assertIsString($messageString); + } + private function isLegacy() { return interface_exists('\Gelf\IMessagePublisher'); From c79d81ec2853bfad5b1c382970bc098a669e906b Mon Sep 17 00:00:00 2001 From: vershinin_so Date: Mon, 8 Jul 2019 11:05:19 +0300 Subject: [PATCH 144/498] mb_* functions with BC --- composer.json | 3 +- src/Monolog/Formatter/FlowdockFormatter.php | 18 +++--------- .../Formatter/GelfMessageFormatter.php | 15 ++++++---- src/Monolog/Formatter/NormalizerFormatter.php | 4 +-- src/Monolog/Formatter/WildfireFormatter.php | 3 +- src/Monolog/Handler/BrowserConsoleHandler.php | 3 +- src/Monolog/Handler/ChromePHPHandler.php | 3 +- src/Monolog/Handler/CubeHandler.php | 5 ++-- src/Monolog/Handler/Curl/Util.php | 8 ++--- src/Monolog/Handler/DeduplicationHandler.php | 5 ++-- src/Monolog/Handler/FleepHookHandler.php | 3 +- src/Monolog/Handler/FlowdockHandler.php | 3 +- src/Monolog/Handler/MailHandler.php | 3 +- src/Monolog/Handler/OverflowHandler.php | 10 +++---- src/Monolog/Handler/PushoverHandler.php | 7 +++-- src/Monolog/Handler/Slack/SlackRecord.php | 3 +- src/Monolog/Handler/SlackHandler.php | 3 +- src/Monolog/Handler/SocketHandler.php | 3 +- src/Monolog/Handler/SqsHandler.php | 5 ++-- src/Monolog/Handler/StreamHandler.php | 5 ++-- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 8 +++-- src/Monolog/Handler/TelegramBotHandler.php | 15 ++++++++-- src/Monolog/Processor/UidProcessor.php | 5 ++-- src/Monolog/Utils.php | 29 +++++++++++++++++++ tests/Monolog/Handler/AmqpHandlerTest.php | 1 - .../Monolog/Handler/SyslogUdpHandlerTest.php | 1 - .../Handler/TelegramBotHandlerTest.php | 13 +++++++-- 27 files changed, 120 insertions(+), 64 deletions(-) diff --git a/composer.json b/composer.json index f34517429..ba3f379ac 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "php-console/php-console": "Allow sending log messages to Google Chrome" + "php-console/php-console": "Allow sending log messages to Google Chrome", + "ext-mbstring": "Allow to work properly with unicode symbols" }, "autoload": { "psr-4": {"Monolog\\": "src/Monolog"} diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 301b74b24..c6276765e 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\Utils; + /** * formats the record to be used in the FlowdockHandler * @@ -84,22 +86,10 @@ public function formatBatch(array $records): array public function getShortMessage(string $message): string { - static $hasMbString; - - if (null === $hasMbString) { - $hasMbString = function_exists('mb_strlen'); - } - $maxLength = 45; - if ($hasMbString) { - if (mb_strlen($message, 'UTF-8') > $maxLength) { - $message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...'; - } - } else { - if (strlen($message) > $maxLength) { - $message = substr($message, 0, $maxLength - 4) . ' ...'; - } + if (Utils::strlen($message) > $maxLength) { + $message = Utils::substr($message, 0, $maxLength - 4) . ' ...'; } return $message; diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 6e5e33f2f..098e96624 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Gelf\Message; +use Monolog\Utils; /** * Serializes a log message to GELF @@ -93,10 +94,10 @@ public function format(array $record): Message ->setLevel($this->logLevels[$record['level']]); // message length + system name length + 200 for padding / metadata - $len = 200 + mb_strlen((string) $record['message']) + mb_strlen($this->systemName); + $len = 200 + Utils::strlen((string) $record['message']) + Utils::strlen($this->systemName); if ($len > $this->maxLength) { - $message->setShortMessage(mb_substr($record['message'], 0, $this->maxLength)); + $message->setShortMessage(Utils::substr($record['message'], 0, $this->maxLength)); } if (isset($record['channel'])) { @@ -113,9 +114,10 @@ public function format(array $record): Message foreach ($record['extra'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = mb_strlen($this->extraPrefix . $key . $val); + $len = Utils::strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->extraPrefix . $key, mb_substr($val, 0, $this->maxLength)); + $message->setAdditional($this->extraPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + continue; } $message->setAdditional($this->extraPrefix . $key, $val); @@ -123,9 +125,10 @@ public function format(array $record): Message foreach ($record['context'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = mb_strlen($this->contextPrefix . $key . $val); + $len = Utils::strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->contextPrefix . $key, mb_substr($val, 0, $this->maxLength)); + $message->setAdditional($this->contextPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + continue; } $message->setAdditional($this->contextPrefix . $key, $val); diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index b806ccd3b..5c67e8331 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -379,12 +379,12 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } - + protected function addJsonEncodeOption($option) { $this->jsonEncodeOptions |= $option; } - + protected function removeJsonEncodeOption($option) { $this->jsonEncodeOptions ^= $option; diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 2d96739e3..40375daed 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\Utils; /** * Serializes a log message according to Wildfire's header requirements @@ -90,7 +91,7 @@ public function format(array $record): string // The message itself is a serialization of the above JSON object + it's length return sprintf( '%d|%s|', - strlen($json), + Utils::strlen($json), $json ); } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 5e46b13bf..a1f17bc23 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\Utils; /** * Handler sending logs to browser's javascript console with no browser extension required @@ -175,7 +176,7 @@ private static function handleStyles(string $formatted): array $args[] = '"font-weight: normal"'; $pos = $match[0][1]; - $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); + $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + Utils::strlen($match[0][0])); } array_unshift($args, static::quote($format)); diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 8f35e1991..c04133ee7 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -146,7 +147,7 @@ protected function send(): void $json = @json_encode(self::$json); $data = base64_encode(utf8_encode($json)); - if (strlen($data) > 240 * 1024) { + if (Utils::strlen($data) > 240 * 1024) { self::$overflowed = true; $record = [ diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 298e572a2..e59a61de4 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Logs to Cube. @@ -134,7 +135,7 @@ private function writeUdp(string $data): void $this->connectUdp(); } - socket_send($this->udpConnection, $data, strlen($data), 0); + socket_send($this->udpConnection, $data, Utils::strlen($data), 0); } private function writeHttp(string $data): void @@ -146,7 +147,7 @@ private function writeHttp(string $data): void curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Content-Length: ' . strlen('['.$data.']'), + 'Content-Length: ' . Utils::strlen('['.$data.']'), ]); Curl\Util::execute($this->httpConnection, 5, false); diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 91e81bb68..b0aeac9cb 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -31,9 +31,9 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param resource $ch curl handler - * @param int $retries - * @param bool $closeAfterDone + * @param resource $ch curl handler + * @param int $retries + * @param bool $closeAfterDone * @return bool|string @see curl_exec */ public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) @@ -65,4 +65,4 @@ public static function execute($ch, int $retries = 5, bool $closeAfterDone = tru return false; } -} \ No newline at end of file +} diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 864c29ae0..0142d8bba 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Simple handler wrapper that deduplicates log records across multiple requests @@ -66,7 +67,7 @@ public function __construct(HandlerInterface $handler, ?string $deduplicationSto { 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->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . Utils::substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore; $this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel); $this->time = $time; } @@ -149,7 +150,7 @@ private function collectLogs(): void while (!feof($handle)) { $log = fgets($handle); - if ($log && substr($log, 0, 10) >= $timestampValidity) { + if ($log && Utils::substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 5087009ff..117904e8e 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Logger; +use Monolog\Utils; /** * Sends logs to Fleep.io using Webhook integrations @@ -96,7 +97,7 @@ private function buildHeader(string $content): string $header = "POST " . static::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; $header .= "Host: " . static::FLEEP_HOST . "\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index be46d0321..b1b50c1c4 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\Utils; /** * Sends notifications through the Flowdock push API @@ -107,7 +108,7 @@ private function buildHeader(string $content): string $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; $header .= "Host: api.flowdock.com\r\n"; $header .= "Content-Type: application/json\r\n"; - $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 3bbfd5655..0fc2e97e1 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\HtmlFormatter; +use Monolog\Utils; /** * Base class for all mail handlers @@ -70,7 +71,7 @@ protected function getHighestRecord(array $records): array protected function isHtmlBody(string $body): bool { - return substr($body, 0, 1) === '<'; + return Utils::substr($body, 0, 1) === '<'; } /** diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 30e81c430..3d034b97c 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -13,7 +13,6 @@ use Monolog\Logger; - /** * Handler to only pass log messages when a certain threshold of number of messages is reached. * @@ -60,9 +59,9 @@ class OverflowHandler extends AbstractHandler /** * @param HandlerInterface $handler - * @param int[] $thresholdMap Dictionary of logger level => threshold - * @param int $level - * @param bool $bubble + * @param int[] $thresholdMap Dictionary of logger level => threshold + * @param int $level + * @param bool $bubble */ public function __construct( HandlerInterface $handler, @@ -87,7 +86,7 @@ public function __construct( * 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 array $record The record to handle + * @param array $record The record to handle * * @return Boolean 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. @@ -108,6 +107,7 @@ public function handle(array $record): bool // The overflow threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 $this->thresholdMap[$level]--; $this->buffer[$level][] = $record; + return false === $this->bubble; } diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 2689de1c6..42de58059 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Sends notifications through the pushover api to mobile phones @@ -115,10 +116,10 @@ protected function generateDataStream(array $record): string private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. - $maxMessageLength = 512 - strlen($this->title); + $maxMessageLength = 512 - Utils::strlen($this->title); $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message']; - $message = substr($message, 0, $maxMessageLength); + $message = Utils::substr($message, 0, $maxMessageLength); $timestamp = $record['datetime']->getTimestamp(); @@ -158,7 +159,7 @@ private function buildHeader(string $content): string $header = "POST /1/messages.json HTTP/1.1\r\n"; $header .= "Host: api.pushover.net\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index c08213663..3fa3cac29 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\Utils; /** * Slack record utility helping to log to Slack webhooks or API. @@ -307,7 +308,7 @@ public function setFormatter(?FormatterInterface $formatter = null): self private function generateAttachmentField(string $title, $value): array { $value = is_array($value) - ? sprintf('```%s```', substr($this->stringify($value), 0, 1990)) + ? sprintf('```%s```', Utils::substr($this->stringify($value), 0, 1990)) : $value; return array( diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 8a6bfdc1f..87bb618e1 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use Monolog\Handler\Slack\SlackRecord; +use Monolog\Utils; /** * Sends notifications through Slack API @@ -129,7 +130,7 @@ private function buildHeader(string $content): string $header = "POST /api/chat.postMessage HTTP/1.1\r\n"; $header .= "Host: slack.com\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . strlen($content) . "\r\n"; + $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 2861e67d7..fd033bce0 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Stores to any socket - uses fsockopen() or pfsockopen(). @@ -325,7 +326,7 @@ private function setStreamChunkSize(): void private function writeToSocket(string $data): void { - $length = strlen($data); + $length = Utils::strlen($data); $sent = 0; $this->lastSentBytes = $sent; while ($this->isConnected() && $sent < $length) { diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 2c89a33de..74b23015f 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -13,6 +13,7 @@ use Aws\Sqs\SqsClient; use Monolog\Logger; +use Monolog\Utils; /** * Writes to any sqs queue. @@ -51,8 +52,8 @@ protected function write(array $record): void } $messageBody = $record['formatted']; - if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { - $messageBody = substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); + if (Utils::strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { + $messageBody = Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); } $this->client->sendMessage([ diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 2cee3f21e..992387378 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Stores to any stream resource @@ -146,8 +147,8 @@ private function getDirFromStream(string $stream): ?string return dirname($stream); } - if ('file://' === substr($stream, 0, 7)) { - return dirname(substr($stream, 7)); + if ('file://' === Utils::substr($stream, 0, 7)) { + return dirname(Utils::substr($stream, 7)); } return null; diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index ad7bb2d9b..34b88c6b6 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -11,6 +11,8 @@ namespace Monolog\Handler\SyslogUdp; +use Monolog\Utils; + class UdpSocket { protected const DATAGRAM_MAX_LENGTH = 65023; @@ -47,13 +49,13 @@ protected function send(string $chunk): void if (!is_resource($this->socket)) { throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); } - socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); + socket_sendto($this->socket, $chunk, Utils::strlen($chunk), $flags = 0, $this->ip, $this->port); } protected function assembleMessage(string $line, string $header): string { - $chunkSize = static::DATAGRAM_MAX_LENGTH - strlen($header); + $chunkSize = static::DATAGRAM_MAX_LENGTH - Utils::strlen($header); - return $header . substr($line, 0, $chunkSize); + return $header . Utils::substr($line, 0, $chunkSize); } } diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 34a87da55..5dae9f54e 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog\Handler; @@ -38,7 +47,7 @@ class TelegramBotHandler extends AbstractProcessingHandler private $channel; /** - * @param string $apiKey Telegram bot access token provided by BotFather + * @param string $apiKey Telegram bot access token provided by BotFather * @param string $channel Telegram channel name * @inheritDoc */ @@ -87,4 +96,4 @@ protected function send(string $message): void throw new RuntimeException('Telegram API error. Description: ' . $result['description']); } } -} \ No newline at end of file +} diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 0c97ab6cd..2644c0b9c 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -12,6 +12,7 @@ namespace Monolog\Processor; use Monolog\ResettableInterface; +use Monolog\Utils; /** * Adds a unique identifier into records @@ -45,11 +46,11 @@ public function getUid(): string public function reset() { - $this->uid = $this->generateUid(strlen($this->uid)); + $this->uid = $this->generateUid(Utils::strlen($this->uid)); } private function generateUid(int $length): string { - return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); + return Utils::substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); } } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 14b76661b..4a11efc68 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -22,4 +22,33 @@ public static function getClass($object): string return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } + + private static function hasMbString(): bool + { + static $hasMbString; + + if (null === $hasMbString) { + $hasMbString = extension_loaded('mbstring'); + } + + return $hasMbString; + } + + public static function strlen(string $string, ?string $encoding = null): int + { + if (self::hasMbString()) { + return mb_strlen($string, $encoding); + } + + return strlen($string); + } + + public static function substr(string $string, int $start, ?int $length = null) + { + if (self::hasMbString()) { + return mb_substr($string, $start, $length); + } + + return substr($string, $start, $length); + } } diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index 680de2905..a3b6bff93 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -14,7 +14,6 @@ use Monolog\Test\TestCase; use Monolog\Logger; use PhpAmqpLib\Message\AMQPMessage; -use PhpAmqpLib\Connection\AMQPConnection; /** * @covers Monolog\Handler\RotatingFileHandler diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 4ef2390ce..f4d41098b 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -75,7 +75,6 @@ public function testSplitWorksOnEmptyMsg() $handler->handle($this->getRecordWithMessage(null)); } - public function testRfc() { $time = 'Mar 22 21:16:47'; diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index c9f22f0b3..c6f0e8a56 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog\Handler; @@ -39,4 +48,4 @@ private function createHandler(string $apiKey = 'testKey', string $channel = 'te ->method('send') ->willReturn(null); } -} \ No newline at end of file +} From ecd871b624c258760433b1e89d94f4edf9deafe0 Mon Sep 17 00:00:00 2001 From: vershinin_so Date: Mon, 8 Jul 2019 11:09:29 +0300 Subject: [PATCH 145/498] fix TypeError --- src/Monolog/Utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 4a11efc68..1ee350f55 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -37,7 +37,7 @@ private static function hasMbString(): bool public static function strlen(string $string, ?string $encoding = null): int { if (self::hasMbString()) { - return mb_strlen($string, $encoding); + return $encoding ? mb_strlen($string, $encoding) : mb_strlen($string); } return strlen($string); From 45ebc699ae3ce3896708a2c9399bae4034f89718 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 8 Jul 2019 13:09:43 +0200 Subject: [PATCH 146/498] Fix markdown syntax --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index b849d09dd..7734132cc 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -39,7 +39,7 @@ - [_FleepHookHandler_](../src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. - [_IFTTTHandler_](../src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. - [_TelegramBotHandler_](../src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. -- [_HipChatHandler_](../src/Monolog/Handler/HipChatHandler.php: Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) +- [_HipChatHandler_](../src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) ### Log specific servers and networked logging From f8de7cf62823b763fde3fb54b65a4f4e4014b232 Mon Sep 17 00:00:00 2001 From: vershinin_so Date: Mon, 8 Jul 2019 18:04:33 +0300 Subject: [PATCH 147/498] use mb_* when needed --- src/Monolog/Formatter/FlowdockFormatter.php | 20 ++++++++++++---- .../Formatter/GelfMessageFormatter.php | 6 ++--- src/Monolog/Formatter/WildfireFormatter.php | 3 +-- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- src/Monolog/Handler/ChromePHPHandler.php | 3 +-- src/Monolog/Handler/CubeHandler.php | 5 ++-- src/Monolog/Handler/DeduplicationHandler.php | 5 ++-- src/Monolog/Handler/FleepHookHandler.php | 3 +-- src/Monolog/Handler/FlowdockHandler.php | 3 +-- src/Monolog/Handler/MailHandler.php | 3 +-- src/Monolog/Handler/PushoverHandler.php | 4 ++-- src/Monolog/Handler/Slack/SlackRecord.php | 3 +-- src/Monolog/Handler/SlackHandler.php | 3 +-- src/Monolog/Handler/SocketHandler.php | 3 +-- src/Monolog/Handler/SqsHandler.php | 2 +- src/Monolog/Handler/StreamHandler.php | 5 ++-- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 4 ++-- src/Monolog/Processor/UidProcessor.php | 5 ++-- src/Monolog/Utils.php | 24 ++----------------- 19 files changed, 42 insertions(+), 64 deletions(-) diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index c6276765e..6a68081ec 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -11,8 +11,6 @@ namespace Monolog\Formatter; -use Monolog\Utils; - /** * formats the record to be used in the FlowdockHandler * @@ -84,12 +82,24 @@ public function formatBatch(array $records): array return $formatted; } - public function getShortMessage(string $message): string + public function getShortMessage($message) { + static $hasMbString; + + if (null === $hasMbString) { + $hasMbString = function_exists('mb_strlen'); + } + $maxLength = 45; - if (Utils::strlen($message) > $maxLength) { - $message = Utils::substr($message, 0, $maxLength - 4) . ' ...'; + if ($hasMbString) { + if (mb_strlen($message, 'UTF-8') > $maxLength) { + $message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...'; + } + } else { + if (strlen($message) > $maxLength) { + $message = substr($message, 0, $maxLength - 4) . ' ...'; + } } return $message; diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 098e96624..271628a3b 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -94,7 +94,7 @@ public function format(array $record): Message ->setLevel($this->logLevels[$record['level']]); // message length + system name length + 200 for padding / metadata - $len = 200 + Utils::strlen((string) $record['message']) + Utils::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)); @@ -114,7 +114,7 @@ public function format(array $record): Message foreach ($record['extra'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = Utils::strlen($this->extraPrefix . $key . $val); + $len = strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->extraPrefix . $key, Utils::substr($val, 0, $this->maxLength)); @@ -125,7 +125,7 @@ public function format(array $record): Message foreach ($record['context'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len = Utils::strlen($this->contextPrefix . $key . $val); + $len = strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { $message->setAdditional($this->contextPrefix . $key, Utils::substr($val, 0, $this->maxLength)); diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 40375daed..2d96739e3 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Logger; -use Monolog\Utils; /** * Serializes a log message according to Wildfire's header requirements @@ -91,7 +90,7 @@ public function format(array $record): string // The message itself is a serialization of the above JSON object + it's length return sprintf( '%d|%s|', - Utils::strlen($json), + strlen($json), $json ); } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index a1f17bc23..4dff9f24f 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -176,7 +176,7 @@ private static function handleStyles(string $formatted): array $args[] = '"font-weight: normal"'; $pos = $match[0][1]; - $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + Utils::strlen($match[0][0])); + $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + strlen($match[0][0])); } array_unshift($args, static::quote($format)); diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index c04133ee7..8f35e1991 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; -use Monolog\Utils; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -147,7 +146,7 @@ protected function send(): void $json = @json_encode(self::$json); $data = base64_encode(utf8_encode($json)); - if (Utils::strlen($data) > 240 * 1024) { + if (strlen($data) > 240 * 1024) { self::$overflowed = true; $record = [ diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index e59a61de4..298e572a2 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Logger; -use Monolog\Utils; /** * Logs to Cube. @@ -135,7 +134,7 @@ private function writeUdp(string $data): void $this->connectUdp(); } - socket_send($this->udpConnection, $data, Utils::strlen($data), 0); + socket_send($this->udpConnection, $data, strlen($data), 0); } private function writeHttp(string $data): void @@ -147,7 +146,7 @@ private function writeHttp(string $data): void curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Content-Length: ' . Utils::strlen('['.$data.']'), + 'Content-Length: ' . strlen('['.$data.']'), ]); Curl\Util::execute($this->httpConnection, 5, false); diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 0142d8bba..864c29ae0 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Logger; -use Monolog\Utils; /** * Simple handler wrapper that deduplicates log records across multiple requests @@ -67,7 +66,7 @@ public function __construct(HandlerInterface $handler, ?string $deduplicationSto { parent::__construct($handler, 0, Logger::DEBUG, $bubble, false); - $this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . Utils::substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore; + $this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore; $this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel); $this->time = $time; } @@ -150,7 +149,7 @@ private function collectLogs(): void while (!feof($handle)) { $log = fgets($handle); - if ($log && Utils::substr($log, 0, 10) >= $timestampValidity) { + if ($log && substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 117904e8e..5087009ff 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Logger; -use Monolog\Utils; /** * Sends logs to Fleep.io using Webhook integrations @@ -97,7 +96,7 @@ private function buildHeader(string $content): string $header = "POST " . static::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; $header .= "Host: " . static::FLEEP_HOST . "\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index b1b50c1c4..be46d0321 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -14,7 +14,6 @@ use Monolog\Logger; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Utils; /** * Sends notifications through the Flowdock push API @@ -108,7 +107,7 @@ private function buildHeader(string $content): string $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; $header .= "Host: api.flowdock.com\r\n"; $header .= "Content-Type: application/json\r\n"; - $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 0fc2e97e1..3bbfd5655 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -13,7 +13,6 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\HtmlFormatter; -use Monolog\Utils; /** * Base class for all mail handlers @@ -71,7 +70,7 @@ protected function getHighestRecord(array $records): array protected function isHtmlBody(string $body): bool { - return Utils::substr($body, 0, 1) === '<'; + return substr($body, 0, 1) === '<'; } /** diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 42de58059..3bb99c759 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -116,7 +116,7 @@ protected function generateDataStream(array $record): string private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. - $maxMessageLength = 512 - Utils::strlen($this->title); + $maxMessageLength = 512 - strlen($this->title); $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message']; $message = Utils::substr($message, 0, $maxMessageLength); @@ -159,7 +159,7 @@ private function buildHeader(string $content): string $header = "POST /1/messages.json HTTP/1.1\r\n"; $header .= "Host: api.pushover.net\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 3fa3cac29..c08213663 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -14,7 +14,6 @@ use Monolog\Logger; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Utils; /** * Slack record utility helping to log to Slack webhooks or API. @@ -308,7 +307,7 @@ public function setFormatter(?FormatterInterface $formatter = null): self private function generateAttachmentField(string $title, $value): array { $value = is_array($value) - ? sprintf('```%s```', Utils::substr($this->stringify($value), 0, 1990)) + ? sprintf('```%s```', substr($this->stringify($value), 0, 1990)) : $value; return array( diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 87bb618e1..8a6bfdc1f 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use Monolog\Handler\Slack\SlackRecord; -use Monolog\Utils; /** * Sends notifications through Slack API @@ -130,7 +129,7 @@ private function buildHeader(string $content): string $header = "POST /api/chat.postMessage HTTP/1.1\r\n"; $header .= "Host: slack.com\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . Utils::strlen($content) . "\r\n"; + $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; return $header; diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index fd033bce0..2861e67d7 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Logger; -use Monolog\Utils; /** * Stores to any socket - uses fsockopen() or pfsockopen(). @@ -326,7 +325,7 @@ private function setStreamChunkSize(): void private function writeToSocket(string $data): void { - $length = Utils::strlen($data); + $length = strlen($data); $sent = 0; $this->lastSentBytes = $sent; while ($this->isConnected() && $sent < $length) { diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 74b23015f..a98c87bf7 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -52,7 +52,7 @@ protected function write(array $record): void } $messageBody = $record['formatted']; - if (Utils::strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { + if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { $messageBody = Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); } diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 992387378..2cee3f21e 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Logger; -use Monolog\Utils; /** * Stores to any stream resource @@ -147,8 +146,8 @@ private function getDirFromStream(string $stream): ?string return dirname($stream); } - if ('file://' === Utils::substr($stream, 0, 7)) { - return dirname(Utils::substr($stream, 7)); + if ('file://' === substr($stream, 0, 7)) { + return dirname(substr($stream, 7)); } return null; diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 34b88c6b6..c43bc156b 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -49,12 +49,12 @@ protected function send(string $chunk): void if (!is_resource($this->socket)) { throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); } - socket_sendto($this->socket, $chunk, Utils::strlen($chunk), $flags = 0, $this->ip, $this->port); + socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); } protected function assembleMessage(string $line, string $header): string { - $chunkSize = static::DATAGRAM_MAX_LENGTH - Utils::strlen($header); + $chunkSize = static::DATAGRAM_MAX_LENGTH - strlen($header); return $header . Utils::substr($line, 0, $chunkSize); } diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 2644c0b9c..0c97ab6cd 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -12,7 +12,6 @@ namespace Monolog\Processor; use Monolog\ResettableInterface; -use Monolog\Utils; /** * Adds a unique identifier into records @@ -46,11 +45,11 @@ public function getUid(): string public function reset() { - $this->uid = $this->generateUid(Utils::strlen($this->uid)); + $this->uid = $this->generateUid(strlen($this->uid)); } private function generateUid(int $length): string { - return Utils::substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); + return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); } } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 1ee350f55..c38904224 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -23,30 +23,10 @@ public static function getClass($object): string return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } - private static function hasMbString(): bool - { - static $hasMbString; - - if (null === $hasMbString) { - $hasMbString = extension_loaded('mbstring'); - } - - return $hasMbString; - } - - public static function strlen(string $string, ?string $encoding = null): int - { - if (self::hasMbString()) { - return $encoding ? mb_strlen($string, $encoding) : mb_strlen($string); - } - - return strlen($string); - } - public static function substr(string $string, int $start, ?int $length = null) { - if (self::hasMbString()) { - return mb_substr($string, $start, $length); + if (extension_loaded('mbstring')) { + return mb_strcut($string, $start, $length); } return substr($string, $start, $length); From ad39412eb0a7842daa92db74b8dc3ecc624e64f9 Mon Sep 17 00:00:00 2001 From: vershinin_so Date: Thu, 11 Jul 2019 09:37:46 +0300 Subject: [PATCH 148/498] type hint --- src/Monolog/Formatter/FlowdockFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 6a68081ec..301b74b24 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -82,7 +82,7 @@ public function formatBatch(array $records): array return $formatted; } - public function getShortMessage($message) + public function getShortMessage(string $message): string { static $hasMbString; From ca3a914276f4609647db611ec39c3a1fa6521823 Mon Sep 17 00:00:00 2001 From: Jason Davis Date: Fri, 12 Jul 2019 11:57:06 -0700 Subject: [PATCH 149/498] Update for compatibility with actively maintained versions of Zend Server --- src/Monolog/Handler/ZendMonitorHandler.php | 46 +++++++++++-------- .../Handler/ZendMonitorHandlerTest.php | 8 +++- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index f22cf2187..a20aeae01 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -17,6 +17,7 @@ * Handler sending logs to Zend Monitor * * @author Christian Bergau + * @author Jason Davis */ class ZendMonitorHandler extends AbstractProcessingHandler { @@ -25,16 +26,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler * * @var array */ - protected $levelMap = array( - Logger::DEBUG => 1, - Logger::INFO => 2, - Logger::NOTICE => 3, - Logger::WARNING => 4, - Logger::ERROR => 5, - Logger::CRITICAL => 6, - Logger::ALERT => 7, - Logger::EMERGENCY => 0, - ); + protected $levelMap = array(); /** * Construct @@ -46,8 +38,21 @@ class ZendMonitorHandler extends AbstractProcessingHandler public function __construct($level = Logger::DEBUG, $bubble = true) { if (!function_exists('zend_monitor_custom_event')) { - throw new MissingExtensionException('You must have Zend Server installed in order to use this handler'); + 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 = array( + 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); } @@ -57,22 +62,23 @@ public function __construct($level = Logger::DEBUG, $bubble = true) protected function write(array $record) { $this->writeZendMonitorCustomEvent( - $this->levelMap[$record['level']], + Logger::getLevelName($record['level']), $record['message'], - $record['formatted'] + $record['formatted'], + $this->levelMap[$record['level']] ); } /** - * Write a record to Zend Monitor - * - * @param int $level - * @param string $message - * @param array $formatted + * Write to Zend Monitor Events + * @param string $type Text displayed in "Class Name (custom)" field + * @param string $message Text displayed in "Error String" + * @param mixed $formatted Displayed in Custom Variables tab + * @param int $severity Set the event severity level (-1,0,1) */ - protected function writeZendMonitorCustomEvent($level, $message, $formatted) + protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity) { - zend_monitor_custom_event($level, $message, $formatted); + zend_monitor_custom_event($type, $message, $formatted, $severity); } /** diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 69b001eae..57e1633f0 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -10,6 +10,7 @@ namespace Monolog\Handler; +use Monolog\Logger; use Monolog\TestCase; class ZendMonitorHandlerTest extends TestCase @@ -53,7 +54,12 @@ public function testWrite() $zendMonitor->expects($this->once()) ->method('writeZendMonitorCustomEvent') - ->with($levelMap[$record['level']], $record['message'], $formatterResult); + ->with( + Logger::getLevelName($record['level']), + $record['message'], + $formatterResult, + $levelMap[$record['level']] + ); $zendMonitor->handle($record); } From 2dfb18db0af80757ef63a56500ee6469567c3af7 Mon Sep 17 00:00:00 2001 From: Tal Ater Date: Sun, 21 Jul 2019 15:42:57 +0300 Subject: [PATCH 150/498] Fixed broken link to PPI framework Old link links to a domain for sale page. Domain must have expired. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49b19bf26..4a81a4246 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Symfony](http://symfony.com) comes out of the box with Monolog. - [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog. - [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog. -- [PPI](http://www.ppi.io/) comes out of the box with Monolog. +- [PPI](https://github.com/ppi/framework) comes out of the box with Monolog. - [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin. - [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. - [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog. From 226bc5fdf4d3d18ff5e4c1fb4274613711aeeaae Mon Sep 17 00:00:00 2001 From: Pierre Lannoy Date: Mon, 22 Jul 2019 16:54:07 +0200 Subject: [PATCH 151/498] Fix for SyslogUdpHandler timezone issue Hello! As described in [this issue](https://github.com/Seldaek/monolog/issues/1350), SyslogUdpHandler doesn't respect `Logger` timezone setting for IETF (RFC-5424) syslog format. This PR is a fix for this issue. --- src/Monolog/Handler/SyslogUdpHandler.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 9381f0081..c6badac6f 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\DateTimeImmutable; use Monolog\Logger; use Monolog\Handler\SyslogUdp\UdpSocket; @@ -57,7 +58,7 @@ protected function write(array $record): void { $lines = $this->splitMessageIntoLines($record['formatted']); - $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]); + $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']], $record['datetime']); foreach ($lines as $line) { $this->socket->write($line, $header); @@ -81,7 +82,7 @@ private function splitMessageIntoLines($message): array /** * Make common syslog header (see rfc5424 or rfc3164) */ - protected function makeCommonSyslogHeader(int $severity): string + protected function makeCommonSyslogHeader(int $severity, DateTimeImmutable $datetime): string { $priority = $severity + $this->facility; @@ -93,10 +94,13 @@ protected function makeCommonSyslogHeader(int $severity): string $hostname = '-'; } - $date = $this->getDateTime(); - if ($this->rfc === self::RFC3164) { - return "<$priority>" . + $datetime->setTimezone(new \DateTimeZone('UTC')); + } + $date = $datetime->format($this->dateFormats[$this->rfc]); + + if ($this->rfc === self::RFC3164) { + return "<$priority>" . $date . " " . $hostname . " " . $this->ident . "[" . $pid . "]: "; From 4e095f38f4f626829c247adba70cc723d986fa70 Mon Sep 17 00:00:00 2001 From: Thomas Perez Date: Wed, 31 Jul 2019 22:19:02 +0200 Subject: [PATCH 152/498] Fix error_handler return type declaration --- src/Monolog/ErrorHandler.php | 2 ++ src/Monolog/Handler/StreamHandler.php | 4 +++- tests/Monolog/Formatter/NormalizerFormatterTest.php | 4 ++++ tests/Monolog/Handler/RotatingFileHandlerTest.php | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 3d386606e..2643fdb87 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -200,6 +200,8 @@ public function handleError($code, $message, $file = '', $line = 0, $context = [ } elseif ($this->previousErrorHandler) { return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); } + + return true; } /** diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 2cee3f21e..0c2f8d1bd 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -134,9 +134,11 @@ protected function streamWrite($stream, array $record): void fwrite($stream, (string) $record['formatted']); } - private function customErrorHandler($code, $msg): void + private function customErrorHandler($code, $msg): bool { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); + + return true; } private function getDirFromStream(string $stream): ?string diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 8f3499a50..9f914883a 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -182,6 +182,8 @@ public function testIgnoresRecursiveObjectReferences() restore_error_handler(); $that->fail("$message should not be raised"); } + + return true; }); $formatter = new NormalizerFormatter(); @@ -215,6 +217,8 @@ public function testIgnoresInvalidTypes() restore_error_handler(); $that->fail("$message should not be raised"); } + + return true; }); $formatter = new NormalizerFormatter(); diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 7d3e8c4f4..35dbcc279 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -34,6 +34,8 @@ public function setUp() 'code' => $code, 'message' => $message, ]; + + return true; }); } From 37900f926821aa2ceaa4aa9b00ed42b5bd19d34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Bla=C5=BEek?= Date: Mon, 12 Aug 2019 15:20:00 +0200 Subject: [PATCH 153/498] Upgrade PHPUnit to v8 --- composer.json | 2 +- .../Formatter/ElasticaFormatterTest.php | 2 +- .../Formatter/GelfMessageFormatterTest.php | 8 ++- .../Formatter/LogstashFormatterTest.php | 10 +--- .../Formatter/MongoDBFormatterTest.php | 2 +- .../Formatter/NormalizerFormatterTest.php | 16 ++---- .../Monolog/Formatter/ScalarFormatterTest.php | 2 +- .../Formatter/WildfireFormatterTest.php | 3 +- .../Handler/AbstractProcessingHandlerTest.php | 6 +- .../Handler/BrowserConsoleHandlerTest.php | 2 +- .../Monolog/Handler/ChromePHPHandlerTest.php | 2 +- .../Handler/DeduplicationHandlerTest.php | 2 +- .../Handler/DoctrineCouchDBHandlerTest.php | 2 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 2 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 7 ++- .../Handler/ElasticsearchHandlerTest.php | 7 ++- tests/Monolog/Handler/ErrorLogHandlerTest.php | 7 ++- tests/Monolog/Handler/FilterHandlerTest.php | 3 +- .../Handler/FingersCrossedHandlerTest.php | 3 +- tests/Monolog/Handler/FirePHPHandlerTest.php | 2 +- .../Monolog/Handler/FleepHookHandlerTest.php | 2 +- tests/Monolog/Handler/FlowdockHandlerTest.php | 2 +- tests/Monolog/Handler/GelfHandlerTest.php | 2 +- tests/Monolog/Handler/GroupHandlerTest.php | 3 +- tests/Monolog/Handler/HandlerWrapperTest.php | 2 +- tests/Monolog/Handler/MongoDBHandlerTest.php | 5 +- .../Handler/NativeMailerHandlerTest.php | 27 ++++----- tests/Monolog/Handler/NewRelicHandlerTest.php | 7 +-- .../Monolog/Handler/PHPConsoleHandlerTest.php | 7 +-- tests/Monolog/Handler/RedisHandlerTest.php | 27 +++++---- tests/Monolog/Handler/RollbarHandlerTest.php | 2 +- .../Handler/RotatingFileHandlerTest.php | 4 +- .../Monolog/Handler/Slack/SlackRecordTest.php | 2 +- tests/Monolog/Handler/SlackHandlerTest.php | 2 +- tests/Monolog/Handler/SocketHandlerTest.php | 55 ++++++++----------- tests/Monolog/Handler/StreamHandlerTest.php | 29 ++++++---- .../Handler/SwiftMailerHandlerTest.php | 2 +- .../Monolog/Handler/SyslogUdpHandlerTest.php | 5 +- .../Handler/TelegramBotHandlerTest.php | 5 +- tests/Monolog/Handler/UdpSocketTest.php | 5 +- .../Handler/WhatFailureGroupHandlerTest.php | 3 +- .../Handler/ZendMonitorHandlerTest.php | 2 +- tests/Monolog/LoggerTest.php | 14 +++-- tests/Monolog/Processor/WebProcessorTest.php | 5 +- tests/Monolog/RegistryTest.php | 7 ++- tests/Monolog/SignalHandlerTest.php | 4 +- 46 files changed, 154 insertions(+), 166 deletions(-) diff --git a/composer.json b/composer.json index f34517429..85637dddb 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^8.3", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index 5e4eeb9c4..e2c977784 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -15,7 +15,7 @@ class ElasticaFormatterTest extends \PHPUnit\Framework\TestCase { - public function setUp() + public function setUp(): void { if (!class_exists("Elastica\Document")) { $this->markTestSkipped("ruflin/elastica not installed"); diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index 012de3cd1..9be4b3e67 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -12,10 +12,11 @@ namespace Monolog\Formatter; use Monolog\Logger; +use PHPUnit\Framework\TestCase; -class GelfMessageFormatterTest extends \PHPUnit\Framework\TestCase +class GelfMessageFormatterTest extends TestCase { - public function setUp() + public function setUp(): void { if (!class_exists('\Gelf\Message')) { $this->markTestSkipped("graylog2/gelf-php is not installed"); @@ -82,10 +83,11 @@ public function testFormatWithFileAndLine() /** * @covers Monolog\Formatter\GelfMessageFormatter::format - * @expectedException InvalidArgumentException */ public function testFormatInvalidFails() { + $this->expectException(\InvalidArgumentException::class); + $formatter = new GelfMessageFormatter(); $record = [ 'level' => Logger::ERROR, diff --git a/tests/Monolog/Formatter/LogstashFormatterTest.php b/tests/Monolog/Formatter/LogstashFormatterTest.php index 5d0374bc9..b242d6803 100644 --- a/tests/Monolog/Formatter/LogstashFormatterTest.php +++ b/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -12,16 +12,10 @@ namespace Monolog\Formatter; use Monolog\Logger; +use PHPUnit\Framework\TestCase; -class LogstashFormatterTest extends \PHPUnit\Framework\TestCase +class LogstashFormatterTest extends TestCase { - public function tearDown() - { - \PHPUnit\Framework\Error\Warning::$enabled = true; - - return parent::tearDown(); - } - /** * @covers Monolog\Formatter\LogstashFormatter::format */ diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index f9494f3d3..140341b44 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -18,7 +18,7 @@ */ class MongoDBFormatterTest extends \PHPUnit\Framework\TestCase { - public function setUp() + public function setUp(): void { if (!class_exists('MongoDB\BSON\UTCDateTime')) { $this->markTestSkipped('ext-mongodb not installed'); diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 8f3499a50..bc918543d 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -11,18 +11,13 @@ namespace Monolog\Formatter; +use PHPUnit\Framework\TestCase; + /** * @covers Monolog\Formatter\NormalizerFormatter */ -class NormalizerFormatterTest extends \PHPUnit\Framework\TestCase +class NormalizerFormatterTest extends TestCase { - public function tearDown() - { - \PHPUnit\Framework\Error\Warning::$enabled = true; - - return parent::tearDown(); - } - public function testFormat() { $formatter = new NormalizerFormatter('Y-m-d'); @@ -263,11 +258,10 @@ public function testNormalizeHandleLargeArrays() $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); } - /** - * @expectedException RuntimeException - */ public function testThrowsOnInvalidEncoding() { + $this->expectException(\RuntimeException::class); + $formatter = new NormalizerFormatter(); $reflMethod = new \ReflectionMethod($formatter, 'toJson'); $reflMethod->setAccessible(true); diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index 9af4937cc..6c519628a 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -17,7 +17,7 @@ class ScalarFormatterTest extends \PHPUnit\Framework\TestCase { private $formatter; - public function setUp() + public function setUp(): void { $this->formatter = new ScalarFormatter(); } diff --git a/tests/Monolog/Formatter/WildfireFormatterTest.php b/tests/Monolog/Formatter/WildfireFormatterTest.php index d06620203..06c75169f 100644 --- a/tests/Monolog/Formatter/WildfireFormatterTest.php +++ b/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -91,10 +91,11 @@ public function testFormatWithoutContext() /** * @covers Monolog\Formatter\WildfireFormatter::formatBatch - * @expectedException BadMethodCallException */ public function testBatchFormatThrowException() { + $this->expectException(\BadMethodCallException::class); + $wildfire = new WildfireFormatter(); $record = [ 'level' => Logger::ERROR, diff --git a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php index 58d092023..0d3736d00 100644 --- a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php +++ b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php @@ -93,10 +93,11 @@ public function testProcessRecord() /** * @covers Monolog\Handler\ProcessableHandlerTrait::pushProcessor * @covers Monolog\Handler\ProcessableHandlerTrait::popProcessor - * @expectedException LogicException */ public function testPushPopProcessor() { + $this->expectException(\LogicException::class); + $logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); $processor1 = new WebProcessor; $processor2 = new WebProcessor; @@ -111,10 +112,11 @@ public function testPushPopProcessor() /** * @covers Monolog\Handler\ProcessableHandlerTrait::pushProcessor - * @expectedException TypeError */ public function testPushProcessorWithNonCallable() { + $this->expectException(\TypeError::class); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); $handler->pushProcessor(new \stdClass()); diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index cbb216a17..57b4cc773 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -19,7 +19,7 @@ */ class BrowserConsoleHandlerTest extends TestCase { - protected function setUp() + protected function setUp(): void { BrowserConsoleHandler::resetStatic(); } diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index aff518471..42c0c559b 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -19,7 +19,7 @@ */ class ChromePHPHandlerTest extends TestCase { - protected function setUp() + protected function setUp(): void { TestChromePHPHandler::resetStatic(); $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0'; diff --git a/tests/Monolog/Handler/DeduplicationHandlerTest.php b/tests/Monolog/Handler/DeduplicationHandlerTest.php index 491fd85c8..ef4fb0a6b 100644 --- a/tests/Monolog/Handler/DeduplicationHandlerTest.php +++ b/tests/Monolog/Handler/DeduplicationHandlerTest.php @@ -158,7 +158,7 @@ public function testGcOldLogs() $this->assertFalse($test->hasWarningRecords()); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { @unlink(sys_get_temp_dir().'/monolog_dedup.log'); } diff --git a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php index f72f32370..80546aaf5 100644 --- a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php +++ b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -16,7 +16,7 @@ class DoctrineCouchDBHandlerTest extends TestCase { - protected function setup() + protected function setUp(): void { if (!class_exists('Doctrine\CouchDB\CouchDBClient')) { $this->markTestSkipped('The "doctrine/couchdb" package is not installed'); diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 9d61356f6..0a291253c 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -17,7 +17,7 @@ class DynamoDbHandlerTest extends TestCase { private $client; - public function setUp() + public function setUp(): void { if (!class_exists('Aws\DynamoDb\DynamoDbClient')) { $this->markTestSkipped('aws/aws-sdk-php not installed'); diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 423adbe6a..c456ec13a 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -34,7 +34,7 @@ class ElasticaHandlerTest extends TestCase 'type' => 'doc_type', ]; - public function setUp() + public function setUp(): void { // Elastica lib required if (!class_exists("Elastica\Client")) { @@ -97,11 +97,12 @@ public function testSetFormatter() /** * @covers Monolog\Handler\ElasticaHandler::setFormatter - * @expectedException InvalidArgumentException - * @expectedExceptionMessage ElasticaHandler is only compatible with ElasticaFormatter */ public function testSetFormatterInvalid() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('ElasticaHandler is only compatible with ElasticaFormatter'); + $handler = new ElasticaHandler($this->client); $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 7895332be..06599e453 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -33,7 +33,7 @@ class ElasticsearchHandlerTest extends TestCase 'type' => 'doc_type', ]; - public function setUp() + public function setUp(): void { // Elasticsearch lib required if (!class_exists('Elasticsearch\Client')) { @@ -109,11 +109,12 @@ public function testSetFormatter() /** * @covers Monolog\Handler\ElasticsearchHandler::setFormatter - * @expectedException InvalidArgumentException - * @expectedExceptionMessage ElasticsearchHandler is only compatible with ElasticsearchFormatter */ public function testSetFormatterInvalid() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); + $handler = new ElasticsearchHandler($this->client); $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); diff --git a/tests/Monolog/Handler/ErrorLogHandlerTest.php b/tests/Monolog/Handler/ErrorLogHandlerTest.php index 16d8e47d9..d48a058b9 100644 --- a/tests/Monolog/Handler/ErrorLogHandlerTest.php +++ b/tests/Monolog/Handler/ErrorLogHandlerTest.php @@ -22,18 +22,19 @@ function error_log() class ErrorLogHandlerTest extends TestCase { - protected function setUp() + protected function setUp(): void { $GLOBALS['error_log'] = []; } /** * @covers Monolog\Handler\ErrorLogHandler::__construct - * @expectedException InvalidArgumentException - * @expectedExceptionMessage The given message type "42" is not supported */ public function testShouldNotAcceptAnInvalidTypeOnConstructor() { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('The given message type "42" is not supported'); + new ErrorLogHandler(42); } diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index b0072de03..db7157191 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -159,10 +159,11 @@ function ($record, $handler) use ($test) { /** * @covers Monolog\Handler\FilterHandler::handle - * @expectedException \RuntimeException */ public function testHandleWithBadCallbackThrowsException() { + $this->expectException(\RuntimeException::class); + $handler = new FilterHandler( function ($record, $handler) { return 'foo'; diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index b545489c9..75dc49af8 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -129,10 +129,11 @@ public function testHandleWithCallback() /** * @covers Monolog\Handler\FingersCrossedHandler::handle * @covers Monolog\Handler\FingersCrossedHandler::activate - * @expectedException RuntimeException */ public function testHandleWithBadCallbackThrowsException() { + $this->expectException(\RuntimeException::class); + $handler = new FingersCrossedHandler(function ($record, $handler) { return 'foo'; }); diff --git a/tests/Monolog/Handler/FirePHPHandlerTest.php b/tests/Monolog/Handler/FirePHPHandlerTest.php index 3ada7cedd..cd8fa1bec 100644 --- a/tests/Monolog/Handler/FirePHPHandlerTest.php +++ b/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -19,7 +19,7 @@ */ class FirePHPHandlerTest extends TestCase { - public function setUp() + public function setUp(): void { TestFirePHPHandler::resetStatic(); $_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0'; diff --git a/tests/Monolog/Handler/FleepHookHandlerTest.php b/tests/Monolog/Handler/FleepHookHandlerTest.php index fe44e360a..de01c44b8 100644 --- a/tests/Monolog/Handler/FleepHookHandlerTest.php +++ b/tests/Monolog/Handler/FleepHookHandlerTest.php @@ -30,7 +30,7 @@ class FleepHookHandlerTest extends TestCase */ private $handler; - public function setUp() + public function setUp(): void { parent::setUp(); diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 23f8b06cd..ec8ad0878 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -31,7 +31,7 @@ class FlowdockHandlerTest extends TestCase */ private $handler; - public function setUp() + public function setUp(): void { if (!extension_loaded('openssl')) { $this->markTestSkipped('This test requires openssl to run'); diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 12e5f8b17..41de094d0 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -18,7 +18,7 @@ class GelfHandlerTest extends TestCase { - public function setUp() + public function setUp(): void { if (!class_exists('Gelf\Publisher') || !class_exists('Gelf\Message')) { $this->markTestSkipped("graylog2/gelf-php not installed"); diff --git a/tests/Monolog/Handler/GroupHandlerTest.php b/tests/Monolog/Handler/GroupHandlerTest.php index 003c70147..536518c07 100644 --- a/tests/Monolog/Handler/GroupHandlerTest.php +++ b/tests/Monolog/Handler/GroupHandlerTest.php @@ -18,10 +18,11 @@ class GroupHandlerTest extends TestCase { /** * @covers Monolog\Handler\GroupHandler::__construct - * @expectedException InvalidArgumentException */ public function testConstructorOnlyTakesHandler() { + $this->expectException(\InvalidArgumentException::class); + new GroupHandler([new TestHandler(), "foo"]); } diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index 42fff1c6d..87a117b18 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -25,7 +25,7 @@ class HandlerWrapperTest extends TestCase private $handler; - public function setUp() + public function setUp(): void { parent::setUp(); $this->handler = $this->createMock('Monolog\\Handler\\HandlerInterface'); diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index 7333ef62a..a21f207bd 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -17,11 +17,10 @@ class MongoDBHandlerTest extends TestCase { - /** - * @expectedException InvalidArgumentException - */ public function testConstructorShouldThrowExceptionForInvalidMongo() { + $this->expectException(\InvalidArgumentException::class); + new MongoDBHandler(new \stdClass, 'db', 'collection'); } diff --git a/tests/Monolog/Handler/NativeMailerHandlerTest.php b/tests/Monolog/Handler/NativeMailerHandlerTest.php index 9e17cd3fb..0803f5b4e 100644 --- a/tests/Monolog/Handler/NativeMailerHandlerTest.php +++ b/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -22,51 +22,46 @@ function mail($to, $subject, $message, $additional_headers = null, $additional_p class NativeMailerHandlerTest extends TestCase { - protected function setUp() + protected function setUp(): void { $GLOBALS['mail'] = []; } - /** - * @expectedException InvalidArgumentException - */ public function testConstructorHeaderInjection() { + $this->expectException(\InvalidArgumentException::class); + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', "receiver@example.org\r\nFrom: faked@attacker.org"); } - /** - * @expectedException InvalidArgumentException - */ public function testSetterHeaderInjection() { + $this->expectException(\InvalidArgumentException::class); + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); $mailer->addHeader("Content-Type: text/html\r\nFrom: faked@attacker.org"); } - /** - * @expectedException InvalidArgumentException - */ public function testSetterArrayHeaderInjection() { + $this->expectException(\InvalidArgumentException::class); + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); $mailer->addHeader(["Content-Type: text/html\r\nFrom: faked@attacker.org"]); } - /** - * @expectedException InvalidArgumentException - */ public function testSetterContentTypeInjection() { + $this->expectException(\InvalidArgumentException::class); + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); $mailer->setContentType("text/html\r\nFrom: faked@attacker.org"); } - /** - * @expectedException InvalidArgumentException - */ public function testSetterEncodingInjection() { + $this->expectException(\InvalidArgumentException::class); + $mailer = new NativeMailerHandler('spammer@example.org', 'dear victim', 'receiver@example.org'); $mailer->setEncoding("utf-8\r\nFrom: faked@attacker.org"); } diff --git a/tests/Monolog/Handler/NewRelicHandlerTest.php b/tests/Monolog/Handler/NewRelicHandlerTest.php index 26160094d..e4e4d70b3 100644 --- a/tests/Monolog/Handler/NewRelicHandlerTest.php +++ b/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -21,18 +21,17 @@ class NewRelicHandlerTest extends TestCase public static $customParameters; public static $transactionName; - public function setUp() + public function setUp(): void { self::$appname = null; self::$customParameters = []; self::$transactionName = null; } - /** - * @expectedException Monolog\Handler\MissingExtensionException - */ public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded() { + $this->expectException(MissingExtensionException::class); + $handler = new StubNewRelicHandlerWithoutExtension(); $handler->handle($this->getRecord(Logger::ERROR)); } diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 9c479da6f..7b899550a 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -34,7 +34,7 @@ class PHPConsoleHandlerTest extends TestCase /** @var ErrorDispatcher|MockObject */ protected $errorDispatcher; - protected function setUp() + protected function setUp(): void { if (!class_exists('PhpConsole\Connector')) { $this->markTestSkipped('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); @@ -187,11 +187,10 @@ public function testException() ); } - /** - * @expectedException Exception - */ public function testWrongOptionsThrowsException() { + $this->expectException(\Exception::class); + new PHPConsoleHandler(['xxx' => 1]); } diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index a0260e1d8..19f2bbc7f 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -17,11 +17,10 @@ class RedisHandlerTest extends TestCase { - /** - * @expectedException InvalidArgumentException - */ public function testConstructorShouldThrowExceptionForInvalidRedis() { + $this->expectException(\InvalidArgumentException::class); + new RedisHandler(new \stdClass(), 'key'); } @@ -43,11 +42,11 @@ public function testConstructorShouldWorkWithRedis() public function testPredisHandle() { - $redis = $this->createPartialMock('Predis\Client', ['rpush']); + $redis = $this->createPartialMock('Predis\Client', ['rPush']); - // Predis\Client uses rpush + // Predis\Client uses rPush $redis->expects($this->once()) - ->method('rpush') + ->method('rPush') ->with('key', 'test'); $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); @@ -63,11 +62,11 @@ public function testRedisHandle() $this->markTestSkipped('The redis ext is required to run this test'); } - $redis = $this->createPartialMock('Redis', ['rpush']); + $redis = $this->createPartialMock('Redis', ['rPush']); // Redis uses rPush $redis->expects($this->once()) - ->method('rpush') + ->method('rPush') ->with('key', 'test'); $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); @@ -83,7 +82,7 @@ public function testRedisHandleCapped() $this->markTestSkipped('The redis ext is required to run this test'); } - $redis = $this->createPartialMock('Redis', ['multi', 'rpush', 'ltrim', 'exec']); + $redis = $this->createPartialMock('Redis', ['multi', 'rPush', 'lTrim', 'exec']); // Redis uses multi $redis->expects($this->once()) @@ -91,11 +90,11 @@ public function testRedisHandleCapped() ->will($this->returnSelf()); $redis->expects($this->once()) - ->method('rpush') + ->method('rPush') ->will($this->returnSelf()); $redis->expects($this->once()) - ->method('ltrim') + ->method('lTrim') ->will($this->returnSelf()); $redis->expects($this->once()) @@ -113,14 +112,14 @@ public function testPredisHandleCapped() { $redis = $this->createPartialMock('Predis\Client', ['transaction']); - $redisTransaction = $this->createPartialMock('Predis\Client', ['rpush', 'ltrim']); + $redisTransaction = $this->createPartialMock('Predis\Client', ['rPush', 'lTrim']); $redisTransaction->expects($this->once()) - ->method('rpush') + ->method('rPush') ->will($this->returnSelf()); $redisTransaction->expects($this->once()) - ->method('ltrim') + ->method('lTrim') ->will($this->returnSelf()); // Redis uses multi diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 5d8c1fc29..7419ef820 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -35,7 +35,7 @@ class RollbarHandlerTest extends TestCase */ private $reportedExceptionArguments = null; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 7d3e8c4f4..6b695154c 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -21,7 +21,7 @@ class RotatingFileHandlerTest extends TestCase { private $lastError; - public function setUp() + public function setUp(): void { $dir = __DIR__.'/Fixtures'; chmod($dir, 0777); @@ -238,7 +238,7 @@ public function testReuseCurrentFile() $this->assertEquals('footest', file_get_contents($log)); } - public function tearDown() + public function tearDown(): void { foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { unlink($file); diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index 9f23c7ce5..f1572b273 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -21,7 +21,7 @@ class SlackRecordTest extends TestCase { private $jsonPrettyPrintFlag; - protected function setUp() + protected function setUp(): void { $this->jsonPrettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; } diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index e8abd15de..4a7833498 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -32,7 +32,7 @@ class SlackHandlerTest extends TestCase */ private $handler; - public function setUp() + public function setUp(): void { if (!extension_loaded('openssl')) { $this->markTestSkipped('This test requires openssl to run'); diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index a003cb7f3..48a2642ab 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -30,20 +30,18 @@ class SocketHandlerTest extends TestCase */ private $res; - /** - * @expectedException UnexpectedValueException - */ public function testInvalidHostname() { + $this->expectException(\UnexpectedValueException::class); + $this->createHandler('garbage://here'); $this->writeRecord('data'); } - /** - * @expectedException \InvalidArgumentException - */ public function testBadConnectionTimeout() { + $this->expectException(\InvalidArgumentException::class); + $this->createHandler('localhost:1234'); $this->handler->setConnectionTimeout(-1); } @@ -55,11 +53,10 @@ public function testSetConnectionTimeout() $this->assertEquals(10.1, $this->handler->getConnectionTimeout()); } - /** - * @expectedException \InvalidArgumentException - */ public function testBadTimeout() { + $this->expectException(\InvalidArgumentException::class); + $this->createHandler('localhost:1234'); $this->handler->setTimeout(-1); } @@ -91,11 +88,10 @@ public function testSetConnectionString() $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString()); } - /** - * @expectedException UnexpectedValueException - */ public function testExceptionIsThrownOnFsockopenError() { + $this->expectException(\UnexpectedValueException::class); + $this->setMockHandler(['fsockopen']); $this->handler->expects($this->once()) ->method('fsockopen') @@ -103,11 +99,10 @@ public function testExceptionIsThrownOnFsockopenError() $this->writeRecord('Hello world'); } - /** - * @expectedException UnexpectedValueException - */ public function testExceptionIsThrownOnPfsockopenError() { + $this->expectException(\UnexpectedValueException::class); + $this->setMockHandler(['pfsockopen']); $this->handler->expects($this->once()) ->method('pfsockopen') @@ -116,11 +111,10 @@ public function testExceptionIsThrownOnPfsockopenError() $this->writeRecord('Hello world'); } - /** - * @expectedException UnexpectedValueException - */ public function testExceptionIsThrownIfCannotSetTimeout() { + $this->expectException(\UnexpectedValueException::class); + $this->setMockHandler(['streamSetTimeout']); $this->handler->expects($this->once()) ->method('streamSetTimeout') @@ -128,11 +122,10 @@ public function testExceptionIsThrownIfCannotSetTimeout() $this->writeRecord('Hello world'); } - /** - * @expectedException UnexpectedValueException - */ public function testExceptionIsThrownIfCannotSetChunkSize() { + $this->expectException(\UnexpectedValueException::class); + $this->setMockHandler(array('streamSetChunkSize')); $this->handler->setChunkSize(8192); $this->handler->expects($this->once()) @@ -141,11 +134,10 @@ public function testExceptionIsThrownIfCannotSetChunkSize() $this->writeRecord('Hello world'); } - /** - * @expectedException RuntimeException - */ public function testWriteFailsOnIfFwriteReturnsFalse() { + $this->expectException(\RuntimeException::class); + $this->setMockHandler(['fwrite']); $callback = function ($arg) { @@ -164,11 +156,10 @@ public function testWriteFailsOnIfFwriteReturnsFalse() $this->writeRecord('Hello world'); } - /** - * @expectedException RuntimeException - */ public function testWriteFailsIfStreamTimesOut() { + $this->expectException(\RuntimeException::class); + $this->setMockHandler(['fwrite', 'streamGetMetadata']); $callback = function ($arg) { @@ -190,11 +181,10 @@ public function testWriteFailsIfStreamTimesOut() $this->writeRecord('Hello world'); } - /** - * @expectedException RuntimeException - */ public function testWriteFailsOnIncompleteWrite() { + $this->expectException(\RuntimeException::class); + $this->setMockHandler(['fwrite', 'streamGetMetadata']); $res = $this->res; @@ -263,11 +253,10 @@ public function testCloseDoesNotClosePersistentSocket() $this->assertTrue(is_resource($this->res)); } - /** - * @expectedException \RuntimeException - */ public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds() { + $this->expectException(\RuntimeException::class); + $this->setMockHandler(['fwrite', 'streamGetMetadata']); $this->handler->expects($this->any()) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 377e29641..f8101dbad 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -70,7 +70,7 @@ public function testSerialization() $this->assertTrue(is_resource($stream)); fseek($stream, 0); - $this->assertContains('testfoo', stream_get_contents($stream)); + $this->assertStringContainsString('testfoo', stream_get_contents($stream)); $serialized = serialize($handler); $this->assertFalse(is_resource($stream)); @@ -81,8 +81,8 @@ public function testSerialization() $this->assertTrue(is_resource($stream)); fseek($stream, 0); $contents = stream_get_contents($stream); - $this->assertNotContains('testfoo', $contents); - $this->assertContains('testbar', $contents); + $this->assertStringNotContainsString('testfoo', $contents); + $this->assertStringContainsString('testbar', $contents); } /** @@ -106,12 +106,13 @@ public function testWriteLocking() } /** - * @expectedException LogicException * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write */ public function testWriteMissingResource() { + $this->expectException(\LogicException::class); + $handler = new StreamHandler(null); $handler->handle($this->getRecord()); } @@ -127,32 +128,35 @@ public function invalidArgumentProvider() /** * @dataProvider invalidArgumentProvider - * @expectedException InvalidArgumentException * @covers Monolog\Handler\StreamHandler::__construct */ public function testWriteInvalidArgument($invalidArgument) { + $this->expectException(\InvalidArgumentException::class); + $handler = new StreamHandler($invalidArgument); } /** - * @expectedException UnexpectedValueException * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write */ public function testWriteInvalidResource() { + $this->expectException(\UnexpectedValueException::class); + $handler = new StreamHandler('bogus://url'); $handler->handle($this->getRecord()); } /** - * @expectedException UnexpectedValueException * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write */ public function testWriteNonExistingResource() { + $this->expectException(\UnexpectedValueException::class); + $handler = new StreamHandler('ftp://foo/bar/baz/'.rand(0, 10000)); $handler->handle($this->getRecord()); } @@ -178,13 +182,15 @@ public function testWriteNonExistingFileResource() } /** - * @expectedException Exception - * @expectedExceptionMessageRegExp /There is no existing directory at/ * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write */ public function testWriteNonExistingAndNotCreatablePath() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('There is no existing directory at'); + + if (defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Permissions checks can not run on windows'); } @@ -193,13 +199,14 @@ public function testWriteNonExistingAndNotCreatablePath() } /** - * @expectedException Exception - * @expectedExceptionMessageRegExp /There is no existing directory at/ * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write */ public function testWriteNonExistingAndNotCreatableFileResource() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('There is no existing directory at'); + if (defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Permissions checks can not run on windows'); } diff --git a/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/tests/Monolog/Handler/SwiftMailerHandlerTest.php index d8ff39bc7..51596c392 100644 --- a/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ b/tests/Monolog/Handler/SwiftMailerHandlerTest.php @@ -20,7 +20,7 @@ class SwiftMailerHandlerTest extends TestCase /** @var \Swift_Mailer|MockObject */ private $mailer; - public function setUp() + public function setUp(): void { $this->mailer = $this ->getMockBuilder('Swift_Mailer') diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 4ef2390ce..4d0e114cb 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -18,11 +18,10 @@ */ class SyslogUdpHandlerTest extends TestCase { - /** - * @expectedException UnexpectedValueException - */ public function testWeValidateFacilities() { + $this->expectException(\UnexpectedValueException::class); + $handler = new SyslogUdpHandler("ip", 514, "invalidFacility"); } diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index c9f22f0b3..6e09aaddf 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -36,7 +36,6 @@ private function createHandler(string $apiKey = 'testKey', string $channel = 'te ->getMock(); $this->handler->expects($this->atLeast(1)) - ->method('send') - ->willReturn(null); + ->method('send'); } -} \ No newline at end of file +} diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index bc01a25b7..530091cde 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -58,11 +58,10 @@ public function testDoubleCloseDoesNotError() $socket->close(); } - /** - * @expectedException RuntimeException - */ public function testWriteAfterCloseErrors() { + $this->expectException(\RuntimeException::class); + $socket = new UdpSocket('127.0.0.1', 514); $socket->close(); $socket->write('foo', "HEADER"); diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 6aacdde54..c7ac45613 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -18,10 +18,11 @@ class WhatFailureGroupHandlerTest extends TestCase { /** * @covers Monolog\Handler\WhatFailureGroupHandler::__construct - * @expectedException InvalidArgumentException */ public function testConstructorOnlyTakesHandler() { + $this->expectException(\InvalidArgumentException::class); + new WhatFailureGroupHandler([new TestHandler(), "foo"]); } diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 4879ebef3..02169f17d 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -17,7 +17,7 @@ class ZendMonitorHandlerTest extends TestCase { protected $zendMonitorHandler; - public function setUp() + public function setUp(): void { if (!function_exists('zend_monitor_custom_event')) { $this->markTestSkipped('ZendServer is not installed'); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index c3c5e94ae..deaa2c33b 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -63,10 +63,11 @@ public function testConvertPSR3ToMonologLevel() /** * @covers Monolog\Logger::getLevelName - * @expectedException InvalidArgumentException */ public function testGetLevelNameThrows() { + $this->expectException(\InvalidArgumentException::class); + Logger::getLevelName(5); } @@ -138,10 +139,11 @@ public function testProcessorsInCtor() /** * @covers Monolog\Logger::pushHandler * @covers Monolog\Logger::popHandler - * @expectedException LogicException */ public function testPushPopHandler() { + $this->expectException(\LogicException::class); + $logger = new Logger(__METHOD__); $handler1 = new TestHandler; $handler2 = new TestHandler; @@ -181,10 +183,11 @@ public function testSetHandlers() /** * @covers Monolog\Logger::pushProcessor * @covers Monolog\Logger::popProcessor - * @expectedException LogicException */ public function testPushPopProcessor() { + $this->expectException(\LogicException::class); + $logger = new Logger(__METHOD__); $processor1 = new WebProcessor; $processor2 = new WebProcessor; @@ -541,7 +544,7 @@ public function testTimezoneIsRespectedInOtherTimezone() } } - public function tearDown() + public function tearDown(): void { date_default_timezone_set('UTC'); } @@ -592,10 +595,11 @@ public function testSetExceptionHandler() /** * @covers Monolog\Logger::handleException - * @expectedException Exception */ public function testDefaultHandleException() { + $this->expectException(\Exception::class); + $logger = new Logger(__METHOD__); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); $handler->expects($this->any()) diff --git a/tests/Monolog/Processor/WebProcessorTest.php b/tests/Monolog/Processor/WebProcessorTest.php index 6da6ab89c..463dfd986 100644 --- a/tests/Monolog/Processor/WebProcessorTest.php +++ b/tests/Monolog/Processor/WebProcessorTest.php @@ -103,11 +103,10 @@ public function testProcessorConfiguringOfExtraFields() $this->assertSame(['url' => 'B'], $record['extra']); } - /** - * @expectedException UnexpectedValueException - */ public function testInvalidData() { + $this->expectException(\UnexpectedValueException::class); + new WebProcessor(new \stdClass); } } diff --git a/tests/Monolog/RegistryTest.php b/tests/Monolog/RegistryTest.php index 7ee2cbdf9..b917de864 100644 --- a/tests/Monolog/RegistryTest.php +++ b/tests/Monolog/RegistryTest.php @@ -13,7 +13,7 @@ class RegistryTest extends \PHPUnit\Framework\TestCase { - protected function setUp() + protected function setUp(): void { Registry::clear(); } @@ -114,11 +114,11 @@ public function testGetsSameLogger() } /** - * @expectedException \InvalidArgumentException * @covers Monolog\Registry::getInstance */ public function testFailsOnNonExistantLogger() { + $this->expectException(\InvalidArgumentException::class); Registry::getInstance('test1'); } @@ -138,11 +138,12 @@ public function testReplacesLogger() } /** - * @expectedException \InvalidArgumentException * @covers Monolog\Registry::addLogger */ public function testFailsOnUnspecifiedReplacement() { + $this->expectException(\InvalidArgumentException::class); + $log1 = new Logger('test1'); $log2 = new Logger('test2'); diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index 5169705a1..e73ad8fd3 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -26,7 +26,7 @@ class SignalHandlerTest extends TestCase private $blockedSignals; private $signalHandlers; - protected function setUp() + protected function setUp(): void { $this->signalHandlers = array(); if (extension_loaded('pcntl')) { @@ -39,7 +39,7 @@ protected function setUp() } } - protected function tearDown() + protected function tearDown(): void { if ($this->asyncSignalHandling !== null) { pcntl_async_signals($this->asyncSignalHandling); From d317cb97d3710b382631a5da881aa2eb50df35c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Bla=C5=BEek?= Date: Tue, 13 Aug 2019 15:34:48 +0200 Subject: [PATCH 154/498] Move expectException before the line where exception is thrown --- .../Formatter/GelfMessageFormatterTest.php | 4 +- .../Formatter/NormalizerFormatterTest.php | 5 ++- .../Handler/AbstractProcessingHandlerTest.php | 9 +++-- tests/Monolog/Handler/ElasticaHandlerTest.php | 5 ++- .../Handler/ElasticsearchHandlerTest.php | 5 ++- tests/Monolog/Handler/FilterHandlerTest.php | 5 ++- .../Handler/FingersCrossedHandlerTest.php | 5 ++- tests/Monolog/Handler/NewRelicHandlerTest.php | 3 +- tests/Monolog/Handler/ProcessHandlerTest.php | 8 ++-- tests/Monolog/Handler/SocketHandlerTest.php | 37 +++++++++++-------- tests/Monolog/Handler/SyslogHandlerTest.php | 2 +- tests/Monolog/LoggerTest.php | 15 +++++--- tests/Monolog/RegistryTest.php | 4 +- 13 files changed, 62 insertions(+), 45 deletions(-) diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index 9be4b3e67..3d58f58bb 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -86,14 +86,14 @@ public function testFormatWithFileAndLine() */ public function testFormatInvalidFails() { - $this->expectException(\InvalidArgumentException::class); - $formatter = new GelfMessageFormatter(); $record = [ 'level' => Logger::ERROR, 'level_name' => 'ERROR', ]; + $this->expectException(\InvalidArgumentException::class); + $formatter->format($record); } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index bc918543d..1725cd7ea 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -260,8 +260,6 @@ public function testNormalizeHandleLargeArrays() public function testThrowsOnInvalidEncoding() { - $this->expectException(\RuntimeException::class); - $formatter = new NormalizerFormatter(); $reflMethod = new \ReflectionMethod($formatter, 'toJson'); $reflMethod->setAccessible(true); @@ -269,6 +267,9 @@ public function testThrowsOnInvalidEncoding() // send an invalid unicode sequence as a object that can't be cleaned $record = new \stdClass; $record->message = "\xB1\x31"; + + $this->expectException(\RuntimeException::class); + $reflMethod->invoke($formatter, $record); } diff --git a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php index 0d3736d00..7d732b39d 100644 --- a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php +++ b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php @@ -96,8 +96,6 @@ public function testProcessRecord() */ public function testPushPopProcessor() { - $this->expectException(\LogicException::class); - $logger = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); $processor1 = new WebProcessor; $processor2 = new WebProcessor; @@ -107,6 +105,9 @@ public function testPushPopProcessor() $this->assertEquals($processor2, $logger->popProcessor()); $this->assertEquals($processor1, $logger->popProcessor()); + + $this->expectException(\LogicException::class); + $logger->popProcessor(); } @@ -115,10 +116,10 @@ public function testPushPopProcessor() */ public function testPushProcessorWithNonCallable() { - $this->expectException(\TypeError::class); - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler'); + $this->expectException(\TypeError::class); + $handler->pushProcessor(new \stdClass()); } diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index c456ec13a..453752f23 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -100,11 +100,12 @@ public function testSetFormatter() */ public function testSetFormatterInvalid() { + $handler = new ElasticaHandler($this->client); + $formatter = new NormalizerFormatter(); + $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('ElasticaHandler is only compatible with ElasticaFormatter'); - $handler = new ElasticaHandler($this->client); - $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); } diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 06599e453..2cc982b38 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -112,11 +112,12 @@ public function testSetFormatter() */ public function testSetFormatterInvalid() { + $handler = new ElasticsearchHandler($this->client); + $formatter = new NormalizerFormatter(); + $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); - $handler = new ElasticsearchHandler($this->client); - $formatter = new NormalizerFormatter(); $handler->setFormatter($formatter); } diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index db7157191..cacbd33a7 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -162,13 +162,14 @@ function ($record, $handler) use ($test) { */ public function testHandleWithBadCallbackThrowsException() { - $this->expectException(\RuntimeException::class); - $handler = new FilterHandler( function ($record, $handler) { return 'foo'; } ); + + $this->expectException(\RuntimeException::class); + $handler->handle($this->getRecord(Logger::WARNING)); } } diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index 75dc49af8..c649f00d3 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -132,11 +132,12 @@ public function testHandleWithCallback() */ public function testHandleWithBadCallbackThrowsException() { - $this->expectException(\RuntimeException::class); - $handler = new FingersCrossedHandler(function ($record, $handler) { return 'foo'; }); + + $this->expectException(\RuntimeException::class); + $handler->handle($this->getRecord(Logger::WARNING)); } diff --git a/tests/Monolog/Handler/NewRelicHandlerTest.php b/tests/Monolog/Handler/NewRelicHandlerTest.php index e4e4d70b3..a02a6efef 100644 --- a/tests/Monolog/Handler/NewRelicHandlerTest.php +++ b/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -30,9 +30,10 @@ public function setUp(): void public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded() { + $handler = new StubNewRelicHandlerWithoutExtension(); + $this->expectException(MissingExtensionException::class); - $handler = new StubNewRelicHandlerWithoutExtension(); $handler->handle($this->getRecord(Logger::ERROR)); } diff --git a/tests/Monolog/Handler/ProcessHandlerTest.php b/tests/Monolog/Handler/ProcessHandlerTest.php index c78d55902..fc1aff475 100644 --- a/tests/Monolog/Handler/ProcessHandlerTest.php +++ b/tests/Monolog/Handler/ProcessHandlerTest.php @@ -135,7 +135,7 @@ public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueEx ->method('selectErrorStream') ->will($this->returnValue(false)); - $this->expectException('\UnexpectedValueException'); + $this->expectException(\UnexpectedValueException::class); /** @var ProcessHandler $handler */ $handler->handle($this->getRecord(Logger::WARNING, 'stream failing, whoops')); } @@ -147,7 +147,9 @@ public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueEx public function testStartupWithErrorsThrowsUnexpectedValueException() { $handler = new ProcessHandler('>&2 echo "some fake error message"'); - $this->expectException('\UnexpectedValueException'); + + $this->expectException(\UnexpectedValueException::class); + $handler->handle($this->getRecord(Logger::WARNING, 'some warning in the house')); } @@ -167,7 +169,7 @@ public function testWritingWithErrorsOnStdOutOfProcessThrowsInvalidArgumentExcep ->method('readProcessErrors') ->willReturnOnConsecutiveCalls('', $this->returnValue('some fake error message here')); - $this->expectException('\UnexpectedValueException'); + $this->expectException(\UnexpectedValueException::class); /** @var ProcessHandler $handler */ $handler->handle($this->getRecord(Logger::WARNING, 'some test stuff')); } diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 48a2642ab..f1377f078 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -90,54 +90,57 @@ public function testSetConnectionString() public function testExceptionIsThrownOnFsockopenError() { - $this->expectException(\UnexpectedValueException::class); - $this->setMockHandler(['fsockopen']); $this->handler->expects($this->once()) ->method('fsockopen') ->will($this->returnValue(false)); + + $this->expectException(\UnexpectedValueException::class); + $this->writeRecord('Hello world'); } public function testExceptionIsThrownOnPfsockopenError() { - $this->expectException(\UnexpectedValueException::class); - $this->setMockHandler(['pfsockopen']); $this->handler->expects($this->once()) ->method('pfsockopen') ->will($this->returnValue(false)); + $this->handler->setPersistent(true); + + $this->expectException(\UnexpectedValueException::class); + $this->writeRecord('Hello world'); } public function testExceptionIsThrownIfCannotSetTimeout() { - $this->expectException(\UnexpectedValueException::class); - $this->setMockHandler(['streamSetTimeout']); $this->handler->expects($this->once()) ->method('streamSetTimeout') ->will($this->returnValue(false)); + + $this->expectException(\UnexpectedValueException::class); + $this->writeRecord('Hello world'); } public function testExceptionIsThrownIfCannotSetChunkSize() { - $this->expectException(\UnexpectedValueException::class); - $this->setMockHandler(array('streamSetChunkSize')); $this->handler->setChunkSize(8192); $this->handler->expects($this->once()) ->method('streamSetChunkSize') ->will($this->returnValue(false)); + + $this->expectException(\UnexpectedValueException::class); + $this->writeRecord('Hello world'); } public function testWriteFailsOnIfFwriteReturnsFalse() { - $this->expectException(\RuntimeException::class); - $this->setMockHandler(['fwrite']); $callback = function ($arg) { @@ -153,13 +156,13 @@ public function testWriteFailsOnIfFwriteReturnsFalse() ->method('fwrite') ->will($this->returnCallback($callback)); + $this->expectException(\RuntimeException::class); + $this->writeRecord('Hello world'); } public function testWriteFailsIfStreamTimesOut() { - $this->expectException(\RuntimeException::class); - $this->setMockHandler(['fwrite', 'streamGetMetadata']); $callback = function ($arg) { @@ -178,13 +181,13 @@ public function testWriteFailsIfStreamTimesOut() ->method('streamGetMetadata') ->will($this->returnValue(['timed_out' => true])); + $this->expectException(\RuntimeException::class); + $this->writeRecord('Hello world'); } public function testWriteFailsOnIncompleteWrite() { - $this->expectException(\RuntimeException::class); - $this->setMockHandler(['fwrite', 'streamGetMetadata']); $res = $this->res; @@ -201,6 +204,8 @@ public function testWriteFailsOnIncompleteWrite() ->method('streamGetMetadata') ->will($this->returnValue(['timed_out' => false])); + $this->expectException(\RuntimeException::class); + $this->writeRecord('Hello world'); } @@ -255,8 +260,6 @@ public function testCloseDoesNotClosePersistentSocket() public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds() { - $this->expectException(\RuntimeException::class); - $this->setMockHandler(['fwrite', 'streamGetMetadata']); $this->handler->expects($this->any()) @@ -269,6 +272,8 @@ public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSecond $this->handler->setWritingTimeout(1); + $this->expectException(\RuntimeException::class); + $this->writeRecord('Hello world'); } diff --git a/tests/Monolog/Handler/SyslogHandlerTest.php b/tests/Monolog/Handler/SyslogHandlerTest.php index 550e21050..5479d547a 100644 --- a/tests/Monolog/Handler/SyslogHandlerTest.php +++ b/tests/Monolog/Handler/SyslogHandlerTest.php @@ -38,7 +38,7 @@ public function testConstruct() */ public function testConstructInvalidFacility() { - $this->expectException('UnexpectedValueException'); + $this->expectException(\UnexpectedValueException::class); $handler = new SyslogHandler('test', 'unknown'); } } diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index deaa2c33b..0163fafa9 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -142,8 +142,6 @@ public function testProcessorsInCtor() */ public function testPushPopHandler() { - $this->expectException(\LogicException::class); - $logger = new Logger(__METHOD__); $handler1 = new TestHandler; $handler2 = new TestHandler; @@ -153,6 +151,9 @@ public function testPushPopHandler() $this->assertEquals($handler2, $logger->popHandler()); $this->assertEquals($handler1, $logger->popHandler()); + + $this->expectException(\LogicException::class); + $logger->popHandler(); } @@ -186,8 +187,6 @@ public function testSetHandlers() */ public function testPushPopProcessor() { - $this->expectException(\LogicException::class); - $logger = new Logger(__METHOD__); $processor1 = new WebProcessor; $processor2 = new WebProcessor; @@ -197,6 +196,9 @@ public function testPushPopProcessor() $this->assertEquals($processor2, $logger->popProcessor()); $this->assertEquals($processor1, $logger->popProcessor()); + + $this->expectException(\LogicException::class); + $logger->popProcessor(); } @@ -598,8 +600,6 @@ public function testSetExceptionHandler() */ public function testDefaultHandleException() { - $this->expectException(\Exception::class); - $logger = new Logger(__METHOD__); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); $handler->expects($this->any()) @@ -610,6 +610,9 @@ public function testDefaultHandleException() ->method('handle') ->will($this->throwException(new \Exception('Some handler exception'))) ; + + $this->expectException(\Exception::class); + $logger->pushHandler($handler); $logger->info('test'); } diff --git a/tests/Monolog/RegistryTest.php b/tests/Monolog/RegistryTest.php index b917de864..0ada5ee6a 100644 --- a/tests/Monolog/RegistryTest.php +++ b/tests/Monolog/RegistryTest.php @@ -142,13 +142,13 @@ public function testReplacesLogger() */ public function testFailsOnUnspecifiedReplacement() { - $this->expectException(\InvalidArgumentException::class); - $log1 = new Logger('test1'); $log2 = new Logger('test2'); Registry::addLogger($log1, 'log'); + $this->expectException(\InvalidArgumentException::class); + Registry::addLogger($log2, 'log'); } } From 021e5a5fe849b9d8cdff4c1d699e4445792a59ff Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Tue, 13 Aug 2019 16:54:43 +0200 Subject: [PATCH 155/498] Change the assert for counting test result values --- tests/Monolog/Handler/BufferHandlerTest.php | 2 +- tests/Monolog/Handler/FingersCrossedHandlerTest.php | 4 ++-- tests/Monolog/Handler/GroupHandlerTest.php | 6 +++--- tests/Monolog/Handler/WhatFailureGroupHandlerTest.php | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Monolog/Handler/BufferHandlerTest.php b/tests/Monolog/Handler/BufferHandlerTest.php index f1338b40d..4867d1826 100644 --- a/tests/Monolog/Handler/BufferHandlerTest.php +++ b/tests/Monolog/Handler/BufferHandlerTest.php @@ -33,7 +33,7 @@ public function testHandleBuffers() $this->assertFalse($test->hasInfoRecords()); $handler->close(); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); } /** diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index b545489c9..8ecbff808 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -35,7 +35,7 @@ public function testHandleBuffers() $handler->handle($this->getRecord(Logger::WARNING)); $handler->close(); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 3); + $this->assertCount(3, $test->getRecords()); } /** @@ -123,7 +123,7 @@ public function testHandleWithCallback() $this->assertFalse($test->hasInfoRecords()); $handler->handle($this->getRecord(Logger::WARNING)); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 3); + $this->assertCount(3, $test->getRecords()); } /** diff --git a/tests/Monolog/Handler/GroupHandlerTest.php b/tests/Monolog/Handler/GroupHandlerTest.php index 003c70147..b2a2713cb 100644 --- a/tests/Monolog/Handler/GroupHandlerTest.php +++ b/tests/Monolog/Handler/GroupHandlerTest.php @@ -38,7 +38,7 @@ public function testHandle() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); } } @@ -53,7 +53,7 @@ public function testHandleBatch() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); } } @@ -108,7 +108,7 @@ public function testHandleBatchUsesProcessors() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); $this->assertTrue($records[1]['extra']['foo']); diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 6aacdde54..185351fdb 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -38,7 +38,7 @@ public function testHandle() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); } } @@ -53,7 +53,7 @@ public function testHandleBatch() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); } } @@ -108,7 +108,7 @@ public function testHandleBatchUsesProcessors() foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); - $this->assertTrue(count($test->getRecords()) === 2); + $this->assertCount(2, $test->getRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); $this->assertTrue($records[1]['extra']['foo']); From ab236865a745f647c84aba68230a537fe13381d3 Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Tue, 13 Aug 2019 17:55:34 +0200 Subject: [PATCH 156/498] Add FallbackGroupHandler --- doc/02-handlers-formatters-processors.md | 5 + src/Monolog/Handler/FallbackGroupHandler.php | 63 ++++++++ .../Monolog/Handler/ExceptionTestHandler.php | 27 ++++ .../Handler/FallbackGroupHandlerTest.php | 141 ++++++++++++++++++ .../Handler/WhatFailureGroupHandlerTest.php | 13 -- 5 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 src/Monolog/Handler/FallbackGroupHandler.php create mode 100644 tests/Monolog/Handler/ExceptionTestHandler.php create mode 100644 tests/Monolog/Handler/FallbackGroupHandlerTest.php diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 7734132cc..a61bd584f 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -108,6 +108,11 @@ exceptions raised by each child handler. This allows you to ignore issues where a remote tcp connection may have died but you do not want your entire application to crash and may wish to continue to log to other handlers. +- [_FallbackGroupHandler_](../src/Monolog/Handler/FallbackGroupHandler.php): This handler extends the _GroupHandler_ ignoring + exceptions raised by each child handler, until one has handled without throwing. + This allows you to ignore issues where a remote tcp connection may have died + but you do not want your entire application to crash and may wish to continue + to attempt log to other handlers, until one does not throw. - [_BufferHandler_](../src/Monolog/Handler/BufferHandler.php): This handler will buffer all the log records it receives until `close()` is called at which point it will call `handleBatch()` on the handler it wraps with all the log messages at once. This is very useful to diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php new file mode 100644 index 000000000..728c4ed07 --- /dev/null +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Throwable; + +class FallbackGroupHandler extends GroupHandler +{ + /** + * {@inheritdoc} + */ + public function handle(array $record): bool + { + if ($this->processors) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + } + foreach ($this->handlers as $handler) { + try { + $handler->handle($record); + break; + } catch (Throwable $e) { + // What throwable? + } + } + return false === $this->bubble; + } + /** + * {@inheritdoc} + */ + public function handleBatch(array $records): void + { + if ($this->processors) { + $processed = []; + foreach ($records as $record) { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); + } + $processed[] = $record; + } + $records = $processed; + } + + foreach ($this->handlers as $handler) { + try { + $handler->handleBatch($records); + break; + } catch (Throwable $e) { + // What throwable? + } + } + } +} diff --git a/tests/Monolog/Handler/ExceptionTestHandler.php b/tests/Monolog/Handler/ExceptionTestHandler.php new file mode 100644 index 000000000..f5a682ef4 --- /dev/null +++ b/tests/Monolog/Handler/ExceptionTestHandler.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Exception; + +class ExceptionTestHandler extends TestHandler +{ + /** + * {@inheritdoc} + */ + public function handle(array $record): bool + { + throw new Exception("ExceptionTestHandler::handle"); + + parent::handle($record); + } +} diff --git a/tests/Monolog/Handler/FallbackGroupHandlerTest.php b/tests/Monolog/Handler/FallbackGroupHandlerTest.php new file mode 100644 index 000000000..f92a5afea --- /dev/null +++ b/tests/Monolog/Handler/FallbackGroupHandlerTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Test\TestCase; + +class FallbackGroupHandlerTest extends TestCase +{ + /** + * @covers Monolog\Handler\FallbackGroupHandler::__construct + * @covers Monolog\Handler\FallbackGroupHandler::handle + */ + public function testHandle() + { + $testHandlerOne = new TestHandler(); + $testHandlerTwo = new TestHandler(); + $testHandlers = [$testHandlerOne, $testHandlerTwo]; + $handler = new FallbackGroupHandler($testHandlers); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + + $this->assertCount(2, $testHandlerOne->getRecords()); + $this->assertCount(0, $testHandlerTwo->getRecords()); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::__construct + * @covers Monolog\Handler\FallbackGroupHandler::handle + */ + public function testHandleExceptionThrown() + { + $testHandlerOne = new ExceptionTestHandler(); + $testHandlerTwo = new TestHandler(); + $testHandlers = [$testHandlerOne, $testHandlerTwo]; + $handler = new FallbackGroupHandler($testHandlers); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::INFO)); + + $this->assertCount(0, $testHandlerOne->getRecords()); + $this->assertCount(2, $testHandlerTwo->getRecords()); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::handleBatch + */ + public function testHandleBatch() + { + $testHandlerOne = new TestHandler(); + $testHandlerTwo = new TestHandler(); + $testHandlers = [$testHandlerOne, $testHandlerTwo]; + $handler = new FallbackGroupHandler($testHandlers); + $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $this->assertCount(2, $testHandlerOne->getRecords()); + $this->assertCount(0, $testHandlerTwo->getRecords()); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::handleBatch + */ + public function testHandleBatchExceptionThrown() + { + $testHandlerOne = new ExceptionTestHandler(); + $testHandlerTwo = new TestHandler(); + $testHandlers = [$testHandlerOne, $testHandlerTwo]; + $handler = new FallbackGroupHandler($testHandlers); + $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $this->assertCount(0, $testHandlerOne->getRecords()); + $this->assertCount(2, $testHandlerTwo->getRecords()); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::isHandling + */ + public function testIsHandling() + { + $testHandlers = [new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)]; + $handler = new FallbackGroupHandler($testHandlers); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); + $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); + $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::handle + */ + public function testHandleUsesProcessors() + { + $test = new TestHandler(); + $handler = new FallbackGroupHandler([$test]); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->handle($this->getRecord(Logger::WARNING)); + $this->assertTrue($test->hasWarningRecords()); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + } + + /** + * @covers Monolog\Handler\FallbackGroupHandler::handleBatch + */ + public function testHandleBatchUsesProcessors() + { + $testHandlerOne = new ExceptionTestHandler(); + $testHandlerTwo = new TestHandler(); + $testHandlers = [$testHandlerOne, $testHandlerTwo]; + $handler = new FallbackGroupHandler($testHandlers); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->pushProcessor(function ($record) { + $record['extra']['foo2'] = true; + + return $record; + }); + $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $this->assertEmpty($testHandlerOne->getRecords()); + $this->assertTrue($testHandlerTwo->hasDebugRecords()); + $this->assertTrue($testHandlerTwo->hasInfoRecords()); + $this->assertCount(2, $testHandlerTwo->getRecords()); + $records = $testHandlerTwo->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + $this->assertTrue($records[1]['extra']['foo']); + $this->assertTrue($records[0]['extra']['foo2']); + $this->assertTrue($records[1]['extra']['foo2']); + } +} diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 6aacdde54..24365659f 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -136,16 +136,3 @@ public function testHandleException() $this->assertTrue($records[0]['extra']['foo']); } } - -class ExceptionTestHandler extends TestHandler -{ - /** - * {@inheritdoc} - */ - public function handle(array $record): bool - { - parent::handle($record); - - throw new \Exception("ExceptionTestHandler::handle"); - } -} From a5876bed1d0f49770acd35feceae3388480b6c55 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 14 Aug 2019 17:34:54 +0200 Subject: [PATCH 157/498] Add explicity void return type to Monolog\Logger --- src/Monolog/Logger.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 517e99960..a8e97870e 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -466,7 +466,7 @@ public function getExceptionHandler(): ?callable * @param string $message The log message * @param array $context The log context */ - public function log($level, $message, array $context = []) + public function log($level, $message, array $context = []): void { $level = static::toMonologLevel($level); @@ -481,7 +481,7 @@ public function log($level, $message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function debug($message, array $context = []) + public function debug($message, array $context = []): void { $this->addRecord(static::DEBUG, (string) $message, $context); } @@ -494,7 +494,7 @@ public function debug($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function info($message, array $context = []) + public function info($message, array $context = []): void { $this->addRecord(static::INFO, (string) $message, $context); } @@ -507,7 +507,7 @@ public function info($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function notice($message, array $context = []) + public function notice($message, array $context = []): void { $this->addRecord(static::NOTICE, (string) $message, $context); } @@ -520,7 +520,7 @@ public function notice($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function warning($message, array $context = []) + public function warning($message, array $context = []): void { $this->addRecord(static::WARNING, (string) $message, $context); } @@ -533,7 +533,7 @@ public function warning($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function error($message, array $context = []) + public function error($message, array $context = []): void { $this->addRecord(static::ERROR, (string) $message, $context); } @@ -546,7 +546,7 @@ public function error($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function critical($message, array $context = []) + public function critical($message, array $context = []): void { $this->addRecord(static::CRITICAL, (string) $message, $context); } @@ -559,7 +559,7 @@ public function critical($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function alert($message, array $context = []) + public function alert($message, array $context = []): void { $this->addRecord(static::ALERT, (string) $message, $context); } @@ -572,7 +572,7 @@ public function alert($message, array $context = []) * @param string $message The log message * @param array $context The log context */ - public function emergency($message, array $context = []) + public function emergency($message, array $context = []): void { $this->addRecord(static::EMERGENCY, (string) $message, $context); } From 5fea290626d98bd8746d010b54f07bf1faf7ad4e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Aug 2019 21:20:20 +0200 Subject: [PATCH 158/498] Fix GroupHandler/WhatFailureGroupHandler to use ProcessableHandlerTrait helper always --- src/Monolog/Handler/GroupHandler.php | 5 +---- src/Monolog/Handler/WhatFailureGroupHandler.php | 9 ++------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 5f6d4344b..51218568c 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -80,10 +80,7 @@ public function handleBatch(array $records): void if ($this->processors) { $processed = []; foreach ($records as $record) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - $processed[] = $record; + $processed[] = $this->processRecord($record); } $records = $processed; } diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index e8abbd644..16c3cbbb5 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -25,9 +25,7 @@ class WhatFailureGroupHandler extends GroupHandler public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -49,10 +47,7 @@ public function handleBatch(array $records): void if ($this->processors) { $processed = array(); foreach ($records as $record) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - $processed[] = $record; + $processed[] = $this->processRecord($record); } $records = $processed; } From 144f2299edaeec7621856dfec56ccbf088479951 Mon Sep 17 00:00:00 2001 From: Pierre Lannoy Date: Thu, 15 Aug 2019 23:23:59 +0200 Subject: [PATCH 159/498] Improvement for the fix To follow @Seldaek improvement recommendations. Sorry for the rookie mistakes :) --- src/Monolog/Handler/SyslogUdpHandler.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index c6badac6f..187211749 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -82,7 +82,7 @@ private function splitMessageIntoLines($message): array /** * Make common syslog header (see rfc5424 or rfc3164) */ - protected function makeCommonSyslogHeader(int $severity, DateTimeImmutable $datetime): string + protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $datetime): string { $priority = $severity + $this->facility; @@ -95,12 +95,12 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeImmutable $date } if ($this->rfc === self::RFC3164) { - $datetime->setTimezone(new \DateTimeZone('UTC')); - } - $date = $datetime->format($this->dateFormats[$this->rfc]); + $datetime->setTimezone(new \DateTimeZone('UTC')); + } + $date = $datetime->format($this->dateFormats[$this->rfc]); - if ($this->rfc === self::RFC3164) { - return "<$priority>" . + if ($this->rfc === self::RFC3164) { + return "<$priority>" . $date . " " . $hostname . " " . $this->ident . "[" . $pid . "]: "; @@ -113,11 +113,6 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeImmutable $date } } - protected function getDateTime(): string - { - return date($this->dateFormats[$this->rfc]); - } - /** * Inject your own socket, mainly used for testing */ From b615b158e4948c707eeb47df2af9773bc02ec4cb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Aug 2019 09:13:44 +0200 Subject: [PATCH 160/498] Fix class import and indenting --- src/Monolog/Handler/SyslogUdpHandler.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 187211749..c85ef5b82 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\DateTimeImmutable; +use DateTimeInterface; use Monolog\Logger; use Monolog\Handler\SyslogUdp\UdpSocket; @@ -95,11 +95,11 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $date } if ($this->rfc === self::RFC3164) { - $datetime->setTimezone(new \DateTimeZone('UTC')); - } - $date = $datetime->format($this->dateFormats[$this->rfc]); + $datetime->setTimezone(new \DateTimeZone('UTC')); + } + $date = $datetime->format($this->dateFormats[$this->rfc]); - if ($this->rfc === self::RFC3164) { + if ($this->rfc === self::RFC3164) { return "<$priority>" . $date . " " . $hostname . " " . From 2eefb0596d3f92bcd2526635fea837800c5d836b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Aug 2019 09:46:27 +0200 Subject: [PATCH 161/498] Fix tests, refs #1352 --- tests/Monolog/Handler/SyslogUdpHandlerTest.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 4d0e114cb..6c346e483 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -27,20 +27,13 @@ public function testWeValidateFacilities() public function testWeSplitIntoLines() { - $time = '2014-01-07T12:34'; $pid = getmypid(); $host = gethostname(); - $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') - ->setConstructorArgs(array("127.0.0.1", 514, "authpriv")) - ->setMethods(array('getDateTime')) - ->getMock(); - - $handler->method('getDateTime') - ->willReturn($time); - + $handler = new \Monolog\Handler\SyslogUdpHandler("127.0.0.1", 514, "authpriv"); $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); + $time = '2014-01-07T12:34:56+00:00'; $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->setMethods(['write']) ->setConstructorArgs(['lol']) @@ -77,7 +70,7 @@ public function testSplitWorksOnEmptyMsg() public function testRfc() { - $time = 'Mar 22 21:16:47'; + $time = 'Jan 07 12:34:56'; $pid = getmypid(); $host = gethostname(); @@ -109,6 +102,6 @@ public function testRfc() protected function getRecordWithMessage($msg) { - return ['message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => [], 'channel' => 'lol']; + return ['message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => [], 'channel' => 'lol', 'datetime' => new \DateTimeImmutable('2014-01-07 12:34:56')]; } } From 1b5341b08b1e54db0a3b6449683465d1d5bc4db8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Aug 2019 12:54:42 +0200 Subject: [PATCH 162/498] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2fe55e8..e0bb7ab8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records * Fixed issue in SignalHandler restarting syscalls functionality + * Fixed ZendMonitorHandler to work with the latest Zend Server versions ### 1.24.0 (2018-11-05) From 4976375873b2f284b629cfe4f3af1286d2762470 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Aug 2019 13:00:02 +0200 Subject: [PATCH 163/498] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d306f969..c7733ac33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### 2.0.0 (xx) + + * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release + * BC Break: Logger methods log/debug/info/notice/warning/error/critical/alert/emergency now have explicit void return types + * Added FallbackGroupHandler which works like the WhatFailureGroupHandler but stops dispatching log records as soon as one handler accepted it + * Fixed date timezone handling in SyslogUdpHandler + ### 2.0.0-beta2 (2019-07-06) * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release From 6688b45ebece577217cf4a2b9094caa6925ce684 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Aug 2019 12:34:04 +0200 Subject: [PATCH 164/498] Normalize the way backtraces are normalized and remove args for special cases, fixes #1346 --- CHANGELOG.md | 1 + src/Monolog/Formatter/JsonFormatter.php | 6 +---- src/Monolog/Formatter/NormalizerFormatter.php | 17 +------------- .../Formatter/NormalizerFormatterTest.php | 23 ++++++------------- .../Monolog/Formatter/ScalarFormatterTest.php | 2 +- 5 files changed, 11 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2fe55e8..2b95161dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records * Fixed issue in SignalHandler restarting syscalls functionality + * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases ### 1.24.0 (2018-11-05) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 9bd305f23..d6ab98fec 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -195,12 +195,8 @@ protected function normalizeException($e) foreach ($trace as $frame) { if (isset($frame['file'])) { $data['trace'][] = $frame['file'].':'.$frame['line']; - } elseif (isset($frame['function']) && $frame['function'] === '{closure}') { - // We should again normalize the frames, because it might contain invalid items - $data['trace'][] = $frame['function']; } else { - // We should again normalize the frames, because it might contain invalid items - $data['trace'][] = $this->normalize($frame); + $data['trace'][] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 668665789..43f1bf6a1 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -151,23 +151,8 @@ protected function normalizeException($e) foreach ($trace as $frame) { if (isset($frame['file'])) { $data['trace'][] = $frame['file'].':'.$frame['line']; - } elseif (isset($frame['function']) && $frame['function'] === '{closure}') { - // Simplify closures handling - $data['trace'][] = $frame['function']; } else { - if (isset($frame['args'])) { - // Make sure that objects present as arguments are not serialized nicely but rather only - // as a class name to avoid any unexpected leak of sensitive information - $frame['args'] = array_map(function ($arg) { - if (is_object($arg) && !($arg instanceof \DateTime || $arg instanceof \DateTimeInterface)) { - return sprintf("[object] (%s)", Utils::getClass($arg)); - } - - return $arg; - }, $frame['args']); - } - // We should again normalize the frames, because it might contain invalid items - $data['trace'][] = $this->toJson($this->normalize($frame), true); + $data['trace'][] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index bafd1c74b..9f0c445a5 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -390,21 +390,12 @@ public function testExceptionTraceWithArgs() $record = array('context' => array('exception' => $e)); $result = $formatter->format($record); - $this->assertRegExp( - '%"resource":"\[resource\] \(stream\)"%', - $result['context']['exception']['trace'][0] - ); - - if (version_compare(PHP_VERSION, '5.5.0', '>=')) { - $pattern = '%"wrappedResource":"\[object\] \(Monolog\\\\\\\\Formatter\\\\\\\\TestFooNorm: \)"%'; - } else { - $pattern = '%\\\\"foo\\\\":null%'; - } - - // Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4 - $this->assertRegExp( - $pattern, - $result['context']['exception']['trace'][0] + $this->assertSame( + array( + PHP_VERSION_ID < 50400 ? 'Monolog\Formatter\{closure}' : 'Monolog\Formatter\NormalizerFormatterTest->Monolog\Formatter\{closure}', + __FILE__.':'.(__LINE__-12), + ), + array_slice($result['context']['exception']['trace'], 0, 2) ); } @@ -421,7 +412,7 @@ public function testExceptionTraceDoesNotLeakCallUserFuncArgs() $result = $formatter->format($record); $this->assertSame( - '{"function":"throwHelper","class":"Monolog\\\\Formatter\\\\NormalizerFormatterTest","type":"->","args":["[object] (Monolog\\\\Formatter\\\\TestInfoLeak)","'.$dt->format('Y-m-d H:i:s').'"]}', + 'Monolog\\Formatter\\NormalizerFormatterTest->throwHelper', $result['context']['exception']['trace'][0] ); } diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index b1c8fd491..88509422c 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -28,7 +28,7 @@ public function buildTrace(\Exception $e) if (isset($frame['file'])) { $data[] = $frame['file'].':'.$frame['line']; } else { - $data[] = json_encode($frame); + $data[] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } From 2efcbcd181a119d948a729bedfb83a462bdfa95d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 30 Aug 2019 10:24:17 +0200 Subject: [PATCH 165/498] Remove closure stack frames entirely from log --- src/Monolog/Formatter/JsonFormatter.php | 2 -- src/Monolog/Formatter/NormalizerFormatter.php | 2 -- tests/Monolog/Formatter/NormalizerFormatterTest.php | 9 +++------ tests/Monolog/Formatter/ScalarFormatterTest.php | 2 -- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index d6ab98fec..2ff119eaa 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -195,8 +195,6 @@ protected function normalizeException($e) foreach ($trace as $frame) { if (isset($frame['file'])) { $data['trace'][] = $frame['file'].':'.$frame['line']; - } else { - $data['trace'][] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 43f1bf6a1..9865394e0 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -151,8 +151,6 @@ protected function normalizeException($e) foreach ($trace as $frame) { if (isset($frame['file'])) { $data['trace'][] = $frame['file'].':'.$frame['line']; - } else { - $data['trace'][] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 9f0c445a5..d4e0d98de 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -391,11 +391,8 @@ public function testExceptionTraceWithArgs() $result = $formatter->format($record); $this->assertSame( - array( - PHP_VERSION_ID < 50400 ? 'Monolog\Formatter\{closure}' : 'Monolog\Formatter\NormalizerFormatterTest->Monolog\Formatter\{closure}', - __FILE__.':'.(__LINE__-12), - ), - array_slice($result['context']['exception']['trace'], 0, 2) + __FILE__.':'.(__LINE__-10), + $result['context']['exception']['trace'][0] ); } @@ -412,7 +409,7 @@ public function testExceptionTraceDoesNotLeakCallUserFuncArgs() $result = $formatter->format($record); $this->assertSame( - 'Monolog\\Formatter\\NormalizerFormatterTest->throwHelper', + __FILE__ .':'.(__LINE__-9), $result['context']['exception']['trace'][0] ); } diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index 88509422c..2d7e6340c 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -27,8 +27,6 @@ public function buildTrace(\Exception $e) foreach ($trace as $frame) { if (isset($frame['file'])) { $data[] = $frame['file'].':'.$frame['line']; - } else { - $data[] = (!empty($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; } } From 57b286f3d1bfbc7a17eef0c70813b91d706b95ca Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 30 Aug 2019 10:40:17 +0200 Subject: [PATCH 166/498] Reuse normalizeException from NormalizerFormatter in JsonFormatter, fixes #1366 --- src/Monolog/Formatter/JsonFormatter.php | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 45fbe13fe..de1f69645 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -166,24 +166,9 @@ protected function normalize($data, int $depth = 0) */ protected function normalizeException(Throwable $e, int $depth = 0): array { - $data = [ - 'class' => Utils::getClass($e), - 'message' => $e->getMessage(), - 'code' => $e->getCode(), - 'file' => $e->getFile().':'.$e->getLine(), - ]; - - if ($this->includeStacktraces) { - $trace = $e->getTrace(); - foreach ($trace as $frame) { - if (isset($frame['file'])) { - $data['trace'][] = $frame['file'].':'.$frame['line']; - } - } - } - - if ($previous = $e->getPrevious()) { - $data['previous'] = $this->normalizeException($previous, $depth + 1); + $data = parent::normalizeException($e, $depth); + if (!$this->includeStacktraces) { + unset($data['trace']); } return $data; From f954b4ea842b4ad5419e0705be9a20c88c586890 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 30 Aug 2019 11:46:18 +0200 Subject: [PATCH 167/498] Update changelog --- CHANGELOG.md | 5 ++++- tests/Monolog/Handler/RedisHandlerTest.php | 9 +++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e587d6879..e0d995ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ -### 2.0.0 (xx) +### 2.0.0 (2019-08-30) * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release * BC Break: Logger methods log/debug/info/notice/warning/error/critical/alert/emergency now have explicit void return types * Added FallbackGroupHandler which works like the WhatFailureGroupHandler but stops dispatching log records as soon as one handler accepted it + * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler + * Fixed support for UTF-8 when cutting strings to avoid cutting a multibyte-character in half + * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases * Fixed date timezone handling in SyslogUdpHandler ### 2.0.0-beta2 (2019-07-06) diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index 19f2bbc7f..b6cc8524e 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -42,12 +42,9 @@ public function testConstructorShouldWorkWithRedis() public function testPredisHandle() { - $redis = $this->createPartialMock('Predis\Client', ['rPush']); - - // Predis\Client uses rPush - $redis->expects($this->once()) - ->method('rPush') - ->with('key', 'test'); + $redis = $this->prophesize('Predis\Client'); + $redis->rpush('key', 'test')->shouldBeCalled(); + $redis = $redis->reveal(); $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); From 68545165e19249013afd1d6f7485aecff07a2d22 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 30 Aug 2019 11:56:44 +0200 Subject: [PATCH 168/498] Update changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0d995ea7..3005e384f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release * BC Break: Logger methods log/debug/info/notice/warning/error/critical/alert/emergency now have explicit void return types * Added FallbackGroupHandler which works like the WhatFailureGroupHandler but stops dispatching log records as soon as one handler accepted it - * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler * Fixed support for UTF-8 when cutting strings to avoid cutting a multibyte-character in half * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases * Fixed date timezone handling in SyslogUdpHandler From f4026e73c9f5aad57f204c76d49a584033149302 Mon Sep 17 00:00:00 2001 From: Paul Vogel Date: Fri, 30 Aug 2019 14:03:35 +0200 Subject: [PATCH 169/498] Use svg for build status directly from travis-ci Since there is no reason to use shields for the build status badge we can use it directly from travis-ci --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a81a4246..a8cbd642b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Monolog - Logging for PHP [![Build Status](https://img.shields.io/travis/Seldaek/monolog.svg)](https://travis-ci.org/Seldaek/monolog) +# Monolog - Logging for PHP [![Build Status](https://travis-ci.org/Seldaek/monolog.svg?branch=master)](https://travis-ci.org/Seldaek/monolog) [![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) From 0ffb4e2811a7c27ccf2ec3421acbd07293c3470d Mon Sep 17 00:00:00 2001 From: Gabriel Machado Date: Sat, 31 Aug 2019 20:17:38 -0300 Subject: [PATCH 170/498] update exception message in InsightOpsHandler --- src/Monolog/Handler/InsightOpsHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index a12e3de56..8f683dce5 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -38,7 +38,7 @@ class InsightOpsHandler extends SocketHandler public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true) { if ($useSSL && !extension_loaded('openssl')) { - throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); + throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler'); } $endpoint = $useSSL From 6d76eaaf7699d6bab1609b0a5abcc9d2326ad566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 19 Aug 2019 17:57:34 +0200 Subject: [PATCH 171/498] Backport Interface and Trait from master to 1.X --- .php_cs | 6 ++ composer.json | 2 +- .../Handler/FormattableHandlerInterface.php | 38 ++++++++++ .../Handler/FormattableHandlerTrait.php | 62 ++++++++++++++++ .../Handler/ProcessableHandlerInterface.php | 39 ++++++++++ .../Handler/ProcessableHandlerTrait.php | 72 +++++++++++++++++++ 6 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 src/Monolog/Handler/FormattableHandlerInterface.php create mode 100644 src/Monolog/Handler/FormattableHandlerTrait.php create mode 100644 src/Monolog/Handler/ProcessableHandlerInterface.php create mode 100644 src/Monolog/Handler/ProcessableHandlerTrait.php diff --git a/.php_cs b/.php_cs index 366ccd08b..fe3c5bff0 100644 --- a/.php_cs +++ b/.php_cs @@ -13,6 +13,12 @@ $finder = Symfony\CS\Finder::create() ->files() ->name('*.php') ->exclude('Fixtures') + // The next 4 files are here for forward compatibility, and are not used by + // Monolog itself + ->exclude(__DIR__.'src/Monolog/Handler/FormattableHandlerInterface.php') + ->exclude(__DIR__.'src/Monolog/Handler/FormattableHandlerTrait.php') + ->exclude(__DIR__.'src/Monolog/Handler/ProcessableHandlerInterface.php') + ->exclude(__DIR__.'src/Monolog/Handler/ProcessableHandlerTrait.php') ->in(__DIR__.'/src') ->in(__DIR__.'/tests') ; diff --git a/composer.json b/composer.json index 3b0c88055..097df8787 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ }, "scripts": { "test": [ - "parallel-lint . --exclude vendor", + "parallel-lint . --exclude vendor --exclude src/Monolog/Handler/FormattableHandlerInterface.php --exclude src/Monolog/Handler/FormattableHandlerTrait.php --exclude src/Monolog/Handler/ProcessableHandlerInterface.php --exclude src/Monolog/Handler/ProcessableHandlerTrait.php", "phpunit" ] } diff --git a/src/Monolog/Handler/FormattableHandlerInterface.php b/src/Monolog/Handler/FormattableHandlerInterface.php new file mode 100644 index 000000000..b6d4c6acb --- /dev/null +++ b/src/Monolog/Handler/FormattableHandlerInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; + +/** + * Interface to describe loggers that have a formatter + * + * @internal This interface is present in monolog 1.x to ease forward compatibility. + * @author Jordi Boggiano + */ +interface FormattableHandlerInterface +{ + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + * @return HandlerInterface self + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface; + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(): FormatterInterface; +} diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php new file mode 100644 index 000000000..5233bf55a --- /dev/null +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; + +/** + * Helper trait for implementing FormattableInterface + * + * @internal This interface is present in monolog 1.x to ease forward compatibility. + * @author Jordi Boggiano + */ +trait FormattableHandlerTrait +{ + /** + * @var FormatterInterface + */ + protected $formatter; + + /** + * {@inheritdoc} + * @suppress PhanTypeMismatchReturn + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->formatter = $formatter; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter(): FormatterInterface + { + if (!$this->formatter) { + $this->formatter = $this->getDefaultFormatter(); + } + + return $this->formatter; + } + + /** + * Gets the default formatter. + * + * Overwrite this if the LineFormatter is not a good default for your handler. + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new LineFormatter(); + } +} diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php new file mode 100644 index 000000000..bfa714975 --- /dev/null +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Processor\ProcessorInterface; + +/** + * Interface to describe loggers that have processors + * + * @internal This interface is present in monolog 1.x to ease forward compatibility. + * @author Jordi Boggiano + */ +interface ProcessableHandlerInterface +{ + /** + * Adds a processor in the stack. + * + * @param ProcessorInterface|callable $callback + * @return HandlerInterface self + */ + public function pushProcessor(callable $callback): HandlerInterface; + + /** + * Removes the processor on top of the stack and returns it. + * + * @throws \LogicException In case the processor stack is empty + * @return callable + */ + public function popProcessor(): callable; +} diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php new file mode 100644 index 000000000..a5092929e --- /dev/null +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\ResettableInterface; + +/** + * Helper trait for implementing ProcessableInterface + * + * @internal This interface is present in monolog 1.x to ease forward compatibility. + * @author Jordi Boggiano + */ +trait ProcessableHandlerTrait +{ + /** + * @var callable[] + */ + protected $processors = []; + + /** + * {@inheritdoc} + * @suppress PhanTypeMismatchReturn + */ + public function pushProcessor(callable $callback): HandlerInterface + { + array_unshift($this->processors, $callback); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function popProcessor(): callable + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * Processes a record. + */ + protected function processRecord(array $record): array + { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + + return $record; + } + + protected function resetProcessors(): void + { + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } +} From 012f8cd194bc95a2cdfe2d6ada9ab90f4be31d66 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 5 Sep 2019 12:13:19 +0200 Subject: [PATCH 172/498] Remove versions from Laravel integration We recently released v6.0 so maybe we shouldn't mention the versions anymore. Monolog will probably always remain with the framework. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a8cbd642b..61216153f 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) can be used very easily with Monolog since it implements the interface. - [Symfony](http://symfony.com) comes out of the box with Monolog. -- [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog. +- [Laravel](http://laravel.com/) comes out of the box with Monolog. - [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog. - [PPI](https://github.com/ppi/framework) comes out of the box with Monolog. - [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin. From c8b0d08cebfaee16569b0e5a9a80911cc238fe1d Mon Sep 17 00:00:00 2001 From: Pierre Lannoy Date: Thu, 5 Sep 2019 13:28:42 +0200 Subject: [PATCH 173/498] Change chrome header size limit Due to change in chromium header size support, the size limit enforced by the handler must be decreased. --- src/Monolog/Handler/ChromePHPHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 37419a061..ac98d5dea 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -43,7 +43,7 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Tracks whether we sent too much data * - * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending + * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending * * @var bool */ @@ -136,7 +136,7 @@ protected function send() $json = @json_encode(self::$json); $data = base64_encode(utf8_encode($json)); - if (strlen($data) > 240 * 1024) { + if (strlen($data) > 3 * 1024) { self::$overflowed = true; $record = array( From 190aa65aac9062072baaac39a079c6dbdc4feb8d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Sep 2019 14:33:55 +0200 Subject: [PATCH 174/498] Fix chromephp tests --- tests/Monolog/Handler/ChromePHPHandlerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 421cc4918..bb1b07920 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -66,10 +66,10 @@ public function testHeadersOverflow() { $handler = new TestChromePHPHandler(); $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 150 * 1024))); + $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 2 * 1024))); // overflow chrome headers limit - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 100 * 1024))); + $handler->handle($this->getRecord(Logger::WARNING, str_repeat('b', 2 * 1024))); $expected = array( 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode(array( @@ -84,7 +84,7 @@ public function testHeadersOverflow() ), array( 'test', - str_repeat('a', 150 * 1024), + str_repeat('a', 2 * 1024), 'unknown', 'warn', ), From 4bfd34158614935aeca338643a620c8d6f262f88 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Sep 2019 14:38:03 +0200 Subject: [PATCH 175/498] Fix type error, fixes #1369 --- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- tests/Monolog/Handler/BrowserConsoleHandlerTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 4dff9f24f..04fb1268c 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -217,7 +217,7 @@ private static function dump(string $title, array $dict): array if (empty($value)) { $value = static::quote(''); } - $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value); + $script[] = static::call('log', static::quote('%s: %o'), static::quote((string) $key), $value); } return $script; diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index 57b4cc773..e0cd6e3db 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -89,13 +89,14 @@ public function testContext() $handler = new BrowserConsoleHandler(); $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, 'test', ['foo' => 'bar'])); + $handler->handle($this->getRecord(Logger::DEBUG, 'test', ['foo' => 'bar', 0 => 'oop'])); $expected = << Date: Thu, 5 Sep 2019 14:47:40 +0200 Subject: [PATCH 176/498] Avoid leaving an error handler dangling --- tests/Monolog/ErrorHandlerTest.php | 32 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 9a8a5be03..8cc591da5 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -28,18 +28,26 @@ public function testHandleError() $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new ErrorHandler($logger); - $resHandler = $errHandler->registerErrorHandler([E_USER_NOTICE => Logger::EMERGENCY], false); - $this->assertSame($errHandler, $resHandler); - trigger_error('Foo', E_USER_ERROR); - $this->assertCount(1, $handler->getRecords()); - $this->assertTrue($handler->hasErrorRecords()); - trigger_error('Foo', E_USER_NOTICE); - $this->assertCount(2, $handler->getRecords()); - $this->assertTrue($handler->hasEmergencyRecords()); - - $errHandler->registerErrorHandler([], true); - $prop = $this->getPrivatePropertyValue($errHandler, 'previousErrorHandler'); - $this->assertTrue(is_callable($prop)); + $phpunitHandler = set_error_handler($prevHandler = function() {}); + + try { + $errHandler->registerErrorHandler([], true); + $prop = $this->getPrivatePropertyValue($errHandler, 'previousErrorHandler'); + $this->assertTrue(is_callable($prop)); + $this->assertSame($prevHandler, $prop); + + $resHandler = $errHandler->registerErrorHandler([E_USER_NOTICE => Logger::EMERGENCY], false); + $this->assertSame($errHandler, $resHandler); + trigger_error('Foo', E_USER_ERROR); + $this->assertCount(1, $handler->getRecords()); + $this->assertTrue($handler->hasErrorRecords()); + trigger_error('Foo', E_USER_NOTICE); + $this->assertCount(2, $handler->getRecords()); + $this->assertTrue($handler->hasEmergencyRecords()); + } finally { + // restore previous handler + set_error_handler($phpunitHandler); + } } public function fatalHandlerProvider() From edaa01a66fb450e194eb8c296cbb9fb5b90df0b0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 5 Sep 2019 14:53:43 +0200 Subject: [PATCH 177/498] Add issue template --- .github/ISSUE_TEMPLATE.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..46e6e8dec --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,3 @@ +I am using Monolog version 1|2 + +... the problem/suggestion/question here ... From c5dcc05defbaf8780c728c1ea31b1a0704d44f56 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 6 Sep 2019 14:21:24 +0200 Subject: [PATCH 178/498] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d78779a00..1673dc8f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,15 @@ -### 1.25.0 (xx) +### 1.25.0 (2019-09-06) * Deprecated SlackbotHandler, use SlackWebhookHandler or SlackHandler instead * Deprecated RavenHandler, use sentry/sentry 2.x and their Sentry\Monolog\Handler instead * Deprecated HipChatHandler, migrate to Slack and use SlackWebhookHandler or SlackHandler instead + * Added forward-compatible interfaces and traits FormattableHandlerInterface, FormattableHandlerTrait, ProcessableHandlerInterface, ProcessableHandlerTrait. If you use modern PHP and want to make code compatible with Monolog 1 and 2 this can help. You will have to require at least Monolog 1.25 though. * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records * Fixed issue in SignalHandler restarting syscalls functionality * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases * Fixed ZendMonitorHandler to work with the latest Zend Server versions + * Fixed ChromePHPHandler to avoid sending more data than latest Chrome versions allow in headers (4KB down from 256KB). ### 1.24.0 (2018-11-05) From 626bde615905ba99ccbe8a3d0da558434fc28aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Fri, 6 Sep 2019 14:55:25 +0200 Subject: [PATCH 179/498] Fixed forward compatibilty layer --- src/Monolog/Handler/FormattableHandlerInterface.php | 3 ++- src/Monolog/Handler/FormattableHandlerTrait.php | 3 ++- src/Monolog/Handler/ProcessableHandlerInterface.php | 5 +++-- src/Monolog/Handler/ProcessableHandlerTrait.php | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/FormattableHandlerInterface.php b/src/Monolog/Handler/FormattableHandlerInterface.php index b6d4c6acb..3e2f1b28a 100644 --- a/src/Monolog/Handler/FormattableHandlerInterface.php +++ b/src/Monolog/Handler/FormattableHandlerInterface.php @@ -16,7 +16,8 @@ /** * Interface to describe loggers that have a formatter * - * @internal This interface is present in monolog 1.x to ease forward compatibility. + * This interface is present in monolog 1.x to ease forward compatibility. + * * @author Jordi Boggiano */ interface FormattableHandlerInterface diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 5233bf55a..e9ec5e776 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -17,7 +17,8 @@ /** * Helper trait for implementing FormattableInterface * - * @internal This interface is present in monolog 1.x to ease forward compatibility. + * This trait is present in monolog 1.x to ease forward compatibility. + * * @author Jordi Boggiano */ trait FormattableHandlerTrait diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index bfa714975..66a3d83ae 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -16,7 +16,8 @@ /** * Interface to describe loggers that have processors * - * @internal This interface is present in monolog 1.x to ease forward compatibility. + * This interface is present in monolog 1.x to ease forward compatibility. + * * @author Jordi Boggiano */ interface ProcessableHandlerInterface @@ -27,7 +28,7 @@ interface ProcessableHandlerInterface * @param ProcessorInterface|callable $callback * @return HandlerInterface self */ - public function pushProcessor(callable $callback): HandlerInterface; + public function pushProcessor($callback): HandlerInterface; /** * Removes the processor on top of the stack and returns it. diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index a5092929e..09f32a12c 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -16,7 +16,8 @@ /** * Helper trait for implementing ProcessableInterface * - * @internal This interface is present in monolog 1.x to ease forward compatibility. + * This trait is present in monolog 1.x to ease forward compatibility. + * * @author Jordi Boggiano */ trait ProcessableHandlerTrait @@ -30,7 +31,7 @@ trait ProcessableHandlerTrait * {@inheritdoc} * @suppress PhanTypeMismatchReturn */ - public function pushProcessor(callable $callback): HandlerInterface + public function pushProcessor($callback): HandlerInterface { array_unshift($this->processors, $callback); From 70e65a5470a42cfec1a7da00d30edb6e617e8dcf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 6 Sep 2019 15:49:17 +0200 Subject: [PATCH 180/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1673dc8f1..9b0f5280f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.25.1 (2019-09-06) + + * Fixed forward-compatible interfaces to be compatible with Monolog 1.x too. + ### 1.25.0 (2019-09-06) * Deprecated SlackbotHandler, use SlackWebhookHandler or SlackHandler instead From c404cb324026cfb1956acf0351f9fa3e82c5f7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Pr=C3=A9vot?= Date: Sat, 7 Sep 2019 21:23:23 -1000 Subject: [PATCH 181/498] Fix file permission --- src/Monolog/Handler/Slack/SlackRecord.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/Monolog/Handler/Slack/SlackRecord.php diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php old mode 100755 new mode 100644 From 74215b17a21158a4b6b8f8f04f76855cb9d347ef Mon Sep 17 00:00:00 2001 From: Heier Date: Sun, 15 Sep 2019 12:16:35 +0800 Subject: [PATCH 182/498] Update 01-usage.md The default date format is changed, so edit documents synchronously. --- doc/01-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index 7767a6116..59b9ae76b 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -206,7 +206,7 @@ write your own (e.g. a multiline text file for human-readable output). To configure a predefined formatter class, just set it as the handler's field: ```php -// the default date format is "Y-m-d H:i:s" +// the default date format is "Y-m-d\TH:i:sP" $dateFormat = "Y n j, g:i a"; // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" $output = "%datetime% > %level_name% > %message% %context% %extra%\n"; From 6a6c2ac8faacfbb910652b8dd6f5cacd016cfc49 Mon Sep 17 00:00:00 2001 From: Jos Ahrens Date: Mon, 21 Oct 2019 18:37:01 +0000 Subject: [PATCH 183/498] github: implement newer version of issue templates Moves away from the older version of GitHub issue templates, includes automatic labelling. more reading: https://help.github.com/en/github/building-a-strong-community/about-issue-and-pull-request-templates --- .github/ISSUE_TEMPLATE.md | 3 --- .github/ISSUE_TEMPLATE/Bug_Report.md | 9 +++++++++ .github/ISSUE_TEMPLATE/Feature.md | 7 +++++++ .github/ISSUE_TEMPLATE/Question.md | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/Bug_Report.md create mode 100644 .github/ISSUE_TEMPLATE/Feature.md create mode 100644 .github/ISSUE_TEMPLATE/Question.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 46e6e8dec..000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,3 +0,0 @@ -I am using Monolog version 1|2 - -... the problem/suggestion/question here ... diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md new file mode 100644 index 000000000..71ce0c2b7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_Report.md @@ -0,0 +1,9 @@ +--- +name: Bug Report +about: Create a bug report +labels: Bug +--- + +Monolog version 1|2 + +Write your bug report here. diff --git a/.github/ISSUE_TEMPLATE/Feature.md b/.github/ISSUE_TEMPLATE/Feature.md new file mode 100644 index 000000000..9ef03eecd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature.md @@ -0,0 +1,7 @@ +--- +name: Feature +about: Suggest a new feature or enhancement +labels: Feature +--- + +Write your suggestion here. diff --git a/.github/ISSUE_TEMPLATE/Question.md b/.github/ISSUE_TEMPLATE/Question.md new file mode 100644 index 000000000..b2810fa36 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Question.md @@ -0,0 +1,9 @@ +--- +name: Question +about: Ask a question regarding software usage +labels: Support +--- + +Monolog version 1|2 + +Write your question here. From e237839d94c7627711ffdfe2db6037425edfeb33 Mon Sep 17 00:00:00 2001 From: Jos Ahrens Date: Mon, 21 Oct 2019 18:53:18 +0000 Subject: [PATCH 184/498] github: Add security header Tying in with #1389, this will add a new section to the 'create new issue' and also be visible in the 'security' tab on GitHub It's been left intentionally generic. --- .github/SECURITY.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/SECURITY.md diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 000000000..d6b6b3fc3 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,7 @@ +# Reporting a vulnerability + +If you have found any issues that might have security implications, +please send a report privately to the email associated with the author +of this repository. + +Do not report security reports publicly. From 3a2d7379a7c5a66217258891e43f2cbd2e08402d Mon Sep 17 00:00:00 2001 From: Alexander Dmitryuk Date: Tue, 5 Nov 2019 14:22:27 +0700 Subject: [PATCH 185/498] HtmlFormatter addRow cast key to string --- src/Monolog/Formatter/HtmlFormatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 3c4e84798..16a30329d 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -92,7 +92,7 @@ public function format(array $record): string if ($record['context']) { $embeddedTable = ''; foreach ($record['context'] as $key => $value) { - $embeddedTable .= $this->addRow($key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string)$key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Context', $embeddedTable, false); @@ -100,7 +100,7 @@ public function format(array $record): string if ($record['extra']) { $embeddedTable = ''; foreach ($record['extra'] as $key => $value) { - $embeddedTable .= $this->addRow($key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string)$key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Extra', $embeddedTable, false); From b7cee792db6d01cf3dd6ea0d1714609d3156ec07 Mon Sep 17 00:00:00 2001 From: Alexander Dmitryuk Date: Tue, 5 Nov 2019 14:48:20 +0700 Subject: [PATCH 186/498] fix test --- tests/Monolog/Handler/ProcessHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/ProcessHandlerTest.php b/tests/Monolog/Handler/ProcessHandlerTest.php index fc1aff475..70619e700 100644 --- a/tests/Monolog/Handler/ProcessHandlerTest.php +++ b/tests/Monolog/Handler/ProcessHandlerTest.php @@ -48,7 +48,7 @@ public function testWriteOpensProcessAndWritesToStdInOfProcess() $handler->expects($this->exactly(2)) ->method('writeProcessInput') - ->withConsecutive($this->stringContains($fixtures[0]), $this->stringContains($fixtures[1])); + ->withConsecutive([$this->stringContains($fixtures[0])], [$this->stringContains($fixtures[1])]); /** @var ProcessHandler $handler */ $handler->handle($this->getRecord(Logger::WARNING, $fixtures[0])); From b271cd4294a2fb19f18d9f0fd0284f224b3e9d28 Mon Sep 17 00:00:00 2001 From: Garrick Lam Date: Thu, 3 Oct 2019 13:02:02 +0800 Subject: [PATCH 187/498] Don't even try to attempt normalizing iterators or generators in context Iterators and Generators may not be rewindable, so foreach is not safe to use on them. Iterators and especially Generators may trigger irreversible actions on calling next(), so iterating over all values can potentially cause harm, e.g. imagine an iterator over a set of HTTP POST requests that are sent when the next value is requested . The only sufficiently safe thing to iterate and include here are primitive arrays. --- src/Monolog/Formatter/JsonFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 2ff119eaa..8d10b8253 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -145,7 +145,7 @@ protected function normalize($data, $depth = 0) return 'Over 9 levels deep, aborting normalization'; } - if (is_array($data) || $data instanceof \Traversable) { + if (is_array($data)) { $normalized = array(); $count = 1; From 9c2dde02b660b53e9e764db812640523f1a32ef6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Nov 2019 07:26:31 +0100 Subject: [PATCH 188/498] Update SECURITY.md --- .github/SECURITY.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/SECURITY.md b/.github/SECURITY.md index d6b6b3fc3..3cc8c1dec 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,7 +1,6 @@ # Reporting a vulnerability If you have found any issues that might have security implications, -please send a report privately to the email associated with the author -of this repository. +please send a report privately to j.boggiano@seld.be Do not report security reports publicly. From 21faa8ed19db0b8f995ac6141c23726e1adf0f32 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Nov 2019 07:34:44 +0100 Subject: [PATCH 189/498] Create FUNDING.yml --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..17efe9939 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [Seldaek] +tidelift: "packagist/monolog/monolog" From f35dac526c30aeca6a0018f7b2274a7c34de7c0b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Nov 2019 07:40:51 +0100 Subject: [PATCH 190/498] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 61216153f..2709be364 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,11 @@ $log->error('Bar'); - [Extending Monolog](doc/04-extending.md) - [Log Record Structure](doc/message-structure.md) -## Support +## 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=readme) +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. ## Third Party Packages From 65f1f304d4e68759970a5c663ad2ae46faa47013 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 Nov 2019 18:21:38 +0100 Subject: [PATCH 191/498] Add forwarding of formatter functions to nested handlers in Sampling, Filter and FingersCrossed handlers, and fix handling of callable factory handler config, fixes #1386, closes #1387 --- src/Monolog/Handler/FilterHandler.php | 52 +++++++++++++---- src/Monolog/Handler/FingersCrossedHandler.php | 58 ++++++++++++++----- src/Monolog/Handler/SamplingHandler.php | 53 +++++++++++++---- 3 files changed, 127 insertions(+), 36 deletions(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 938c1a7e9..11ede52e5 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; /** * Simple handler wrapper that filters records based on a list of levels @@ -45,7 +46,7 @@ class FilterHandler extends AbstractHandler protected $bubble; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $this). + * @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 $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 @@ -104,21 +105,13 @@ public function handle(array $record) return false; } - // The same logic as in FingersCrossedHandler - if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - if ($this->processors) { foreach ($this->processors as $processor) { $record = call_user_func($processor, $record); } } - $this->handler->handle($record); + $this->getHandler($record)->handle($record); return false === $this->bubble; } @@ -135,6 +128,43 @@ public function handleBatch(array $records) } } - $this->handler->handleBatch($filtered); + $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered); + } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 275fd5136..cdabc4458 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -15,6 +15,7 @@ use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Logger; use Monolog\ResettableInterface; +use Monolog\Formatter\FormatterInterface; /** * Buffers all records until a certain level is reached @@ -39,7 +40,7 @@ class FingersCrossedHandler extends AbstractHandler protected $passthruLevel; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action * @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 @@ -88,15 +89,7 @@ public function activate() if ($this->stopBuffering) { $this->buffering = false; } - if (!$this->handler instanceof HandlerInterface) { - $record = end($this->buffer) ?: null; - - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - $this->handler->handleBatch($this->buffer); + $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); $this->buffer = array(); } @@ -120,7 +113,7 @@ public function handle(array $record) $this->activate(); } } else { - $this->handler->handle($record); + $this->getHandler($record)->handle($record); } return false === $this->bubble; @@ -140,8 +133,8 @@ public function reset() parent::reset(); - if ($this->handler instanceof ResettableInterface) { - $this->handler->reset(); + if ($this->getHandler() instanceof ResettableInterface) { + $this->getHandler()->reset(); } } @@ -167,11 +160,48 @@ private function flushBuffer() return $record['level'] >= $level; }); if (count($this->buffer) > 0) { - $this->handler->handleBatch($this->buffer); + $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); } } $this->buffer = array(); $this->buffering = true; } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); + } } diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 9509ae378..b547ed7da 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; + /** * Sampling handler * @@ -38,7 +40,7 @@ class SamplingHandler extends AbstractHandler protected $factor; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). * @param int $factor Sample factor */ public function __construct($handler, $factor) @@ -54,29 +56,58 @@ public function __construct($handler, $factor) public function isHandling(array $record) { - return $this->handler->isHandling($record); + return $this->getHandler($record)->isHandling($record); } public function handle(array $record) { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { - // The same logic as in FingersCrossedHandler - if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); - if (!$this->handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); - } - } - if ($this->processors) { foreach ($this->processors as $processor) { $record = call_user_func($processor, $record); } } - $this->handler->handle($record); + $this->getHandler($record)->handle($record); } return false === $this->bubble; } + + /** + * Return the nested handler + * + * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * + * @return HandlerInterface + */ + public function getHandler(array $record = null) + { + if (!$this->handler instanceof HandlerInterface) { + $this->handler = call_user_func($this->handler, $record, $this); + if (!$this->handler instanceof HandlerInterface) { + throw new \RuntimeException("The factory callable should return a HandlerInterface"); + } + } + + return $this->handler; + } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->getHandler()->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->getHandler()->getFormatter(); + } } From 0ff3a9bd0399ddcf02f6b1ab80efca8f3ea2d6e2 Mon Sep 17 00:00:00 2001 From: Trevor North Date: Fri, 11 Oct 2019 11:56:29 +0100 Subject: [PATCH 192/498] Fix BrowserConsoleHandler formatting This resolves an issue whereby all styles would be applied in reverse order to the formatting markers. --- src/Monolog/Handler/BrowserConsoleHandler.php | 9 +++++---- .../Handler/BrowserConsoleHandlerTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 23cf23ba1..68feb4808 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -164,21 +164,22 @@ private static function generateScript() private static function handleStyles($formatted) { - $args = array(static::quote('font-weight: normal')); + $args = array(); $format = '%c' . $formatted; preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach (array_reverse($matches) as $match) { - $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $args[] = '"font-weight: normal"'; + $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $pos = $match[0][1]; $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); } - array_unshift($args, static::quote($format)); + $args[] = static::quote('font-weight: normal'); + $args[] = static::quote($format); - return $args; + return array_reverse($args); } private static function handleCustomStyles($style, $string) diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index ffe45da2f..1d526c709 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -48,6 +48,22 @@ public function testStyling() $this->assertEquals($expected, $this->generateScript()); } + public function testStylingMultiple() + { + $handler = new BrowserConsoleHandler(); + $handler->setFormatter($this->getIdentityFormatter()); + + $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}[[baz]]{color: blue}')); + + $expected = <<assertEquals($expected, $this->generateScript()); + } + public function testEscaping() { $handler = new BrowserConsoleHandler(); From cf77550dca7ed60552dd4fd929d8c6287f8292d4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 20:38:27 +0100 Subject: [PATCH 193/498] Make sure all exception codes are integers, fixes #1393 --- src/Monolog/Formatter/JsonFormatter.php | 2 +- src/Monolog/Formatter/MongoDBFormatter.php | 2 +- src/Monolog/Formatter/NormalizerFormatter.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 8d10b8253..96a059179 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -186,7 +186,7 @@ protected function normalizeException($e) $data = array( 'class' => Utils::getClass($e), 'message' => $e->getMessage(), - 'code' => $e->getCode(), + 'code' => (int) $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), ); diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index eb7be849f..bd9e4c02b 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -87,7 +87,7 @@ protected function formatException(\Exception $exception, $nestingLevel) $formattedException = array( 'class' => Utils::getClass($exception), 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), + 'code' => (int) $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), ); diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 9865394e0..867f6fb71 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -129,7 +129,7 @@ protected function normalizeException($e) $data = array( 'class' => Utils::getClass($e), 'message' => $e->getMessage(), - 'code' => $e->getCode(), + 'code' => (int) $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), ); From e1af546a55723e3e83b1e3193aa29b51cdae6735 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 20:48:30 +0100 Subject: [PATCH 194/498] Handle detail key of SoapFault being an object, fixes #1391 --- src/Monolog/Formatter/NormalizerFormatter.php | 4 ++-- tests/Monolog/Formatter/NormalizerFormatterTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 867f6fb71..8205d266c 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -142,8 +142,8 @@ protected function normalizeException($e) $data['faultactor'] = $e->faultactor; } - if (isset($e->detail)) { - $data['detail'] = $e->detail; + if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { + $data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail); } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index d4e0d98de..986daa621 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -92,7 +92,7 @@ public function testFormatSoapFaultException() } $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', 'world'); + $e = new \SoapFault('foo', 'bar', 'hello', (object) ['foo' => 'world']); $formatted = $formatter->format(array( 'exception' => $e, )); From 12a76ad61e5ac3770ed175579f990f365f66ffd9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 21:24:23 +0100 Subject: [PATCH 195/498] Fix usages of json_encode which did not handle invalid UTF8 gracefully, fixes #1392 --- src/Monolog/Formatter/FluentdFormatter.php | 4 +- src/Monolog/Formatter/HtmlFormatter.php | 5 +- src/Monolog/Formatter/LineFormatter.php | 2 +- src/Monolog/Formatter/NormalizerFormatter.php | 123 +---------------- src/Monolog/Handler/ChromePHPHandler.php | 5 +- src/Monolog/Handler/CubeHandler.php | 5 +- src/Monolog/Handler/FlowdockHandler.php | 3 +- src/Monolog/Handler/IFTTTHandler.php | 3 +- src/Monolog/Handler/NewRelicHandler.php | 3 +- src/Monolog/Handler/PHPConsoleHandler.php | 3 +- src/Monolog/Handler/Slack/SlackRecord.php | 5 +- src/Monolog/Handler/SlackHandler.php | 3 +- src/Monolog/Handler/SlackWebhookHandler.php | 3 +- src/Monolog/Utils.php | 130 ++++++++++++++++++ .../Formatter/NormalizerFormatterTest.php | 61 +------- tests/Monolog/UtilsTest.php | 67 +++++++++ 16 files changed, 228 insertions(+), 197 deletions(-) create mode 100644 tests/Monolog/UtilsTest.php diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index 46a91ffe8..f8ead4756 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\Utils; + /** * Class FluentdFormatter * @@ -71,7 +73,7 @@ public function format(array $record) $message['level_name'] = $record['level_name']; } - return json_encode(array($tag, $record['datetime']->getTimestamp(), $message)); + return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message)); } public function formatBatch(array $records) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index dfc0b4a3e..9e8d2d018 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\Utils; /** * Formats incoming records into an HTML table @@ -133,9 +134,9 @@ protected function convertToString($data) $data = $this->normalize($data); if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true); } - return str_replace('\\/', '/', json_encode($data)); + return str_replace('\\/', '/', Utils::jsonEncode($data, null, true)); } } diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index f98e1a6fc..acc1fd38f 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -163,7 +163,7 @@ protected function convertToString($data) return $this->toJson($data, true); } - return str_replace('\\/', '/', @json_encode($data)); + return str_replace('\\/', '/', $this->toJson($data, true)); } protected function replaceNewlines($str) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 8205d266c..61861c869 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -171,127 +171,6 @@ protected function normalizeException($e) */ protected function toJson($data, $ignoreErrors = false) { - // suppress json_encode errors since it's twitchy with some inputs - if ($ignoreErrors) { - return @$this->jsonEncode($data); - } - - $json = $this->jsonEncode($data); - - if ($json === false) { - $json = $this->handleJsonError(json_last_error(), $data); - } - - return $json; - } - - /** - * @param mixed $data - * @return string JSON encoded data or null on failure - */ - private function jsonEncode($data) - { - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); - } - - return json_encode($data); - } - - /** - * Handle a json_encode failure. - * - * If the failure is due to invalid string encoding, try to clean the - * input and encode again. If the second encoding attempt fails, the - * inital error is not encoding related or the input can't be cleaned then - * raise a descriptive exception. - * - * @param int $code return code of json_last_error function - * @param mixed $data data that was meant to be encoded - * @throws \RuntimeException if failure can't be corrected - * @return string JSON encoded data after error correction - */ - private function handleJsonError($code, $data) - { - if ($code !== JSON_ERROR_UTF8) { - $this->throwEncodeError($code, $data); - } - - if (is_string($data)) { - $this->detectAndCleanUtf8($data); - } elseif (is_array($data)) { - array_walk_recursive($data, array($this, 'detectAndCleanUtf8')); - } else { - $this->throwEncodeError($code, $data); - } - - $json = $this->jsonEncode($data); - - if ($json === false) { - $this->throwEncodeError(json_last_error(), $data); - } - - return $json; - } - - /** - * Throws an exception according to a given code with a customized message - * - * @param int $code return code of json_last_error function - * @param mixed $data data that was meant to be encoded - * @throws \RuntimeException - */ - private function throwEncodeError($code, $data) - { - 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)); - } - - /** - * Detect invalid UTF-8 string characters and convert to valid UTF-8. - * - * Valid UTF-8 input will be left unmodified, but strings containing - * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed - * original encoding of ISO-8859-15. This conversion may result in - * incorrect output if the actual encoding was not ISO-8859-15, but it - * will be clean UTF-8 output and will not rely on expensive and fragile - * detection algorithms. - * - * Function converts the input in place in the passed variable so that it - * can be used as a callback for array_walk_recursive. - * - * @param mixed &$data Input to check and convert if needed - * @private - */ - public function detectAndCleanUtf8(&$data) - { - if (is_string($data) && !preg_match('//u', $data)) { - $data = preg_replace_callback( - '/[\x80-\xFF]+/', - function ($m) { return utf8_encode($m[0]); }, - $data - ); - $data = str_replace( - array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'), - array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'), - $data - ); - } + return Utils::jsonEncode($data, null, $ignoreErrors); } } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index ac98d5dea..47120e545 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Logger; +use Monolog\Utils; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -134,7 +135,7 @@ protected function send() self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; } - $json = @json_encode(self::$json); + $json = Utils::jsonEncode(self::$json, null, true); $data = base64_encode(utf8_encode($json)); if (strlen($data) > 3 * 1024) { self::$overflowed = true; @@ -149,7 +150,7 @@ protected function send() 'extra' => array(), ); self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); - $json = @json_encode(self::$json); + $json = Utils::jsonEncode(self::$json, null, true); $data = base64_encode(utf8_encode($json)); } diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 96b3ca0c5..44928efb2 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Logs to Cube. @@ -119,9 +120,9 @@ protected function write(array $record) $data['data']['level'] = $record['level']; if ($this->scheme === 'http') { - $this->writeHttp(json_encode($data)); + $this->writeHttp(Utils::jsonEncode($data)); } else { - $this->writeUdp(json_encode($data)); + $this->writeUdp(Utils::jsonEncode($data)); } } diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index dd9a361c2..f0f010cbf 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; @@ -105,7 +106,7 @@ protected function generateDataStream($record) */ private function buildContent($record) { - return json_encode($record['formatted']['flowdock']); + return Utils::jsonEncode($record['formatted']['flowdock']); } /** diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 7f2262208..f4d3b97eb 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * IFTTTHandler uses cURL to trigger IFTTT Maker actions @@ -53,7 +54,7 @@ public function write(array $record) "value2" => $record["level_name"], "value3" => $record["message"], ); - $postString = json_encode($postData); + $postString = Utils::jsonEncode($postData); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey); diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index f911997ad..64dc1381a 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; /** @@ -190,7 +191,7 @@ protected function setNewRelicParameter($key, $value) if (null === $value || is_scalar($value)) { newrelic_add_custom_parameter($key, $value); } else { - newrelic_add_custom_parameter($key, @json_encode($value)); + newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true)); } } diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 1f2076a49..d0a8b43e7 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -14,6 +14,7 @@ use Exception; use Monolog\Formatter\LineFormatter; use Monolog\Logger; +use Monolog\Utils; use PhpConsole\Connector; use PhpConsole\Handler; use PhpConsole\Helper; @@ -188,7 +189,7 @@ private function handleDebugRecord(array $record) $tags = $this->getRecordTags($record); $message = $record['message']; if ($record['context']) { - $message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context']))); + $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index e55e0e2e5..2a8818d4f 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -12,6 +12,7 @@ namespace Monolog\Handler\Slack; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -212,8 +213,8 @@ public function stringify($fields) $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); return $hasSecondDimension || $hasNonNumericKeys - ? json_encode($normalized, $prettyPrintFlag) - : json_encode($normalized); + ? Utils::jsonEncode($normalized, $prettyPrintFlag) + : Utils::jsonEncode($normalized); } /** diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 45d634f46..88c4c4d00 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; /** @@ -118,7 +119,7 @@ protected function prepareContentData($record) $dataArray['token'] = $this->token; if (!empty($dataArray['attachments'])) { - $dataArray['attachments'] = json_encode($dataArray['attachments']); + $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']); } return $dataArray; diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 1ef85faea..b87be99a8 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; /** @@ -83,7 +84,7 @@ public function getWebhookUrl() protected function write(array $record) { $postData = $this->slackRecord->getSlackData($record); - $postString = json_encode($postData); + $postString = Utils::jsonEncode($postData); $ch = curl_init(); $options = array( diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index eb9be863b..de4080161 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -22,4 +22,134 @@ public static function getClass($object) return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } + + /** + * Return the JSON representation of a value + * + * @param mixed $data + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null + * @throws \RuntimeException if encoding fails and errors are not ignored + * @return string + */ + public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false) + { + if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) { + $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } + + $json = json_encode($data, $encodeFlags); + + if (false === $json) { + if ($ignoreErrors) { + return 'null'; + } + + $json = self::handleJsonError(json_last_error(), $data); + } + + return $json; + } + + /** + * Handle a json_encode failure. + * + * If the failure is due to invalid string encoding, try to clean the + * input and encode again. If the second encoding attempt fails, the + * inital error is not encoding related or the input can't be cleaned then + * raise a descriptive exception. + * + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @throws \RuntimeException if failure can't be corrected + * @return string JSON encoded data after error correction + */ + public static function handleJsonError($code, $data, $encodeFlags = null) + { + if ($code !== JSON_ERROR_UTF8) { + self::throwEncodeError($code, $data); + } + + if (is_string($data)) { + self::detectAndCleanUtf8($data); + } elseif (is_array($data)) { + array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8')); + } else { + self::throwEncodeError($code, $data); + } + + if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) { + $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } + + $json = json_encode($data, $encodeFlags); + + if ($json === false) { + self::throwEncodeError(json_last_error(), $data); + } + + return $json; + } + + /** + * Throws an exception according to a given code with a customized message + * + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded + * @throws \RuntimeException + */ + private static function throwEncodeError($code, $data) + { + 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)); + } + + /** + * Detect invalid UTF-8 string characters and convert to valid UTF-8. + * + * Valid UTF-8 input will be left unmodified, but strings containing + * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed + * original encoding of ISO-8859-15. This conversion may result in + * incorrect output if the actual encoding was not ISO-8859-15, but it + * will be clean UTF-8 output and will not rely on expensive and fragile + * detection algorithms. + * + * Function converts the input in place in the passed variable so that it + * can be used as a callback for array_walk_recursive. + * + * @param mixed &$data Input to check and convert if needed + * @private + */ + public static function detectAndCleanUtf8(&$data) + { + if (is_string($data) && !preg_match('//u', $data)) { + $data = preg_replace_callback( + '/[\x80-\xFF]+/', + function ($m) { return utf8_encode($m[0]); }, + $data + ); + $data = str_replace( + array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'), + array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'), + $data + ); + } + } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 986daa621..123b5cf67 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -190,7 +190,7 @@ public function testIgnoresRecursiveObjectReferences() restore_error_handler(); - $this->assertEquals(@json_encode(array($foo, $bar)), $res); + $this->assertEquals('null', $res); } public function testCanNormalizeReferences() @@ -223,7 +223,7 @@ public function testIgnoresInvalidTypes() restore_error_handler(); - $this->assertEquals(@json_encode(array($resource)), $res); + $this->assertEquals('null', $res); } public function testNormalizeHandleLargeArraysWithExactly1000Items() @@ -305,63 +305,6 @@ public function testConvertsInvalidEncodingAsLatin9() } } - /** - * @param mixed $in Input - * @param mixed $expect Expected output - * @covers Monolog\Formatter\NormalizerFormatter::detectAndCleanUtf8 - * @dataProvider providesDetectAndCleanUtf8 - */ - public function testDetectAndCleanUtf8($in, $expect) - { - $formatter = new NormalizerFormatter(); - $formatter->detectAndCleanUtf8($in); - $this->assertSame($expect, $in); - } - - public function providesDetectAndCleanUtf8() - { - $obj = new \stdClass; - - return array( - 'null' => array(null, null), - 'int' => array(123, 123), - 'float' => array(123.45, 123.45), - 'bool false' => array(false, false), - 'bool true' => array(true, true), - 'ascii string' => array('abcdef', 'abcdef'), - 'latin9 string' => array("\xB1\x31\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xFF", '±1€ŠšŽžŒœŸÿ'), - 'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'), - 'empty array' => array(array(), array()), - 'array' => array(array('abcdef'), array('abcdef')), - 'object' => array($obj, $obj), - ); - } - - /** - * @param int $code - * @param string $msg - * @dataProvider providesHandleJsonErrorFailure - */ - public function testHandleJsonErrorFailure($code, $msg) - { - $formatter = new NormalizerFormatter(); - $reflMethod = new \ReflectionMethod($formatter, 'handleJsonError'); - $reflMethod->setAccessible(true); - - $this->setExpectedException('RuntimeException', $msg); - $reflMethod->invoke($formatter, $code, 'faked'); - } - - public function providesHandleJsonErrorFailure() - { - return array( - 'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'), - 'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'), - 'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'), - 'default' => array(-1, 'Unknown error'), - ); - } - public function testExceptionTraceWithArgs() { if (defined('HHVM_VERSION')) { diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php new file mode 100644 index 000000000..1ffcc74b8 --- /dev/null +++ b/tests/Monolog/UtilsTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +class UtilsTest extends \PHPUnit_Framework_TestCase +{ + /** + * @param int $code + * @param string $msg + * @dataProvider providesHandleJsonErrorFailure + */ + public function testHandleJsonErrorFailure($code, $msg) + { + $this->setExpectedException('RuntimeException', $msg); + Utils::handleJsonError($code, 'faked'); + } + + public function providesHandleJsonErrorFailure() + { + return array( + 'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'), + 'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'), + 'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'), + 'default' => array(-1, 'Unknown error'), + ); + } + + /** + * @param mixed $in Input + * @param mixed $expect Expected output + * @covers Monolog\Formatter\NormalizerFormatter::detectAndCleanUtf8 + * @dataProvider providesDetectAndCleanUtf8 + */ + public function testDetectAndCleanUtf8($in, $expect) + { + Utils::detectAndCleanUtf8($in); + $this->assertSame($expect, $in); + } + + public function providesDetectAndCleanUtf8() + { + $obj = new \stdClass; + + return array( + 'null' => array(null, null), + 'int' => array(123, 123), + 'float' => array(123.45, 123.45), + 'bool false' => array(false, false), + 'bool true' => array(true, true), + 'ascii string' => array('abcdef', 'abcdef'), + 'latin9 string' => array("\xB1\x31\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xFF", '±1€ŠšŽžŒœŸÿ'), + 'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'), + 'empty array' => array(array(), array()), + 'array' => array(array('abcdef'), array('abcdef')), + 'object' => array($obj, $obj), + ); + } +} From 9776fa1d548716490a7d49ffbb608e5c2dda589b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 21:52:37 +0100 Subject: [PATCH 196/498] Fix type error, fixes #1382 --- src/Monolog/Handler/Slack/SlackRecord.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index dbfcd9824..60d2c9e18 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -159,7 +159,7 @@ public function getSlackData(array $record): array if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( - $key, + (string) $key, $record[$key] ); } else { @@ -324,7 +324,7 @@ private function generateAttachmentFields(array $data): array { $fields = array(); foreach ($this->normalizerFormatter->format($data) as $key => $value) { - $fields[] = $this->generateAttachmentField($key, $value); + $fields[] = $this->generateAttachmentField((string) $key, $value); } return $fields; From 05f6ed7205319323df4d5526358a7aeb6d18b1cd Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 22:10:50 +0100 Subject: [PATCH 197/498] Fix php 5.3 syntax --- tests/Monolog/Formatter/NormalizerFormatterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 123b5cf67..82c0ebaf1 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -92,7 +92,7 @@ public function testFormatSoapFaultException() } $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', (object) ['foo' => 'world']); + $e = new \SoapFault('foo', 'bar', 'hello', (object) array('foo' => 'world')); $formatted = $formatter->format(array( 'exception' => $e, )); From dc2895c80da6bcc9b9f26ab6d0736b86f019813f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 22:13:21 +0100 Subject: [PATCH 198/498] Suppress errors when json_encode has ignoreErrors set --- src/Monolog/Utils.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index de4080161..180a159db 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -38,13 +38,17 @@ public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = fa $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; } - $json = json_encode($data, $encodeFlags); - - if (false === $json) { - if ($ignoreErrors) { + if ($ignoreErrors) { + $json = @json_encode($data, $encodeFlags); + if (false === $json) { return 'null'; } + return $json; + } + + $json = json_encode($data, $encodeFlags); + if (false === $json) { $json = self::handleJsonError(json_last_error(), $data); } From f97cc755af78886da8b5878ab7db225fbbc0f8f3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 12 Nov 2019 22:28:59 +0100 Subject: [PATCH 199/498] Fix 5.3/5.4 builds --- tests/Monolog/Formatter/NormalizerFormatterTest.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 82c0ebaf1..38c73170b 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -190,7 +190,11 @@ public function testIgnoresRecursiveObjectReferences() restore_error_handler(); - $this->assertEquals('null', $res); + if (PHP_VERSION_ID < 50500) { + $this->assertEquals('[{"bar":{"foo":null}},{"foo":{"bar":null}}]', $res); + } else { + $this->assertEquals('null', $res); + } } public function testCanNormalizeReferences() @@ -223,7 +227,11 @@ public function testIgnoresInvalidTypes() restore_error_handler(); - $this->assertEquals('null', $res); + if (PHP_VERSION_ID < 50500) { + $this->assertEquals('[null]', $res); + } else { + $this->assertEquals('null', $res); + } } public function testNormalizeHandleLargeArraysWithExactly1000Items() From ec3e0e3f907d25456063ec1e1799eb0bcf4a5bab Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 13 Nov 2019 10:47:25 +0100 Subject: [PATCH 200/498] set json flags correctly for SlackRecord, fixes #1396, closes #1397 --- src/Monolog/Handler/Slack/SlackRecord.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 2a8818d4f..39455501f 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -208,13 +208,17 @@ public function stringify($fields) { $normalized = $this->normalizerFormatter->format($fields); $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; + $flags = 0; + if (PHP_VERSION_ID >= 50400) { + $flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + } $hasSecondDimension = count(array_filter($normalized, 'is_array')); $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); return $hasSecondDimension || $hasNonNumericKeys - ? Utils::jsonEncode($normalized, $prettyPrintFlag) - : Utils::jsonEncode($normalized); + ? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags) + : Utils::jsonEncode($normalized, $flags); } /** From 4a70fb3353107bf1be596958d395ec29b32dbbec Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 13 Nov 2019 10:51:07 +0100 Subject: [PATCH 201/498] Add formatter forwarding to BufferHandler as well --- src/Monolog/Handler/BufferHandler.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 61d1b50c1..a7e364582 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -126,4 +126,22 @@ public function reset() $this->handler->reset(); } } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter) + { + $this->handler->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->handler->getFormatter(); + } } From ac44cccd84d77609f501d91c1c955513017bf267 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 13 Nov 2019 10:54:16 +0100 Subject: [PATCH 202/498] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b0f5280f..a00c1ece8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### 1.25.2 (2019-11-13) + + * Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable + * Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler and SamplingHandler + * Fixed BrowserConsoleHandler formatting when using multiple styles + * Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings + * Fixed normalization of SoapFault objects containing non-strings as "detail" + * Fixed json encoding across all handlers to always attempt recovery of non-UTF-8 strings instead of failing the whole encoding + ### 1.25.1 (2019-09-06) * Fixed forward-compatible interfaces to be compatible with Monolog 1.x too. From d5e2fb341cb44f7e2ab639d12a1e5901091ec287 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 13 Nov 2019 11:00:05 +0100 Subject: [PATCH 203/498] Add missing use statement --- src/Monolog/Handler/BufferHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index a7e364582..0957e5580 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\ResettableInterface; +use Monolog\Formatter\FormatterInterface; /** * Buffers all records until closing the handler and then pass them as batch. From f9d56fd2f5533322caccdfcddbb56aedd622ef1c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 13 Nov 2019 11:27:43 +0100 Subject: [PATCH 204/498] Prepare changelog --- CHANGELOG.md | 2 +- src/Monolog/Handler/BufferHandler.php | 6 +++--- src/Monolog/Handler/OverflowHandler.php | 21 ++++++++++++++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52191a8d8..39444c930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ### 2.0.1 (2019-11-13) * Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable - * Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler and SamplingHandler + * Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler, OverflowHandler and SamplingHandler * Fixed BrowserConsoleHandler formatting when using multiple styles * Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings * Fixed normalization of SoapFault objects containing non-strings as "detail" diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index c3fcc4aeb..7a5902849 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -23,7 +23,7 @@ * * @author Christophe Coevoet */ -class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface +class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; @@ -135,7 +135,7 @@ public function reset() /** * {@inheritdoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { $this->handler->setFormatter($formatter); @@ -145,7 +145,7 @@ public function setFormatter(FormatterInterface $formatter) /** * {@inheritdoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { return $this->handler->getFormatter(); } diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 3d034b97c..448f6334d 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; /** * Handler to only pass log messages when a certain threshold of number of messages is reached. @@ -33,7 +34,7 @@ * * @author Kris Buist */ -class OverflowHandler extends AbstractHandler +class OverflowHandler extends AbstractHandler implements FormattableHandlerInterface { /** @var HandlerInterface */ private $handler; @@ -124,4 +125,22 @@ public function handle(array $record): bool return false === $this->bubble; } + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->handler->setFormatter($formatter); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter(): FormatterInterface + { + return $this->handler->getFormatter(); + } } From 3dcb1919a3b7027e60cfa9b9c9971535c1e1bf00 Mon Sep 17 00:00:00 2001 From: Thomas Praxl Date: Fri, 15 Nov 2019 09:07:02 +0100 Subject: [PATCH 205/498] Fix misleading @throws tag in StreamHandler doc The `\Exception` for non-existing and not creatable paths is thrown earliest on first write. Not during StreamHandler instantiation, as claimed by the constructor's `@throws` tag. --- src/Monolog/Handler/StreamHandler.php | 3 +- tests/Monolog/Handler/StreamHandlerTest.php | 43 ++++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 0c2f8d1bd..9541556b9 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -32,13 +32,12 @@ class StreamHandler extends AbstractProcessingHandler private $dirCreated; /** - * @param resource|string $stream + * @param resource|string $stream If a missing path can't be created, an Exception will be thrown on first write * @param string|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 * @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 * - * @throws \Exception If a missing directory is not buildable * @throws \InvalidArgumentException If stream is not a resource or string */ public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index f8101dbad..96a2ff46d 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -184,33 +184,40 @@ public function testWriteNonExistingFileResource() /** * @covers Monolog\Handler\StreamHandler::__construct * @covers Monolog\Handler\StreamHandler::write + * @dataProvider provideNonExistingAndNotCreatablePath */ - public function testWriteNonExistingAndNotCreatablePath() + public function testWriteNonExistingAndNotCreatablePath($nonExistingAndNotCreatablePath) { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('There is no existing directory at'); - - if (defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Permissions checks can not run on windows'); } - $handler = new StreamHandler('/foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); - $handler->handle($this->getRecord()); - } - /** - * @covers Monolog\Handler\StreamHandler::__construct - * @covers Monolog\Handler\StreamHandler::write - */ - public function testWriteNonExistingAndNotCreatableFileResource() - { + $handler = null; + + try { + $handler = new StreamHandler($nonExistingAndNotCreatablePath); + } catch (\Exception $fail) { + $this->fail( + 'A non-existing and not creatable path should throw an Exception earliest on first write. + Not during instantiation.' + ); + } + $this->expectException(\Exception::class); $this->expectExceptionMessage('There is no existing directory at'); - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $this->markTestSkipped('Permissions checks can not run on windows'); - } - $handler = new StreamHandler('file:///foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000)); $handler->handle($this->getRecord()); } + + public function provideNonExistingAndNotCreatablePath() + { + return [ + '/foo/bar/…' => [ + '/foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000), + ], + 'file:///foo/bar/…' => [ + 'file:///foo/bar/'.rand(0, 10000).DIRECTORY_SEPARATOR.rand(0, 10000), + ], + ]; + } } From 525d29847ae2f5560c0320f3709a2e2d695756db Mon Sep 17 00:00:00 2001 From: David Maicher Date: Fri, 15 Nov 2019 13:05:36 +0100 Subject: [PATCH 206/498] FilterHandler: fix handle empty batch of filtered records --- src/Monolog/Handler/FilterHandler.php | 2 +- tests/Monolog/Handler/FilterHandlerTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 11ede52e5..bf5cb52ab 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -128,7 +128,7 @@ public function handleBatch(array $records) } } - $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered); + $this->getHandler(count($filtered) > 0 ? $filtered[count($filtered) - 1] : null)->handleBatch($filtered); } /** diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index 31b7686a0..5784c1a49 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -167,4 +167,12 @@ function ($record, $handler) { ); $handler->handle($this->getRecord(Logger::WARNING)); } + + public function testHandleEmptyBatch() + { + $test = new TestHandler(); + $handler = new FilterHandler($test); + $handler->handleBatch(array()); + $this->assertSame(array(), $test->getRecords()); + } } From 3c3ff5881c69417576e8e0b0a9c2e32ccee09029 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 15 Nov 2019 15:46:53 +0100 Subject: [PATCH 207/498] Avoid calling nested handler entirely if there is nothing left to handle --- src/Monolog/Handler/FilterHandler.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index bf5cb52ab..949f22718 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -128,7 +128,9 @@ public function handleBatch(array $records) } } - $this->getHandler(count($filtered) > 0 ? $filtered[count($filtered) - 1] : null)->handleBatch($filtered); + if (count($filtered) > 0) { + $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered); + } } /** From 764601c60648e7e1e4cf47e91e37e1059f8329be Mon Sep 17 00:00:00 2001 From: Thomas Praxl Date: Mon, 25 Nov 2019 12:01:34 +0100 Subject: [PATCH 208/498] Expect and document a more concrete exception type As was proposed during review. --- src/Monolog/Handler/StreamHandler.php | 2 +- tests/Monolog/Handler/StreamHandlerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 9541556b9..4cce3c39b 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -32,7 +32,7 @@ class StreamHandler extends AbstractProcessingHandler private $dirCreated; /** - * @param resource|string $stream If a missing path can't be created, an Exception will be thrown on first write + * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write * @param string|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 * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 96a2ff46d..8e0d111f0 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -203,7 +203,7 @@ public function testWriteNonExistingAndNotCreatablePath($nonExistingAndNotCreata ); } - $this->expectException(\Exception::class); + $this->expectException(\UnexpectedValueException::class); $this->expectExceptionMessage('There is no existing directory at'); $handler->handle($this->getRecord()); From c8cd53dc0f486acdc07fd6467646b25459b98d0f Mon Sep 17 00:00:00 2001 From: Karolis Date: Sat, 7 Dec 2019 10:08:00 +0000 Subject: [PATCH 209/498] More detailed ElasticsearchHandler exceptions --- src/Monolog/Handler/ElasticsearchHandler.php | 48 ++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 6d0021b9e..ed9a2bc54 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -11,14 +11,14 @@ namespace Monolog\Handler; -use Elasticsearch\Client; -use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; -use InvalidArgumentException; -use Monolog\Formatter\ElasticsearchFormatter; -use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; -use RuntimeException; use Throwable; +use RuntimeException; +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\ElasticsearchFormatter; +use InvalidArgumentException; +use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; +use Elasticsearch\Client; /** * Elasticsearch handler @@ -148,12 +148,44 @@ protected function bulkSend(array $records): void $responses = $this->client->bulk($params); if ($responses['errors'] === true) { - throw new ElasticsearchRuntimeException('Elasticsearch returned error for one of the records'); + throw $this->createExceptionFromResponses($responses); } } catch (Throwable $e) { if (! $this->options['ignore_error']) { throw new RuntimeException('Error sending messages to Elasticsearch', 0, $e); } } + } + + /** + * Creates elasticsearch exception from responses array + * + * Only the first error is converted into an exception. + * + * @param array $responses returned by $this->client->bulk() + */ + protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException + { + foreach ($responses['items'] ?? [] as $item) { + if (isset($item['index']['error'])) { + return $this->createExceptionFromError($item['index']['error']); + } + } + + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); } + + /** + * Creates elasticsearch exception from error array + * + * @param array $error + */ + protected function createExceptionFromError(array $error): ElasticsearchRuntimeException + { + $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); + } + + } From 33794125e3d306ff457b555044884656774773cf Mon Sep 17 00:00:00 2001 From: Karolis Date: Sat, 7 Dec 2019 10:11:40 +0000 Subject: [PATCH 210/498] ElasticsearchHandler indentation fixes --- src/Monolog/Handler/ElasticsearchHandler.php | 30 +++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index ed9a2bc54..64a285e99 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -164,28 +164,26 @@ protected function bulkSend(array $records): void * * @param array $responses returned by $this->client->bulk() */ - protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException - { - foreach ($responses['items'] ?? [] as $item) { - if (isset($item['index']['error'])) { - return $this->createExceptionFromError($item['index']['error']); - } - } - - return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); - } + protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException + { + foreach ($responses['items'] ?? [] as $item) { + if (isset($item['index']['error'])) { + return $this->createExceptionFromError($item['index']['error']); + } + } + + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); + } /** * Creates elasticsearch exception from error array * * @param array $error */ - protected function createExceptionFromError(array $error): ElasticsearchRuntimeException - { - $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + protected function createExceptionFromError(array $error): ElasticsearchRuntimeException + { + $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; - return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); } - - } From f8245696b31439b972035aa922cb8fca82a91384 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 6 Dec 2019 21:51:12 +0000 Subject: [PATCH 211/498] Use strtr() instead of strtoupper() to avoid bogus results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For examle the tr_TR locale will upper-case "i" to the "latin capital letter i with dot above" İ. --- src/Monolog/Logger.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 05dfc8179..e649af51b 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -527,8 +527,13 @@ public static function getLevelName($level) */ public static function toMonologLevel($level) { - if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) { - return constant(__CLASS__.'::'.strtoupper($level)); + if (is_string($level)) { + // Contains chars of all log levels and avoids using strtoupper() which may have + // strange results depending on locale (for example, "i" will become "İ") + $upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); + if (defined(__CLASS__.'::'.$upper)) { + return constant(__CLASS__ . '::' . $upper); + } } return $level; From 633bcd526850e67a83ad1097eba69ed40e3a1f76 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 7 Dec 2019 16:37:53 +0100 Subject: [PATCH 212/498] Also fix SoapFault handling in LineFormatter, refs #1391 --- src/Monolog/Formatter/LineFormatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index fa0c44bca..9fe431933 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -180,8 +180,8 @@ private function formatException(\Throwable $e): string $str .= ' faultactor: ' . $e->faultactor; } - if (isset($e->detail)) { - $str .= ' detail: ' . $e->detail; + if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { + $str .= ' detail: ' . (is_string($e->detail) ? $e->detail : reset($e->detail)); } } $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; From 3e777f724559527229eec1c1d98c798e55b0f035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Hump=C3=A1l?= Date: Wed, 11 Dec 2019 15:56:32 +0100 Subject: [PATCH 213/498] Correct pronoun in readme for contributors --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2709be364..aebd054c0 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono ### Author Jordi Boggiano - -
-See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project. +See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) who participated in this project. ### License From 2a447ab91d7f0bcddf971917b9c42b8bdf8aa225 Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Mon, 16 Dec 2019 10:56:39 +0200 Subject: [PATCH 214/498] upd 7.4 image on travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aeb3978c9..57e2a5197 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ dist: trusty php: - 7.2 - 7.3 - - 7.4snapshot + - 7.4 cache: directories: @@ -18,7 +18,7 @@ matrix: env: deps=low fast_finish: true allow_failures: - - php: 7.4snapshot + - php: 7.4 before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From c53ab0db0b8a4325762eb0a993f7f9829ebbb385 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 19 Dec 2019 14:11:45 +0100 Subject: [PATCH 215/498] Add nightly builds --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 57e2a5197..1b7658f7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ php: - 7.2 - 7.3 - 7.4 + - nightly cache: directories: @@ -18,7 +19,7 @@ matrix: env: deps=low fast_finish: true allow_failures: - - php: 7.4 + - php: nightly before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini From 39c7e04ad4dcb186fca7a87229fc005839f2e992 Mon Sep 17 00:00:00 2001 From: Fabien Date: Thu, 12 Dec 2019 15:11:15 +0100 Subject: [PATCH 216/498] Set phpredis multi() mode parameter --- src/Monolog/Handler/RedisHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 590f99657..bb00db509 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -73,7 +73,8 @@ protected function write(array $record) protected function writeCapped(array $record) { if ($this->redisClient instanceof \Redis) { - $this->redisClient->multi() + $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1; + $this->redisClient->multi($mode) ->rpush($this->redisKey, $record["formatted"]) ->ltrim($this->redisKey, -$this->capSize, -1) ->exec(); From 96ec86aaa1866b17488b5e3deaaa8f174f2bd996 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Dec 2019 09:59:49 +0000 Subject: [PATCH 217/498] Update .travis.yml --- .travis.yml | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index c258b68cb..9df224adc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,26 +1,29 @@ language: php -sudo: false -dist: trusty - -php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - - 7.3 - - 7.4snapshot - matrix: + fast_finish: true include: - dist: precise php: 5.3 + env: deps=low - dist: precise php: 5.3 - env: deps=low - fast_finish: true + - php: 5.4 + dist: trusty + - php: 5.5 + dist: trusty + - php: 5.6 + dist: xenial + - php: 7.0 + dist: xenial + - php: 7.1 + dist: bionic + - php: 7.2 + dist: bionic + - php: 7.3 + dist: bionic + - php: 7.4 + dist: bionic before_script: - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi From 9621075c0fbab6ec7adadf87e35e7b47d138baee Mon Sep 17 00:00:00 2001 From: theravel Date: Tue, 10 Dec 2019 23:20:58 +0100 Subject: [PATCH 218/498] Fix JSON formatting of resource type, closes #1410 --- src/Monolog/Formatter/JsonFormatter.php | 4 ++++ tests/Monolog/Formatter/JsonFormatterTest.php | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 96a059179..86966b079 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -165,6 +165,10 @@ protected function normalize($data, $depth = 0) return $this->normalizeException($data); } + if (is_resource($data)) { + return parent::normalize($data); + } + return $data; } diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 24b06cc94..db07a4cd2 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -114,6 +114,14 @@ public function testDefFormatWithThrowable() $this->assertContextContainsFormattedException($formattedThrowable, $message); } + public function testDefFormatWithResource() + { + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); + $record = $this->getRecord(); + $record['context'] = array('field_resource' => curl_init()); + $this->assertEquals('{"message":"test","context":{"field_resource":"[resource] (curl)"},"level":300,"level_name":"WARNING","channel":"test","datetime":'.json_encode($record['datetime']).',"extra":[]}', $formatter->format($record)); + } + /** * @param string $expected * @param string $actual From fa82921994db851a8becaf3787a9e73c5976b6f1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 20 Dec 2019 15:15:16 +0100 Subject: [PATCH 219/498] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a00c1ece8..255297c69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### 1.25.3 (2019-12-20) + + * Fixed formatting of resources in JsonFormatter + * Fixed RedisHandler failing to use MULTI properly when passed a proxied Redis instance (e.g. in Symfony with lazy services) + * Fixed FilterHandler triggering a notice when handleBatch was filtering all records passed to it + * Fixed Turkish locale messing up the conversion of level names to their constant values + ### 1.25.2 (2019-11-13) * Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable From c861fcba2ca29404dc9e617eedd9eff4616986b8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 20 Dec 2019 15:22:59 +0100 Subject: [PATCH 220/498] Fix indentation --- src/Monolog/Handler/ElasticsearchHandler.php | 62 ++++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 64a285e99..7a7ef0596 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -155,35 +155,35 @@ protected function bulkSend(array $records): void throw new RuntimeException('Error sending messages to Elasticsearch', 0, $e); } } - } - - /** - * Creates elasticsearch exception from responses array - * - * Only the first error is converted into an exception. - * - * @param array $responses returned by $this->client->bulk() - */ - protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException - { - foreach ($responses['items'] ?? [] as $item) { - if (isset($item['index']['error'])) { - return $this->createExceptionFromError($item['index']['error']); - } - } - - return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); - } - - /** - * Creates elasticsearch exception from error array - * - * @param array $error - */ - protected function createExceptionFromError(array $error): ElasticsearchRuntimeException - { - $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; - - return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); - } + } + + /** + * Creates elasticsearch exception from responses array + * + * Only the first error is converted into an exception. + * + * @param array $responses returned by $this->client->bulk() + */ + protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException + { + foreach ($responses['items'] ?? [] as $item) { + if (isset($item['index']['error'])) { + return $this->createExceptionFromError($item['index']['error']); + } + } + + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); + } + + /** + * Creates elasticsearch exception from error array + * + * @param array $error + */ + protected function createExceptionFromError(array $error): ElasticsearchRuntimeException + { + $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); + } } From 2567ccaf622092c1b77928bf623e52abeec90ac5 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 20 Dec 2019 14:35:44 +0000 Subject: [PATCH 221/498] [2.x] Tweaked travis config --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index de6d7a3cd..cabc2297f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: php -sudo: false - cache: directories: - $HOME/.composer/cache @@ -9,6 +7,9 @@ cache: matrix: fast_finish: true include: + - php: 7.2 + dist: bionic + env: deps=low - php: 7.2 dist: bionic - php: 7.3 @@ -17,8 +18,6 @@ matrix: dist: bionic - php: nightly dist: bionic - - php: 7.2 - env: deps=low allow_failures: - php: nightly From c0f8ed9797e93b354910f6d1c24c0299098bc982 Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Tue, 7 Jan 2020 14:49:18 +0100 Subject: [PATCH 222/498] Update html color --- src/Monolog/Formatter/HtmlFormatter.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index d82dfb237..54b84618c 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -27,13 +27,13 @@ class HtmlFormatter extends NormalizerFormatter * Translates Monolog log levels to html color priorities. */ protected $logLevels = [ - Logger::DEBUG => '#cccccc', - Logger::INFO => '#468847', - Logger::NOTICE => '#3a87ad', - Logger::WARNING => '#c09853', - Logger::ERROR => '#f0ad4e', - Logger::CRITICAL => '#FF7708', - Logger::ALERT => '#C12A19', + Logger::DEBUG => '#CCCCCC', + Logger::INFO => '#28A745', + Logger::NOTICE => '#17A2B8', + Logger::WARNING => '#FFC107', + Logger::ERROR => '#FD7E14', + Logger::CRITICAL => '#DC3545', + Logger::ALERT => '#821722', Logger::EMERGENCY => '#000000', ]; From 13555a5122a32b601e0aa93abf71dd8fae75b6df Mon Sep 17 00:00:00 2001 From: Rick Strafy <45132928+Rixafy@users.noreply.github.com> Date: Fri, 10 Jan 2020 21:14:38 +0100 Subject: [PATCH 223/498] Replace old Nette Framework extension with new one --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aebd054c0..63670383e 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. - [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog. - [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog. -- [Nette Framework](http://nette.org/en/) can be used with Monolog via [Kdyby/Monolog](https://github.com/Kdyby/Monolog) extension. +- [Nette Framework](http://nette.org/en/) can be used with Monolog via [contributte/monolog](https://github.com/contributte/monolog) extension. - [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog. - [FuelPHP](http://fuelphp.com/) comes out of the box with Monolog. - [Equip Framework](https://github.com/equip/framework) comes out of the box with Monolog. From ed46997f58b3dc63dd080ae5e197c0483c410459 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Thu, 30 Jan 2020 17:41:20 +0100 Subject: [PATCH 224/498] Fix typehint for AbstractHandler level parameter The level parameter of the AbstractHandler supports also the PSR levels as strings e.g. `\Psr\Log\LogLevel::ERROR` or from a ENV variable `CUSTOM_ERROR_HANDLER_LEVEL=error` --- src/Monolog/Handler/AbstractHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 92b9d4580..cdd9f7d40 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -33,8 +33,8 @@ abstract class AbstractHandler implements HandlerInterface, ResettableInterface protected $processors = array(); /** - * @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 + * @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 */ public function __construct($level = Logger::DEBUG, $bubble = true) { From c715dafb23ac78785b8253fd5abbcbb10e0bb6f7 Mon Sep 17 00:00:00 2001 From: Abdouni Abdelkarim Date: Fri, 14 Feb 2020 00:14:40 +0100 Subject: [PATCH 225/498] bump year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 5170c6df4..aa2a0426c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2019 Jordi Boggiano +Copyright (c) 2011-2020 Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 280f6a131f4ea00718f353103bfe265462b607e6 Mon Sep 17 00:00:00 2001 From: Henrique Serrat Date: Fri, 13 Mar 2020 11:25:08 -0300 Subject: [PATCH 226/498] Check that is not null before calling preg_match --- src/Monolog/Processor/GitProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 9fc3f50f0..cdf5ec736 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -52,7 +52,7 @@ private static function getGitInfo() } $branches = `git branch -v --no-abbrev`; - if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { + if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { return self::$cache = array( 'branch' => $matches[1], 'commit' => $matches[2], From a14890834a39bb860e1cdb8872e42bf0dbe9f2dd Mon Sep 17 00:00:00 2001 From: jambert Date: Sat, 4 Apr 2020 15:37:48 +0200 Subject: [PATCH 227/498] Registry class not used in ErrorHandler --- src/Monolog/ErrorHandler.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index adc55bdf6..36ec0098f 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -14,7 +14,6 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Monolog\Handler\AbstractHandler; -use Monolog\Registry; /** * Monolog error handler From 19fb871b9ba6eeb22f87939099c0583b25d8e16f Mon Sep 17 00:00:00 2001 From: Yohann Durand Date: Tue, 14 Apr 2020 19:17:30 +0200 Subject: [PATCH 228/498] Update 02-handlers-formatters-processors.md formating improve --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index a61bd584f..bf9417ebc 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -35,7 +35,7 @@ - [_SlackWebhookHandler_](../src/Monolog/Handler/SlackWebhookHandler.php): Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks. - [_SlackHandler_](../src/Monolog/Handler/SlackHandler.php): Logs records to a [Slack](https://www.slack.com/) account using the Slack API (complex setup). - [_SendGridHandler_](../src/Monolog/Handler/SendGridHandler.php): Sends emails via the SendGrid API. -- [_MandrillHandler_](../src/Monolog/Handler/MandrillHandler.php): Sends emails via the Mandrill API using a [`Swift_Message`](http://swiftmailer.org/) instance. +- [_MandrillHandler_](../src/Monolog/Handler/MandrillHandler.php): Sends emails via the [`Mandrill API`](https://mandrillapp.com/api/docs/) using a [`Swift_Message`](http://swiftmailer.org/) instance. - [_FleepHookHandler_](../src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. - [_IFTTTHandler_](../src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. - [_TelegramBotHandler_](../src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. From ff3128b487a2bd4326eeb30327d67156e0c98ab4 Mon Sep 17 00:00:00 2001 From: Pierre Grimaud Date: Tue, 28 Apr 2020 18:57:34 +0200 Subject: [PATCH 229/498] Fix typos --- src/Monolog/Utils.php | 2 +- tests/Monolog/Handler/ErrorLogHandlerTest.php | 2 +- tests/Monolog/RegistryTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 358087cb0..e2058d593 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -71,7 +71,7 @@ public static function jsonEncode($data, ?int $encodeFlags = null, bool $ignoreE * * If the failure is due to invalid string encoding, try to clean the * input and encode again. If the second encoding attempt fails, the - * inital error is not encoding related or the input can't be cleaned then + * initial error is not encoding related or the input can't be cleaned then * raise a descriptive exception. * * @param int $code return code of json_last_error function diff --git a/tests/Monolog/Handler/ErrorLogHandlerTest.php b/tests/Monolog/Handler/ErrorLogHandlerTest.php index d48a058b9..10e8ec206 100644 --- a/tests/Monolog/Handler/ErrorLogHandlerTest.php +++ b/tests/Monolog/Handler/ErrorLogHandlerTest.php @@ -41,7 +41,7 @@ public function testShouldNotAcceptAnInvalidTypeOnConstructor() /** * @covers Monolog\Handler\ErrorLogHandler::write */ - public function testShouldLogMessagesUsingErrorLogFuncion() + public function testShouldLogMessagesUsingErrorLogFunction() { $type = ErrorLogHandler::OPERATING_SYSTEM; $handler = new ErrorLogHandler($type); diff --git a/tests/Monolog/RegistryTest.php b/tests/Monolog/RegistryTest.php index 0ada5ee6a..3ebfe841b 100644 --- a/tests/Monolog/RegistryTest.php +++ b/tests/Monolog/RegistryTest.php @@ -116,7 +116,7 @@ public function testGetsSameLogger() /** * @covers Monolog\Registry::getInstance */ - public function testFailsOnNonExistantLogger() + public function testFailsOnNonExistentLogger() { $this->expectException(\InvalidArgumentException::class); Registry::getInstance('test1'); From 21c7b7610d3ba84bcd13c5d7eb10de352071b295 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 21:33:22 +0200 Subject: [PATCH 230/498] Remove abandoned dep, fixes #1445 --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 097df8787..346ef883d 100644 --- a/composer.json +++ b/composer.json @@ -26,10 +26,8 @@ "php-amqplib/php-amqplib": "~2.4", "swiftmailer/swiftmailer": "^5.3|^6.0", "php-console/php-console": "^3.1.3", - "phpunit/phpunit-mock-objects": "2.3.0", - "jakub-onderka/php-parallel-lint": "0.9" + "php-parallel-lint/php-parallel-lint": "^1.0" }, - "_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - needs hhvm 3.8+ on travis", "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", "sentry/sentry": "Allow sending log messages to a Sentry server", From 74f92ea154eed179700960111970234f00b1a56b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 21:42:25 +0200 Subject: [PATCH 231/498] Remove lock file --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 346ef883d..e171e2029 100644 --- a/composer.json +++ b/composer.json @@ -60,5 +60,6 @@ "parallel-lint . --exclude vendor --exclude src/Monolog/Handler/FormattableHandlerInterface.php --exclude src/Monolog/Handler/FormattableHandlerTrait.php --exclude src/Monolog/Handler/ProcessableHandlerInterface.php --exclude src/Monolog/Handler/ProcessableHandlerTrait.php", "phpunit" ] - } + }, + "lock": false } From ab01f390c798883dcdb4a58e48333ee3323325a3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 21:50:15 +0200 Subject: [PATCH 232/498] Add JSON_INVALID_UTF8_SUBSTITUTE flag to default json_encode flags, refs #1446, fixes #1203 --- src/Monolog/Utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index e2058d593..240b3742a 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -13,7 +13,7 @@ final class Utils { - const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION; + const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION | JSON_INVALID_UTF8_SUBSTITUTE; /** * @internal From eb84930e70d8b355cee2e96993011d8d8dced0d1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 21:50:47 +0200 Subject: [PATCH 233/498] Make NormalizerFormatter::addJsonEncodeOption/removeJsonEncodeOption public, fixes #1446 --- src/Monolog/Formatter/NormalizerFormatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index fe75881b3..eb0713296 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -244,12 +244,12 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } - protected function addJsonEncodeOption($option) + public function addJsonEncodeOption($option) { $this->jsonEncodeOptions |= $option; } - protected function removeJsonEncodeOption($option) + public function removeJsonEncodeOption($option) { $this->jsonEncodeOptions ^= $option; } From f2792852325a68f6a197403077bf6975be186acf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 22:18:29 +0200 Subject: [PATCH 234/498] =?UTF-8?q?Fix=20tests,=20invalid=20UTF-8=20is=20n?= =?UTF-8?q?ow=20returning=20=EF=BF=BDs=20instead=20of=20being=20converted?= =?UTF-8?q?=20to=20possibly=20valid=20ISO-8559-15?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Monolog/Formatter/LogstashFormatterTest.php | 2 +- tests/Monolog/Formatter/NormalizerFormatterTest.php | 8 +++----- tests/Monolog/Handler/RotatingFileHandlerTest.php | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/Monolog/Formatter/LogstashFormatterTest.php b/tests/Monolog/Formatter/LogstashFormatterTest.php index b242d6803..07a7efe2c 100644 --- a/tests/Monolog/Formatter/LogstashFormatterTest.php +++ b/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -176,6 +176,6 @@ public function testFormatWithLatin9Data() $this->assertEquals('ERROR', $message['level']); $this->assertEquals('test', $message['type']); $this->assertEquals('hostname', $message['host']); - $this->assertEquals('ÖWN; FBCR/OrangeEspaña; Versão/4.0; Färist', $message['extra']['user_agent']); + $this->assertEquals('�WN; FBCR/OrangeEspa�a; Vers�o/4.0; F�rist', $message['extra']['user_agent']); } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index d3661c5ae..9ea7f080a 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -270,7 +270,7 @@ public function testNormalizeHandleLargeArrays() $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); } - public function testThrowsOnInvalidEncoding() + public function testIgnoresInvalidEncoding() { $formatter = new NormalizerFormatter(); $reflMethod = new \ReflectionMethod($formatter, 'toJson'); @@ -280,9 +280,7 @@ public function testThrowsOnInvalidEncoding() $record = new \stdClass; $record->message = "\xB1\x31"; - $this->expectException(\RuntimeException::class); - - $reflMethod->invoke($formatter, $record); + $this->assertsame('{"message":"�1"}', $reflMethod->invoke($formatter, $record)); } public function testConvertsInvalidEncodingAsLatin9() @@ -293,7 +291,7 @@ public function testConvertsInvalidEncodingAsLatin9() $res = $reflMethod->invoke($formatter, ['message' => "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"]); - $this->assertSame('{"message":"€ŠšŽžŒœŸ"}', $res); + $this->assertSame('{"message":"��������"}', $res); } public function testMaxNormalizeDepth() diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 75bcab30d..5446f40e8 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -137,7 +137,7 @@ public function testAllowOnlyFixedDefinedDateFormats($dateFormat, $valid) $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); if (!$valid) { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageRegExp('~^Invalid date format~'); + $this->expectExceptionMessageMatches('~^Invalid date format~'); } $handler->setFilenameFormat('{filename}-{date}', $dateFormat); $this->assertTrue(true); @@ -178,7 +178,7 @@ public function testDisallowFilenameFormatsWithoutDate($filenameFormat, $valid) $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); if (!$valid) { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageRegExp('~^Invalid filename format~'); + $this->expectExceptionMessageMatches('~^Invalid filename format~'); } $handler->setFilenameFormat($filenameFormat, RotatingFileHandler::FILE_PER_DAY); From 13ee5dabda349251adce7cad72b69524c6281855 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 May 2020 22:22:28 +0200 Subject: [PATCH 235/498] Bump phpunit requirement --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f37b9ba10..5bab0ffb8 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php-console/php-console": "^3.1.3", "php-parallel-lint/php-parallel-lint": "^1.0", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^8.3", + "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <3.0", From 6038dcb21ce15210decec251066834b44a813b59 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Wed, 1 Apr 2020 05:03:52 +0200 Subject: [PATCH 236/498] JsonFormatter: add option to ignore empty `context` and `extra` fields Similar to efe572cb1074. --- src/Monolog/Formatter/JsonFormatter.php | 17 ++++++++++++++--- tests/Monolog/Formatter/JsonFormatterTest.php | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 6b6dc6afd..454b69768 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -28,16 +28,18 @@ class JsonFormatter extends NormalizerFormatter protected $batchMode; protected $appendNewline; + protected $ignoreEmptyContextAndExtra; /** * @var bool */ protected $includeStacktraces = false; - public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true) + public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false) { $this->batchMode = $batchMode; $this->appendNewline = $appendNewline; + $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; } /** @@ -68,11 +70,20 @@ public function isAppendingNewlines(): bool public function format(array $record): string { $normalized = $this->normalize($record); + if (isset($normalized['context']) && $normalized['context'] === []) { - $normalized['context'] = new \stdClass; + if ($this->ignoreEmptyContextAndExtra) { + unset($normalized['context']); + } else { + $normalized['context'] = new \stdClass; + } } if (isset($normalized['extra']) && $normalized['extra'] === []) { - $normalized['extra'] = new \stdClass; + if ($this->ignoreEmptyContextAndExtra) { + unset($normalized['extra']); + } else { + $normalized['extra'] = new \stdClass; + } } return $this->toJson($normalized, true) . ($this->appendNewline ? "\n" : ''); diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index afcdb13a1..dbc2a08cb 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -295,4 +295,23 @@ public function testNormalizeHandleLargeArrays() $this->assertCount(1001, $res['context'][0]); $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); } + + public function testEmptyContextAndExtraFieldsCanBeIgnored() + { + $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true, true); + + $record = $formatter->format(array( + 'level' => 100, + 'level_name' => 'DEBUG', + 'channel' => 'test', + 'message' => 'Testing', + 'context' => array(), + 'extra' => array(), + )); + + $this->assertSame( + '{"level":100,"level_name":"DEBUG","channel":"test","message":"Testing"}'."\n", + $record + ); + } } From 56a8b31e4b117b0794f740c169e1d87aa191ea7f Mon Sep 17 00:00:00 2001 From: James Gilliland Date: Fri, 15 May 2020 11:17:51 -0500 Subject: [PATCH 237/498] Assert SoapFail can handle a structured detail --- tests/Monolog/Formatter/LineFormatterTest.php | 13 +++++++++++ .../Formatter/NormalizerFormatterTest.php | 22 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index 1b115b9f9..86d22d38e 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -192,6 +192,19 @@ public function testDefFormatWithSoapFaultException() $path = str_replace('\\/', '/', json_encode(__FILE__)); $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: world): bar at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); + + $message = $formatter->format([ + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => ['exception' => new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world'])], + 'datetime' => new \DateTimeImmutable, + 'extra' => [], + 'message' => 'foobar', + ]); + + $path = str_replace('\\/', '/', json_encode(__FILE__)); + + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: {\"bar\":{\"biz\":\"baz\"},\"foo\":\"world\"}): bar at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); } public function testBatchFormat() diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 9ea7f080a..90dd835f9 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -87,7 +87,7 @@ public function testFormatSoapFaultException() } $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', (object) ['foo' => 'world']); + $e = new \SoapFault('foo', 'bar', 'hello', 'world'); $formatted = $formatter->format([ 'exception' => $e, ]); @@ -105,6 +105,26 @@ public function testFormatSoapFaultException() 'detail' => 'world', ], ], $formatted); + + $formatter = new NormalizerFormatter('Y-m-d'); + $e = new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world']); + $formatted = $formatter->format([ + 'exception' => $e, + ]); + + unset($formatted['exception']['trace']); + + $this->assertEquals([ + 'exception' => [ + 'class' => 'SoapFault', + 'message' => 'bar', + 'code' => 0, + 'file' => $e->getFile().':'.$e->getLine(), + 'faultcode' => 'foo', + 'faultactor' => 'hello', + 'detail' => '{"bar":{"biz":"baz"},"foo":"world"}', + ], + ], $formatted); } public function testFormatToStringExceptionHandle() From 2066ce89d03202a438d45f851f6ed44e482f245e Mon Sep 17 00:00:00 2001 From: James Gilliland Date: Fri, 15 May 2020 11:25:01 -0500 Subject: [PATCH 238/498] Fix SoapFault detail with nested object Fixes #1431 --- src/Monolog/Formatter/LineFormatter.php | 9 +++++++-- src/Monolog/Formatter/NormalizerFormatter.php | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 9fe431933..0c342a547 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -180,8 +180,13 @@ private function formatException(\Throwable $e): string $str .= ' faultactor: ' . $e->faultactor; } - if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { - $str .= ' detail: ' . (is_string($e->detail) ? $e->detail : reset($e->detail)); + if (isset($e->detail)) { + if (is_string($e->detail)) { + $str .= ' detail: ' . $e->detail; + } + elseif (is_object($e->detail) || is_array($e->detail)) { + $str .= ' detail: ' . Utils::jsonEncode($e->detail); + } } } $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index eb0713296..7368ce04d 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -202,8 +202,13 @@ protected function normalizeException(Throwable $e, int $depth = 0) $data['faultactor'] = $e->faultactor; } - if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { - $data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail); + if (isset($e->detail)) { + if (is_string($e->detail)) { + $data['detail'] = $e->detail; + } + elseif (is_object($e->detail) || is_array($e->detail)) { + $data['detail'] = Utils::jsonEncode($e->detail); + } } } From acd3173c4a9af218d4a58288a4fc61859ce91f7b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 May 2020 16:39:23 +0200 Subject: [PATCH 239/498] Fix SoapFault when detail is nested object, fixes #1431, refs #1462 --- src/Monolog/Formatter/NormalizerFormatter.php | 8 +++++-- .../Formatter/NormalizerFormatterTest.php | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 61861c869..3a01f2cef 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -142,8 +142,12 @@ protected function normalizeException($e) $data['faultactor'] = $e->faultactor; } - if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) { - $data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail); + if (isset($e->detail)) { + if (is_string($e->detail)) { + $data['detail'] = $e->detail; + } elseif (is_object($e->detail) || is_array($e->detail)) { + $data['detail'] = $this->toJson($e->detail, true); + } } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 38c73170b..b02a7f837 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -92,7 +92,7 @@ public function testFormatSoapFaultException() } $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', (object) array('foo' => 'world')); + $e = new \SoapFault('foo', 'bar', 'hello', 'world'); $formatted = $formatter->format(array( 'exception' => $e, )); @@ -110,6 +110,26 @@ public function testFormatSoapFaultException() 'detail' => 'world', ), ), $formatted); + + $formatter = new NormalizerFormatter('Y-m-d'); + $e = new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world']); + $formatted = $formatter->format([ + 'exception' => $e, + ]); + + unset($formatted['exception']['trace']); + + $this->assertEquals([ + 'exception' => [ + 'class' => 'SoapFault', + 'message' => 'bar', + 'code' => 0, + 'file' => $e->getFile().':'.$e->getLine(), + 'faultcode' => 'foo', + 'faultactor' => 'hello', + 'detail' => '{"bar":{"biz":"baz"},"foo":"world"}', + ], + ], $formatted); } public function testFormatToStringExceptionHandle() From c50950d79e381a55d4f605bfe8137ad392e668c1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 May 2020 16:54:57 +0200 Subject: [PATCH 240/498] Canonicalize paths when constructing RotatingFileHandler/StreamHandler, fixes #1326 --- src/Monolog/Handler/RotatingFileHandler.php | 3 ++- src/Monolog/Handler/StreamHandler.php | 3 ++- src/Monolog/Utils.php | 30 +++++++++++++++++++++ tests/Monolog/UtilsTest.php | 23 ++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index ae2309f8a..b8253ba0f 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Stores logs to files that are rotated every day and a limited number of files are kept. @@ -45,7 +46,7 @@ class RotatingFileHandler extends StreamHandler */ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) { - $this->filename = $filename; + $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = (int) $maxFiles; $this->nextRotation = new \DateTime('tomorrow'); $this->filenameFormat = '{filename}-{date}'; diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 27d90e064..7c0dfd22b 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Stores to any stream resource @@ -45,7 +46,7 @@ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $fi if (is_resource($stream)) { $this->stream = $stream; } elseif (is_string($stream)) { - $this->url = $stream; + $this->url = Utils::canonicalizePath($stream); } else { throw new \InvalidArgumentException('A stream must either be a resource or a string.'); } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 180a159db..712b19692 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -23,6 +23,36 @@ public static function getClass($object) return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } + /** + * Makes sure if a relative path is passed in it is turned into an absolute path + * + * @param string $streamUrl stream URL or path without protocol + * + * @return string + */ + public static function canonicalizePath($streamUrl) + { + $prefix = ''; + if ('file://' === substr($streamUrl, 0, 7)) { + $streamUrl = substr($streamUrl, 7); + $prefix = 'file://'; + } + + // other type of stream, not supported + if (false !== strpos($streamUrl, '://')) { + return $streamUrl; + } + + // already absolute + if (substr($streamUrl, 0, 1) === '/' || substr($streamUrl, 1, 1) === ':' || substr($streamUrl, 0, 2) === '\\\\') { + return $prefix.$streamUrl; + } + + $streamUrl = getcwd() . '/' . $streamUrl; + + return $prefix.$streamUrl; + } + /** * Return the JSON representation of a value * diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 1ffcc74b8..428e02cc9 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -13,6 +13,29 @@ class UtilsTest extends \PHPUnit_Framework_TestCase { + /** + * @param string $expected + * @param string $input + * @dataProvider providePathsToCanonicalize + */ + public function testCanonicalizePath($expected, $input) + { + $this->assertSame($expected, Utils::canonicalizePath($input)); + } + + public function providePathsToCanonicalize() + { + return array( + array('/foo/bar', '/foo/bar'), + array('file://'.getcwd().'/bla', 'file://bla'), + array(getcwd().'/bla', 'bla'), + array(getcwd().'/./bla', './bla'), + array('file:///foo/bar', 'file:///foo/bar'), + array('any://foo', 'any://foo'), + array('\\\\network\path', '\\\\network\path'), + ); + } + /** * @param int $code * @param string $msg From fa4a173f69736f3d58d3d4f742ac2534bce8c96b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 May 2020 16:56:55 +0200 Subject: [PATCH 241/498] Fix 5.3 syntax --- .../Monolog/Formatter/NormalizerFormatterTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index b02a7f837..32235daca 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -112,15 +112,15 @@ public function testFormatSoapFaultException() ), $formatted); $formatter = new NormalizerFormatter('Y-m-d'); - $e = new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world']); - $formatted = $formatter->format([ + $e = new \SoapFault('foo', 'bar', 'hello', (object) array('bar' => (object) array('biz' => 'baz'), 'foo' => 'world')); + $formatted = $formatter->format(array( 'exception' => $e, - ]); + )); unset($formatted['exception']['trace']); - $this->assertEquals([ - 'exception' => [ + $this->assertEquals(array( + 'exception' => array( 'class' => 'SoapFault', 'message' => 'bar', 'code' => 0, @@ -128,8 +128,8 @@ public function testFormatSoapFaultException() 'faultcode' => 'foo', 'faultactor' => 'hello', 'detail' => '{"bar":{"biz":"baz"},"foo":"world"}', - ], - ], $formatted); + ), + ), $formatted); } public function testFormatToStringExceptionHandle() From de87dad98f087ff0d75529a1d116f72452f6bfc7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 May 2020 17:02:48 +0200 Subject: [PATCH 242/498] Fix CS --- src/Monolog/Formatter/HtmlFormatter.php | 4 ++-- src/Monolog/Formatter/JsonFormatter.php | 1 - src/Monolog/Formatter/NormalizerFormatter.php | 4 ++-- src/Monolog/Handler/FallbackGroupHandler.php | 1 + src/Monolog/Handler/ZendMonitorHandler.php | 8 ++++---- src/Monolog/Utils.php | 8 ++++---- tests/Monolog/ErrorHandlerTest.php | 3 ++- tests/Monolog/Handler/NativeMailerHandlerTest.php | 1 - tests/Monolog/UtilsTest.php | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 54b84618c..90db3f2a0 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -93,7 +93,7 @@ public function format(array $record): string if ($record['context']) { $embeddedTable = ''; foreach ($record['context'] as $key => $value) { - $embeddedTable .= $this->addRow((string)$key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Context', $embeddedTable, false); @@ -101,7 +101,7 @@ public function format(array $record): string if ($record['extra']) { $embeddedTable = ''; foreach ($record['extra'] as $key => $value) { - $embeddedTable .= $this->addRow((string)$key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Extra', $embeddedTable, false); diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 454b69768..c367baa67 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -11,7 +11,6 @@ namespace Monolog\Formatter; -use Monolog\Utils; use Throwable; /** diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 779e18bbf..3fdb3b459 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -203,7 +203,7 @@ protected function normalizeException(Throwable $e, int $depth = 0) } if (isset($e->detail)) { - if (is_string($e->detail)) { + if (is_string($e->detail)) { $data['detail'] = $e->detail; } elseif (is_object($e->detail) || is_array($e->detail)) { $data['detail'] = $this->toJson($e->detail, true); @@ -230,7 +230,7 @@ protected function normalizeException(Throwable $e, int $depth = 0) * * @param mixed $data * @throws \RuntimeException if encoding fails and errors are not ignored - * @return string if encoding fails and ignoreErrors is true 'null' is returned + * @return string if encoding fails and ignoreErrors is true 'null' is returned */ protected function toJson($data, bool $ignoreErrors = false): string { diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index ea0657486..9c92fa2d3 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -31,6 +31,7 @@ public function handle(array $record): bool // What throwable? } } + return false === $this->bubble; } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index d664fa895..78a886f15 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -71,10 +71,10 @@ protected function write(array $record): void /** * Write to Zend Monitor Events - * @param string $type Text displayed in "Class Name (custom)" field - * @param string $message Text displayed in "Error String" - * @param 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 mixed $formatted Displayed in Custom Variables tab + * @param int $severity Set the event severity level (-1,0,1) */ protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void { diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index a6977b929..007ad686b 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -66,10 +66,10 @@ public static function canonicalizePath(string $streamUrl): string * Return the JSON representation of a value * * @param mixed $data - * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null * @throws \RuntimeException if encoding fails and errors are not ignored - * @return string when errors are ignored and the encoding fails, "null" is returned which is valid json for null + * @return string when errors are ignored and the encoding fails, "null" is returned which is valid json for null */ public static function jsonEncode($data, ?int $encodeFlags = null, bool $ignoreErrors = false): string { @@ -102,8 +102,8 @@ public static function jsonEncode($data, ?int $encodeFlags = null, bool $ignoreE * initial error is not encoding related or the input can't be cleaned then * raise a descriptive exception. * - * @param int $code return code of json_last_error function - * @param mixed $data data that was meant to be encoded + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION * @throws \RuntimeException if failure can't be corrected * @return string JSON encoded data after error correction diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 8cc591da5..69cb3e505 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -28,7 +28,8 @@ public function testHandleError() $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new ErrorHandler($logger); - $phpunitHandler = set_error_handler($prevHandler = function() {}); + $phpunitHandler = set_error_handler($prevHandler = function () { + }); try { $errHandler->registerErrorHandler([], true); diff --git a/tests/Monolog/Handler/NativeMailerHandlerTest.php b/tests/Monolog/Handler/NativeMailerHandlerTest.php index 0803f5b4e..62f79b20e 100644 --- a/tests/Monolog/Handler/NativeMailerHandlerTest.php +++ b/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -13,7 +13,6 @@ use Monolog\Test\TestCase; use Monolog\Logger; -use InvalidArgumentException; function mail($to, $subject, $message, $additional_headers = null, $additional_parameters = null) { diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index c74b96ebb..68a62b14c 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -1,4 +1,4 @@ - Date: Fri, 22 May 2020 08:44:02 +0200 Subject: [PATCH 243/498] Telegram Handler: support additional API parameters (#1451) --- src/Monolog/Handler/TelegramBotHandler.php | 62 ++++++++++++++++++- .../Handler/TelegramBotHandlerTest.php | 24 ++++++- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 5dae9f54e..3abb646ec 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -32,6 +32,15 @@ class TelegramBotHandler extends AbstractProcessingHandler { private const BOT_API = 'https://api.telegram.org/bot'; + /** + * @var array AVAILABLE_PARSE_MODES The available values of parseMode according to the Telegram api documentation + */ + private const AVAILABLE_PARSE_MODES = [ + 'HTML', + 'MarkdownV2', + 'Markdown' // legacy mode without underline and strikethrough, use MarkdownV2 instead + ]; + /** * Telegram bot access token provided by BotFather. * Create telegram bot with https://telegram.me/BotFather and use access token from it. @@ -46,6 +55,26 @@ class TelegramBotHandler extends AbstractProcessingHandler */ 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|null + */ + private $parseMode; + + /** + * Disables link previews for links in the message. + * @var bool|null + */ + private $disableWebPagePreview; + + /** + * Sends the message silently. Users will receive a notification with no sound. + * @var bool|null + */ + private $disableNotification; + /** * @param string $apiKey Telegram bot access token provided by BotFather * @param string $channel Telegram channel name @@ -55,7 +84,10 @@ public function __construct( string $apiKey, string $channel, $level = Logger::DEBUG, - bool $bubble = true + bool $bubble = true, + string $parseMode = null, + bool $disableWebPagePreview = null, + bool $disableNotification = null ) { parent::__construct($level, $bubble); @@ -63,6 +95,31 @@ public function __construct( $this->channel = $channel; $this->level = $level; $this->bubble = $bubble; + $this->setParseMode($parseMode); + $this->disableWebPagePreview($disableWebPagePreview); + $this->disableNotification($disableNotification); + } + + public function setParseMode(string $parseMode = null): self + { + if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES)) { + throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . implode(', ', self::AVAILABLE_PARSE_MODES) . '.'); + } + + $this->parseMode = $parseMode; + return $this; + } + + public function disableWebPagePreview(bool $disableWebPagePreview = null): self + { + $this->disableWebPagePreview = $disableWebPagePreview; + return $this; + } + + public function disableNotification(bool $disableNotification = null): self + { + $this->disableNotification = $disableNotification; + return $this; } /** @@ -87,6 +144,9 @@ protected function send(string $message): void curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'text' => $message, 'chat_id' => $this->channel, + 'parse_mode' => $this->parseMode, + 'disable_web_page_preview' => $this->disableWebPagePreview, + 'disable_notification' => $this->disableNotification, ])); $result = Curl\Util::execute($ch); diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 1d36406b8..ad524e94c 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -35,9 +35,15 @@ public function testSendTelegramRequest(): void * @param string $apiKey * @param string $channel */ - private function createHandler(string $apiKey = 'testKey', string $channel = 'testChannel'): void + private function createHandler( + string $apiKey = 'testKey', + string $channel = 'testChannel', + string $parseMode = 'Markdown', + bool $disableWebPagePreview = false, + bool $disableNotification = true + ): void { - $constructorArgs = [$apiKey, $channel, Logger::DEBUG, true]; + $constructorArgs = [$apiKey, $channel, Logger::DEBUG, true, $parseMode, $disableWebPagePreview, $disableNotification]; $this->handler = $this->getMockBuilder(TelegramBotHandler::class) ->setConstructorArgs($constructorArgs) @@ -47,4 +53,18 @@ private function createHandler(string $apiKey = 'testKey', string $channel = 'te $this->handler->expects($this->atLeast(1)) ->method('send'); } + + public function testSetInvalidParseMode(): void + { + $this->expectException(\InvalidArgumentException::class); + + $handler = new TelegramBotHandler('testKey', 'testChannel'); + $handler->setParseMode('invalid parse mode'); + } + + public function testSetParseMode(): void + { + $handler = new TelegramBotHandler('testKey', 'testChannel'); + $handler->setParseMode('HTML'); + } } From a73b4036c5f4f4721e74b66904e5da00096fd788 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:10:51 +0200 Subject: [PATCH 244/498] Build updates --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9df224adc..c40fb38cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,8 @@ matrix: before_script: - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi - - if [ "$deps" == "low" ]; then composer update --prefer-source --prefer-lowest --prefer-stable; fi - - if [ "$deps" != "low" ]; then composer install --prefer-source; fi + - composer self-update --snapshot + - if [ "$deps" == "low" ]; then composer update -n --prefer-dist --prefer-lowest --prefer-stable; fi + - if [ "$deps" != "low" ]; then composer update -n --prefer-dist; fi script: composer test From 6f9b0a5ff2eb12cf560577b8963539ac1767a1f9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:27:32 +0200 Subject: [PATCH 245/498] Remove deprecation warnings on 7.4 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c40fb38cd..fe999c207 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ matrix: before_script: - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi + - if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then echo "error_reporting = E_ALL & ~E_DEPRECATED" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi - composer self-update --snapshot - if [ "$deps" == "low" ]; then composer update -n --prefer-dist --prefer-lowest --prefer-stable; fi - if [ "$deps" != "low" ]; then composer update -n --prefer-dist; fi From b5260af0d1f62feb72ee6b3b3ed7faf2e41f78d6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:30:27 +0200 Subject: [PATCH 246/498] Also remove deprecation warnings when running outside of travis on php 7.4 --- phpunit.xml.dist | 2 +- tests/bootstrap.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/bootstrap.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 20d82b631..54da28187 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,6 @@ - + tests/Monolog/ diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 000000000..fedc5caf0 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,9 @@ += 70400) { + error_reporting(E_ALL & ~E_DEPRECATED); +} else { + error_reporting(E_ALL); +} + +include __DIR__.'/../vendor/autoload.php'; \ No newline at end of file From 3022efff205e2448b560c833c6fbbf91c3139168 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:31:27 +0200 Subject: [PATCH 247/498] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 255297c69..31512f013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 1.25.4 (2020-05-22) + + * Fixed GitProcessor type error when there is no git repo present + * Fixed normalization of SoapFault objects containing deeply nested objects as "detail" + * Fixed support for relative paths in RotatingFileHandler + ### 1.25.3 (2019-12-20) * Fixed formatting of resources in JsonFormatter From dc1e854c631e7fc85f01288a314ab50be1f45f65 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:48:22 +0200 Subject: [PATCH 248/498] Update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e15cfc49d..55a8088db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +### 2.1.0 (2020-05-22) + + * Added `JSON_INVALID_UTF8_SUBSTITUTE` to default json flags, so that invalid UTF8 characters now get converted to [�](https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character) instead of being converted from ISO-8859-15 to UTF8 as it was before, which was hardly a comprehensive solution + * Added `$ignoreEmptyContextAndExtra` option to JsonFormatter to skip empty context/extra entirely from the output + * Added `$parseMode`, `$disableWebPagePreview` and `$disableNotification` options to TelegramBotHandler + * NormalizerFormatter::addJsonEncodeOption and removeJsonEncodeOption are now public to allow modifying default json flags + * Fixed GitProcessor type error when there is no git repo present + * Fixed normalization of SoapFault objects containing deeply nested objects as "detail" + * Fixed support for relative paths in RotatingFileHandler + ### 2.0.2 (2019-12-20) * Fixed ElasticsearchHandler swallowing exceptions details when failing to index log records From ec855db757a8c9539d2381dc4b96e85a433ae05a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:49:50 +0200 Subject: [PATCH 249/498] Remove Composer platform check to allow php8 testing --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5bab0ffb8..bb73438f7 100644 --- a/composer.json +++ b/composer.json @@ -66,7 +66,8 @@ ] }, "config": { - "sort-packages": true + "sort-packages": true, + "platform-check": false }, "lock": false } From ed3d51a965da4cf743dacba6d4741797be4a54fb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 09:52:07 +0200 Subject: [PATCH 250/498] Bump php requirement to allow greater releases --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bb73438f7..96f47f1f4 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": "^7.2", + "php": ">=7.2", "psr/log": "^1.0.1" }, "require-dev": { From 977e91b78382478d8c49705aa53491e53951cf5b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 10:09:24 +0200 Subject: [PATCH 251/498] Skip linting on php8 --- .travis.yml | 4 +++- composer.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e6390a2d3..afd700241 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,4 +33,6 @@ before_script: - if [ "$deps" == "low" ]; then composer update -n --prefer-dist --prefer-lowest --prefer-stable $COMPOSER_ARGS; fi - if [ "$deps" != "low" ]; then composer update -n --prefer-dist $COMPOSER_ARGS; fi -script: composer test +script: + - if [ "`phpenv version-name`" != "nightly" ]; then composer lint; fi + - composer test diff --git a/composer.json b/composer.json index 96f47f1f4..9e54787c1 100644 --- a/composer.json +++ b/composer.json @@ -60,8 +60,10 @@ } }, "scripts": { + "lint": [ + "parallel-lint . --exclude vendor" + ], "test": [ - "parallel-lint . --exclude vendor", "phpunit" ] }, From 38914429aac460e8e4616c8cb486ecb40ec90bb1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 May 2020 10:12:19 +0200 Subject: [PATCH 252/498] Remove allow_failures flag from php 8 --- .travis.yml | 2 -- CHANGELOG.md | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index afd700241..7223ea98a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,6 @@ matrix: - php: nightly dist: bionic env: COMPOSER_ARGS=--ignore-platform-reqs - allow_failures: - - php: nightly before_script: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a8088db..762c53f60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Added `JSON_INVALID_UTF8_SUBSTITUTE` to default json flags, so that invalid UTF8 characters now get converted to [�](https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character) instead of being converted from ISO-8859-15 to UTF8 as it was before, which was hardly a comprehensive solution * Added `$ignoreEmptyContextAndExtra` option to JsonFormatter to skip empty context/extra entirely from the output * Added `$parseMode`, `$disableWebPagePreview` and `$disableNotification` options to TelegramBotHandler + * Added tentative support for PHP 8 * NormalizerFormatter::addJsonEncodeOption and removeJsonEncodeOption are now public to allow modifying default json flags * Fixed GitProcessor type error when there is no git repo present * Fixed normalization of SoapFault objects containing deeply nested objects as "detail" From 148a26ae5ab3dbda10e18dfe13295cb0d6142902 Mon Sep 17 00:00:00 2001 From: Abdouni Abdelkarim Date: Mon, 1 Jun 2020 10:39:40 +0200 Subject: [PATCH 253/498] Update 01-usage.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello, I just update a code to use the array short syntax. And i also correct highlight syntax. 😉 --- doc/01-usage.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index 59b9ae76b..78ba83ddb 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -125,7 +125,7 @@ record: ```php info('Adding a new user', array('username' => 'Seldaek')); +$logger->info('Adding a new user', ['username' => 'Seldaek']); ``` Simple handlers (like the StreamHandler for instance) will simply format @@ -206,6 +206,8 @@ write your own (e.g. a multiline text file for human-readable output). To configure a predefined formatter class, just set it as the handler's field: ```php + Date: Tue, 2 Jun 2020 11:06:18 +0300 Subject: [PATCH 254/498] Various minor changes to docs (#1468) * Various minor changes to docs * Revert failOnRisk and failOnWarning --- .gitattributes | 1 + .gitignore | 1 + README.md | 2 +- phpunit.xml.dist | 7 ++++++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index ed6e29a8a..5d13ab73e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ /tests export-ignore /.* export-ignore /phpunit.xml.dist export-ignore +/UPGRADE.md diff --git a/.gitignore b/.gitignore index 0640915db..a3ec4bab3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ composer.lock .DS_Store .php_cs.cache .hg +.phpunit.result.cache diff --git a/README.md b/README.md index 63670383e..9ca3c6a6b 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ See also the list of [contributors](https://github.com/Seldaek/monolog/contribut ### License -Monolog is licensed under the MIT License - see the `LICENSE` file for details +Monolog is licensed under the MIT License - see the [LICENSE](LICENSE) file for details ### Acknowledgements diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1a676b24b..1104f47ef 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,11 @@ - + tests/Monolog/ From ec3b35f72ccbb17778488671a3a784742a103f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20DECOOL?= Date: Thu, 4 Jun 2020 23:13:45 +0200 Subject: [PATCH 255/498] Fix array offset access on null in RavenHandler --- src/Monolog/Handler/RavenHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 1929f25fd..9d24dfe86 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -86,7 +86,7 @@ public function handleBatch(array $records) // the record with the highest severity is the "main" one $record = array_reduce($records, function ($highest, $record) { - if ($record['level'] > $highest['level']) { + if (null === $highest || $record['level'] > $highest['level']) { return $record; } From 27ce3a47d4206b6ecd4cd4fe462cdfb758285b64 Mon Sep 17 00:00:00 2001 From: Alex Elkins Date: Tue, 9 Jun 2020 21:43:19 -0400 Subject: [PATCH 256/498] Fix grammatical error --- src/Monolog/Handler/StreamHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 215ae02c8..3a3460d07 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -169,7 +169,7 @@ private function createDir(): void $status = mkdir($dir, 0777, true); restore_error_handler(); if (false === $status && !is_dir($dir)) { - throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir)); + throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } $this->dirCreated = true; From 4ef697d912f71bc584f6a0bfe27d26d71a0e38c0 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Mon, 22 Jun 2020 21:31:17 +0300 Subject: [PATCH 257/498] [Sendgrid] Allow int or string on sendgrid handler --- src/Monolog/Handler/SendGridHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index c154a5d17..e774d309b 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -56,10 +56,10 @@ class SendGridHandler extends MailHandler * @param string $from The sender of the email * @param string|array $to The recipients of the email * @param string $subject The subject of the mail - * @param int $level The minimum logging level at which this handler will be triggered + * @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 */ - public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, int $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) { parent::__construct($level, $bubble); $this->apiUser = $apiUser; From c6a56f0e33813f28f2b81e070423d8dc4e7e82c3 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Mon, 22 Jun 2020 21:39:58 +0300 Subject: [PATCH 258/498] Allow string also for level --- src/Monolog/Handler/OverflowHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 448f6334d..dbe9b22d1 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -61,13 +61,13 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter /** * @param HandlerInterface $handler * @param int[] $thresholdMap Dictionary of logger level => threshold - * @param int $level + * @param int|string $level The minimum logging level at which this handler will be triggered * @param bool $bubble */ public function __construct( HandlerInterface $handler, array $thresholdMap = [], - int $level = Logger::DEBUG, + $level = Logger::DEBUG, bool $bubble = true ) { $this->handler = $handler; From 1eafcbf040d046da152ebec74df1f9d53a558ed8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 8 Jul 2020 11:59:01 +0200 Subject: [PATCH 259/498] Allow null subjects in SwiftMailerHandler, fixes #1479 --- src/Monolog/Handler/SwiftMailerHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 88279d118..66264cb53 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -52,9 +52,9 @@ protected function send(string $content, array $records): void /** * Gets the formatter for the Swift_Message subject. * - * @param string $format The format of the subject + * @param string|null $format The format of the subject */ - protected function getSubjectFormatter(string $format): FormatterInterface + protected function getSubjectFormatter(?string $format): FormatterInterface { return new LineFormatter($format); } From 35a1e4de9bc8806275b6e03e96ce458b3221d198 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 8 Jul 2020 20:53:16 +0200 Subject: [PATCH 260/498] Fix php8 build --- tests/Monolog/Formatter/JsonFormatterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index dbc2a08cb..17a3ba823 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -189,8 +189,8 @@ public function testDefFormatWithResource() { $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); $record = $this->getRecord(); - $record['context'] = ['field_resource' => curl_init()]; - $this->assertEquals('{"message":"test","context":{"field_resource":"[resource(curl)]"},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); + $record['context'] = ['field_resource' => opendir(__DIR__)]; + $this->assertEquals('{"message":"test","context":{"field_resource":"[resource(stream)]"},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } /** From c3a05db90c1342e447969572084941fdd8a35240 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 8 Jul 2020 20:59:21 +0200 Subject: [PATCH 261/498] Fix unique_id in WebProcessor not being disableable, fixes #1470 --- src/Monolog/Processor/WebProcessor.php | 8 ++++---- tests/Monolog/Processor/WebProcessorTest.php | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 684188f66..2e8dfae1b 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -52,6 +52,10 @@ public function __construct($serverData = null, array $extraFields = null) throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); } + if (isset($this->serverData['UNIQUE_ID'])) { + $this->extraFields['unique_id'] = 'UNIQUE_ID'; + } + if (null !== $extraFields) { if (isset($extraFields[0])) { foreach (array_keys($this->extraFields) as $fieldName) { @@ -104,10 +108,6 @@ private function appendExtraFields(array $extra) $extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null; } - if (isset($this->serverData['UNIQUE_ID'])) { - $extra['unique_id'] = $this->serverData['UNIQUE_ID']; - } - return $extra; } } diff --git a/tests/Monolog/Processor/WebProcessorTest.php b/tests/Monolog/Processor/WebProcessorTest.php index 4105baf79..3e4effb6b 100644 --- a/tests/Monolog/Processor/WebProcessorTest.php +++ b/tests/Monolog/Processor/WebProcessorTest.php @@ -88,6 +88,19 @@ public function testProcessorAddsOnlyRequestedExtraFields() $this->assertSame(array('url' => 'A', 'http_method' => 'C'), $record['extra']); } + public function testProcessorAddsOnlyRequestedExtraFieldsIncludingOptionalFields() + { + $server = array( + 'REQUEST_URI' => 'A', + 'UNIQUE_ID' => 'X', + ); + + $processor = new WebProcessor($server, array('url')); + $record = $processor($this->getRecord()); + + $this->assertSame(array('url' => 'A'), $record['extra']); + } + public function testProcessorConfiguringOfExtraFields() { $server = array( From 0ae6fd8a09a1756c194b96e4d90d11ba69ec70a9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 8 Jul 2020 21:09:28 +0200 Subject: [PATCH 262/498] Fix removing of json options, fixes #1469 --- src/Monolog/Formatter/NormalizerFormatter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 3fdb3b459..41968310e 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -99,7 +99,7 @@ public function setJsonPrettyPrint(bool $enable): self if ($enable) { $this->jsonEncodeOptions |= JSON_PRETTY_PRINT; } else { - $this->jsonEncodeOptions ^= JSON_PRETTY_PRINT; + $this->jsonEncodeOptions &= ~JSON_PRETTY_PRINT; } return $this; @@ -255,6 +255,6 @@ public function addJsonEncodeOption($option) public function removeJsonEncodeOption($option) { - $this->jsonEncodeOptions ^= $option; + $this->jsonEncodeOptions &= ~$option; } } From 53e2c97b0bc2f831dbfe381f085ddbecd19d8fce Mon Sep 17 00:00:00 2001 From: Mponos George Date: Wed, 8 Jul 2020 22:40:29 +0300 Subject: [PATCH 263/498] Static analysis improvements (#1475) * Static analysis improvements * Fix review issues --- src/Monolog/Handler/FilterHandler.php | 2 ++ src/Monolog/Handler/FingersCrossedHandler.php | 2 ++ src/Monolog/Handler/MandrillHandler.php | 2 ++ src/Monolog/Handler/ProcessableHandlerInterface.php | 4 ++++ src/Monolog/Handler/SamplingHandler.php | 2 ++ src/Monolog/Handler/SwiftMailerHandler.php | 2 ++ src/Monolog/Handler/TestHandler.php | 5 ++++- src/Monolog/Logger.php | 2 ++ 8 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 77b45b999..ee1304d60 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -49,6 +49,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese protected $bubble; /** + * @psalm-param HandlerInterface|callable(?array, HandlerInterface): HandlerInterface $handler + * * @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 diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 3e529f50a..12d55a3a5 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -47,6 +47,8 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $bubble; /** + * @psalm-param HandlerInterface|callable(?array, FingersCrossedHandler): HandlerInterface $handler + * * @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. diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 46b8bff03..19aeeb3be 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -25,6 +25,8 @@ class MandrillHandler extends MailHandler protected $apiKey; /** + * @psalm-param Swift_Message|callable(string, array): 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 * @param string|int $level The minimum logging level at which this handler will be triggered diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 2c9557b40..41b52ce5f 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -23,6 +23,8 @@ interface ProcessableHandlerInterface /** * Adds a processor in the stack. * + * @psalm-param ProcessorInterface|callable(array): array $callback + * * @param ProcessorInterface|callable $callback * @return HandlerInterface self */ @@ -31,6 +33,8 @@ public function pushProcessor(callable $callback): HandlerInterface; /** * Removes the processor on top of the stack and returns it. * + * @psalm-return callable(array): array + * * @throws \LogicException In case the processor stack is empty * @return callable */ diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 296478738..d7953aa7c 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -42,6 +42,8 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter protected $factor; /** + * @psalm-param HandlerInterface|callable(array, HandlerInterface): HandlerInterface $handler + * * @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) */ diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 66264cb53..27bf6f078 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -28,6 +28,8 @@ class SwiftMailerHandler extends MailHandler private $messageTemplate; /** + * @psalm-param Swift_Message|callable(string, array): Swift_Message $message + * * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced * @param string|int $level The minimum logging level at which this handler will be triggered diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 4260f7404..568db512b 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -139,13 +139,16 @@ public function hasRecordThatContains(string $message, $level): bool */ public function hasRecordThatMatches(string $regex, $level): bool { - return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return $this->hasRecordThatPasses(function (array $rec) use ($regex): bool { return preg_match($regex, $rec['message']) > 0; }, $level); } /** + * @psalm-param callable(array, int): mixed $predicate + * * @param string|int $level Logging level value or name + * @return bool */ public function hasRecordThatPasses(callable $predicate, $level) { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 9242f6ee9..b8e2db98f 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -140,6 +140,8 @@ class Logger implements LoggerInterface, ResettableInterface protected $exceptionHandler; /** + * @psalm-param 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 From a54cd1f1782f62714e4d28651224316bb5540e08 Mon Sep 17 00:00:00 2001 From: Mponos George Date: Wed, 8 Jul 2020 23:02:57 +0300 Subject: [PATCH 264/498] Replace call_user_func --- src/Monolog/ErrorHandler.php | 4 ++-- src/Monolog/Handler/FilterHandler.php | 2 +- src/Monolog/Handler/FingersCrossedHandler.php | 2 +- src/Monolog/Handler/MandrillHandler.php | 2 +- src/Monolog/Handler/SamplingHandler.php | 2 +- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- src/Monolog/Handler/TestHandler.php | 2 +- src/Monolog/Logger.php | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 2643fdb87..89381b9a7 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -166,7 +166,7 @@ public function handleException($e) ); if ($this->previousExceptionHandler) { - call_user_func($this->previousExceptionHandler, $e); + ($this->previousExceptionHandler)($e); } if (!headers_sent() && !ini_get('display_errors')) { @@ -198,7 +198,7 @@ public function handleError($code, $message, $file = '', $line = 0, $context = [ if ($this->previousErrorHandler === true) { return false; } elseif ($this->previousErrorHandler) { - return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); + return ($this->previousErrorHandler)($code, $message, $file, $line, $context); } return true; diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index ee1304d60..735fdfbd3 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -145,7 +145,7 @@ public function handleBatch(array $records): void public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 12d55a3a5..7424b1084 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -188,7 +188,7 @@ private function flushBuffer(): void public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 19aeeb3be..2a3b49c5f 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -37,7 +37,7 @@ public function __construct(string $apiKey, $message, $level = Logger::ERROR, bo parent::__construct($level, $bubble); if (!$message instanceof \Swift_Message && is_callable($message)) { - $message = call_user_func($message); + $message = $message(); } if (!$message instanceof \Swift_Message) { throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index d7953aa7c..6dcf59961 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -86,7 +86,7 @@ public function handle(array $record): bool public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 27bf6f078..6b3e49500 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -75,7 +75,7 @@ protected function buildMessage(string $content, array $records): Swift_Message $message = clone $this->messageTemplate; $message->generateId(); } elseif (is_callable($this->messageTemplate)) { - $message = call_user_func($this->messageTemplate, $content, $records); + $message = ($this->messageTemplate)($content, $records); } if (!$message instanceof Swift_Message) { diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 568db512b..9fa77b9fa 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -159,7 +159,7 @@ public function hasRecordThatPasses(callable $predicate, $level) } foreach ($this->recordsByLevel[$level] as $i => $rec) { - if (call_user_func($predicate, $rec, $i)) { + if ($predicate($rec, $i)) { return true; } } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index b8e2db98f..0fb5196bd 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -312,7 +312,7 @@ public function addRecord(int $level, string $message, array $context = []): boo try { foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); + $record = $processor($record); } // advance the array pointer to the first handler that will handle this record @@ -610,6 +610,6 @@ protected function handleException(Throwable $e, array $record) throw $e; } - call_user_func($this->exceptionHandler, $e, $record); + ($this->exceptionHandler)($e, $record); } } From bcca19cee0ed507f342d39688a071e7c989393d8 Mon Sep 17 00:00:00 2001 From: axell-brendow Date: Wed, 22 Jul 2020 13:06:59 -0300 Subject: [PATCH 265/498] Improve exception message This exception is commonly thrown in Laravel applications when using Docker. But it is not clear why the system could not open a file that has read permission for all users. So, when I came to the code of Monolog I saw that you try to open it in append mode, so I think that just adding this information could help a lot other users. --- src/Monolog/Handler/StreamHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 7c0dfd22b..b52607d2e 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -106,7 +106,8 @@ protected function write(array $record) restore_error_handler(); if (!is_resource($this->stream)) { $this->stream = null; - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url)); + + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); } } From 1817faadd1846cd08be9a49e905dc68823bc38c0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 23 Jul 2020 10:35:51 +0200 Subject: [PATCH 266/498] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31512f013..757643df9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### 1.25.5 (2020-07-23) + + * Fixed array access on null in RavenHandler + * Fixed unique_id in WebProcessor not being disableable + ### 1.25.4 (2020-05-22) * Fixed GitProcessor type error when there is no git repo present From f9eee5cec93dfb313a38b6b288741e84e53f02d5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 23 Jul 2020 10:41:23 +0200 Subject: [PATCH 267/498] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63fbe34c4..e39c390b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### 2.1.1 (2020-07-23) + + * Fixed removing of json encoding options + * Fixed type hint of $level not accepting strings in SendGridHandler and OverflowHandler + * Fixed SwiftMailerHandler not accepting email templates with an empty subject + * Fixed array access on null in RavenHandler + * Fixed unique_id in WebProcessor not being disableable + ### 2.1.0 (2020-05-22) * Added `JSON_INVALID_UTF8_SUBSTITUTE` to default json flags, so that invalid UTF8 characters now get converted to [�](https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character) instead of being converted from ISO-8859-15 to UTF8 as it was before, which was hardly a comprehensive solution From c282728812ee503a70d944bbdc9bbd07d48180be Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov Date: Mon, 27 Jul 2020 12:50:54 +0300 Subject: [PATCH 268/498] Update TelegramBotHandler.php Parameters `$level` and `$bubble` are already passed to parent constructor, no need to set them again. Also setting `$level` without `setLevel()` makes it incomparable as it is not converted to int via `Logger::toMonologLevel()`. --- src/Monolog/Handler/TelegramBotHandler.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 3abb646ec..bec080b8e 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -93,8 +93,6 @@ public function __construct( $this->apiKey = $apiKey; $this->channel = $channel; - $this->level = $level; - $this->bubble = $bubble; $this->setParseMode($parseMode); $this->disableWebPagePreview($disableWebPagePreview); $this->disableNotification($disableNotification); From fa78dd44004221145701cf3fcdf66d61ebbbce7e Mon Sep 17 00:00:00 2001 From: Dino Korah Date: Tue, 4 Aug 2020 12:09:20 +0100 Subject: [PATCH 269/498] Backport PsrLogMessageProcessor from master (2.x) --- .../Processor/PsrLogMessageProcessor.php | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 008850545..3d12522f1 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -22,6 +22,24 @@ */ class PsrLogMessageProcessor implements ProcessorInterface { + const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; + + /** @var string|null */ + private $dateFormat; + + /** @var bool */ + private $removeUsedContextFields; + + /** + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format + * @param bool $removeUsedContextFields If set to true the fields interpolated into message gets unset + */ + public function __construct($dateFormat = null, $removeUsedContextFields = false) + { + $this->dateFormat = $dateFormat; + $this->removeUsedContextFields = $removeUsedContextFields; + } + /** * @param array $record * @return array @@ -34,12 +52,25 @@ public function __invoke(array $record) $replacements = array(); foreach ($record['context'] as $key => $val) { + $placeholder = '{' . $key . '}'; + if (strpos($record['message'], $placeholder) === false) { + continue; + } + if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { - $replacements['{'.$key.'}'] = $val; + $replacements[$placeholder] = $val; + } elseif ($val instanceof \DateTime) { + $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE); } elseif (is_object($val)) { - $replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']'; + $replacements[$placeholder] = '[object '.Utils::getClass($val).']'; + } elseif (is_array($val)) { + $replacements[$placeholder] = 'array'.@json_encode($val); } else { - $replacements['{'.$key.'}'] = '['.gettype($val).']'; + $replacements[$placeholder] = '['.gettype($val).']'; + } + + if ($this->removeUsedContextFields) { + unset($record['context'][$key]); } } From a05c1a973289ac2a9e404329ad122fbca993367b Mon Sep 17 00:00:00 2001 From: Dino Korah Date: Tue, 4 Aug 2020 12:25:34 +0100 Subject: [PATCH 270/498] Fix broken unit tests --- .../Processor/PsrLogMessageProcessorTest.php | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Processor/PsrLogMessageProcessorTest.php b/tests/Monolog/Processor/PsrLogMessageProcessorTest.php index 029a0c02d..957aebab7 100644 --- a/tests/Monolog/Processor/PsrLogMessageProcessorTest.php +++ b/tests/Monolog/Processor/PsrLogMessageProcessorTest.php @@ -27,8 +27,37 @@ public function testReplacement($val, $expected) $this->assertEquals($expected, $message['message']); } + public function testReplacementWithContextRemoval() + { + $proc = new PsrLogMessageProcessor($dateFormat = null, $removeUsedContextFields = true); + + $message = $proc(array( + 'message' => '{foo}', + 'context' => array('foo' => 'bar', 'lorem' => 'ipsum'), + )); + $this->assertSame('bar', $message['message']); + $this->assertSame(array('lorem' => 'ipsum'), $message['context']); + } + + public function testCustomDateFormat() + { + $format = "Y-m-d"; + $date = new \DateTime(); + + $proc = new PsrLogMessageProcessor($format); + + $message = $proc(array( + 'message' => '{foo}', + 'context' => array('foo' => $date), + )); + $this->assertEquals($date->format($format), $message['message']); + $this->assertSame(array('foo' => $date), $message['context']); + } + public function getPairs() { + $date = new \DateTime(); + return array( array('foo', 'foo'), array('3', '3'), @@ -36,8 +65,12 @@ public function getPairs() array(null, ''), array(true, '1'), array(false, ''), + array($date, $date->format(PsrLogMessageProcessor::SIMPLE_DATE)), array(new \stdClass, '[object stdClass]'), - array(array(), '[array]'), + array(array(), 'array[]'), + array(array(1, 2, 3), 'array[1,2,3]'), + array(array('foo' => 'bar'), 'array{"foo":"bar"}'), + array(stream_context_create(), '[resource]'), ); } } From bf1a76edb4534235f88b2c6c9dac0e98af83edd6 Mon Sep 17 00:00:00 2001 From: Kim Pepper Date: Thu, 13 Aug 2020 14:06:38 +1000 Subject: [PATCH 271/498] Adds support for unix sockets --- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 3 ++- src/Monolog/Handler/SyslogUdpHandler.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index c43bc156b..63ee3014c 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -28,7 +28,8 @@ public function __construct(string $ip, int $port = 514) { $this->ip = $ip; $this->port = $port; - $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + $domain = $port === 0 ? AF_UNIX : AF_INET; + $this->socket = socket_create($domain, SOCK_DGRAM, SOL_UDP); } public function write($line, $header = "") diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index c85ef5b82..4c8a6c0f1 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -51,7 +51,7 @@ public function __construct(string $host, int $port = 514, $facility = LOG_USER, $this->ident = $ident; $this->rfc = $rfc; - $this->socket = new UdpSocket($host, $port ?: 514); + $this->socket = new UdpSocket($host, $port); } protected function write(array $record): void From 2d506686587f5b08e50c2e5e476e6e7d90a41988 Mon Sep 17 00:00:00 2001 From: Anton Gorlanov Date: Thu, 13 Aug 2020 12:53:19 +0300 Subject: [PATCH 272/498] Speed up Logger::addRecord --- src/Monolog/Logger.php | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 0fb5196bd..8e6698a72 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -285,16 +285,18 @@ public function useMicrosecondTimestamps(bool $micro) */ public function addRecord(int $level, string $message, array $context = []): bool { - // check if any handler will handle this message so we can return early and save cycles - $handlerKey = null; - foreach ($this->handlers as $key => $handler) { + $offset = 0; + foreach ($this->handlers as $handler) { if ($handler->isHandling(['level' => $level])) { - $handlerKey = $key; break; } + + $offset++; } + // cut off checked not handleable handlers + $remainedHandlers = array_slice($this->handlers, $offset); - if (null === $handlerKey) { + if (!$remainedHandlers) { return false; } @@ -315,18 +317,10 @@ public function addRecord(int $level, string $message, array $context = []): boo $record = $processor($record); } - // advance the array pointer to the first handler that will handle this record - reset($this->handlers); - while ($handlerKey !== key($this->handlers)) { - next($this->handlers); - } - - while ($handler = current($this->handlers)) { + foreach ($remainedHandlers as $handler) { if (true === $handler->handle($record)) { break; } - - next($this->handlers); } } catch (Throwable $e) { $this->handleException($e, $record); From 1eaf4c2bf54cea5f0f8d759661bd142e4cf3fb2a Mon Sep 17 00:00:00 2001 From: Kim Pepper Date: Fri, 14 Aug 2020 10:29:13 +1000 Subject: [PATCH 273/498] Change protocol --- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 63ee3014c..371edb49e 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -28,8 +28,14 @@ public function __construct(string $ip, int $port = 514) { $this->ip = $ip; $this->port = $port; - $domain = $port === 0 ? AF_UNIX : AF_INET; - $this->socket = socket_create($domain, SOCK_DGRAM, SOL_UDP); + $domain = AF_INET; + $protocol = SOL_UDP; + // Check if we are using unix sockets. + if ($port === 0) { + $domain = AF_UNIX; + $protocol = IPPROTO_IP; + } + $this->socket = socket_create($domain, SOCK_DGRAM, $protocol); } public function write($line, $header = "") From 0af0cd83382bbb70fa2f033fdc96ad8a4b3888d0 Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Fri, 14 Aug 2020 11:41:52 +0200 Subject: [PATCH 274/498] BUGFIX substr() broke when passing a NULL because of strict type in case mb mod not installed --- src/Monolog/Utils.php | 2 +- test.php | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 test.php diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 007ad686b..7515eadbe 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -31,7 +31,7 @@ public static function substr(string $string, int $start, ?int $length = null) return mb_strcut($string, $start, $length); } - return substr($string, $start, $length); + return substr($string, $start, $length ?: strlen($string)); } /** diff --git a/test.php b/test.php new file mode 100644 index 000000000..e69de29bb From 515621a0bb1d3cab214b577b1766585eb2a6ccbe Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Fri, 14 Aug 2020 19:53:15 +0200 Subject: [PATCH 275/498] Delete test.php --- test.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.php diff --git a/test.php b/test.php deleted file mode 100644 index e69de29bb..000000000 From fad3e427c78266abf428c76b11e50ee9f537fb7f Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Tue, 18 Aug 2020 16:32:06 +0200 Subject: [PATCH 276/498] Made the check in substr() strict compare to NULL --- src/Monolog/Utils.php | 2 +- test.php | 0 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 test.php diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 7515eadbe..5299d441a 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -31,7 +31,7 @@ public static function substr(string $string, int $start, ?int $length = null) return mb_strcut($string, $start, $length); } - return substr($string, $start, $length ?: strlen($string)); + return substr($string, $start, (null === $length) ? strlen($string) : $length); } /** diff --git a/test.php b/test.php deleted file mode 100644 index e69de29bb..000000000 From 8c1efc5a7748924e27b805d6a827cbaa438bec4e Mon Sep 17 00:00:00 2001 From: Chris Barr Date: Sat, 22 Aug 2020 23:37:15 +0100 Subject: [PATCH 277/498] Minor docs fixes --- doc/02-handlers-formatters-processors.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index bf9417ebc..3748233b0 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -86,8 +86,8 @@ ### Wrappers / Special Handlers -- [_FingersCrossedHandler_](../src/Monolog/Handler/FingersCrossedHandler.php): A very interesting wrapper. It takes a logger as - parameter and will accumulate log records of all levels until a record +- [_FingersCrossedHandler_](../src/Monolog/Handler/FingersCrossedHandler.php): A very interesting wrapper. It takes a handler as + a parameter and will accumulate log records of all levels until a record exceeds the defined severity level. At which point it delivers all records, including those of lower severity, to the handler it wraps. This means that until an error actually happens you will not see anything in your logs, but @@ -95,7 +95,7 @@ records. This provides you with all the information you need, but only when you need it. - [_DeduplicationHandler_](../src/Monolog/Handler/DeduplicationHandler.php): Useful if you are sending notifications or emails - when critical errors occur. It takes a logger as parameter and will + when critical errors occur. It takes a handler as a parameter and will accumulate log records of all levels until the end of the request (or `flush()` is called). At that point it delivers all records to the handler it wraps, but only if the records are unique over a given time period @@ -134,7 +134,7 @@ - [_HandlerWrapper_](../src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create your own wrappers easily. - [_OverflowHandler_](../src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it - receives, up until a configured threshold of number of messages of a certain lever is reached, after it will pass all + receives, up until a configured threshold of number of messages of a certain level is reached, after it will pass all log messages to the wrapped handler. Useful for applying in batch processing when you're only interested in significant failures instead of minor, single erroneous events. From 36e25bafe07837861208d69c46d9dc8c404d4907 Mon Sep 17 00:00:00 2001 From: Pierre Lannoy Date: Thu, 3 Sep 2020 14:22:34 +0200 Subject: [PATCH 278/498] Support for extended RFC5424 timestamp format As described in [RFC5424 Timestamp format](https://tools.ietf.org/html/rfc5424#section-6.2.3), it is allowed to send second fraction as doted mili (3 digits) or micro (6 digits) in syslog messages. I suggest this modest PR to support it. --- src/Monolog/Handler/SyslogUdpHandler.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 4c8a6c0f1..75ce293f8 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -25,10 +25,12 @@ class SyslogUdpHandler extends AbstractSyslogHandler { const RFC3164 = 0; const RFC5424 = 1; + const RFC5424e = 2; private $dateFormats = array( self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, + self::RFC5424e => \DateTime::RFC3339_EXTENDED, ); protected $socket; From 7640be31a1ac4114bdad0588b1e5aca80bf4ff81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Faug=C3=A8re=20Ga=C3=ABtan?= Date: Thu, 1 Oct 2020 17:30:47 +0200 Subject: [PATCH 279/498] Adding Redis Pub/Sub handler (closes #574) --- src/Monolog/Handler/RedisPubSubHandler.php | 67 ++++++++++++++++ .../Handler/RedisPubSubHandlerTest.php | 76 +++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 src/Monolog/Handler/RedisPubSubHandler.php create mode 100644 tests/Monolog/Handler/RedisPubSubHandlerTest.php diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php new file mode 100644 index 000000000..c9b13198b --- /dev/null +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; + +/** + * Sends the message to a Redis Pub/Sub channel using PUBLISH + * + * usage example: + * + * $log = new Logger('application'); + * $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING); + * $log->pushHandler($redis); + * + * @author Gaëtan Faugère + */ +class RedisPubSubHandler extends AbstractProcessingHandler +{ + private $redisClient; + private $channelKey; + + /** + * @param \Predis\Client|\Redis $redis The redis instance + * @param string $key The channel key to publish records to + * @param string|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($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; + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record): void + { + $this->redisClient->publish($this->channelKey, $record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new LineFormatter(); + } +} diff --git a/tests/Monolog/Handler/RedisPubSubHandlerTest.php b/tests/Monolog/Handler/RedisPubSubHandlerTest.php new file mode 100644 index 000000000..5a37d4100 --- /dev/null +++ b/tests/Monolog/Handler/RedisPubSubHandlerTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Test\TestCase; +use Monolog\Logger; +use Monolog\Formatter\LineFormatter; + +class RedisPubSubHandlerTest extends TestCase +{ + public function testConstructorShouldThrowExceptionForInvalidRedis() + { + $this->expectException(\InvalidArgumentException::class); + + new RedisPubSubHandler(new \stdClass(), 'key'); + } + + public function testConstructorShouldWorkWithPredis() + { + $redis = $this->createMock('Predis\Client'); + $this->assertInstanceof('Monolog\Handler\RedisPubSubHandler', new RedisPubSubHandler($redis, 'key')); + } + + public function testConstructorShouldWorkWithRedis() + { + if (!class_exists('Redis')) { + $this->markTestSkipped('The redis ext is required to run this test'); + } + + $redis = $this->createMock('Redis'); + $this->assertInstanceof('Monolog\Handler\RedisPubSubHandler', new RedisPubSubHandler($redis, 'key')); + } + + public function testPredisHandle() + { + $redis = $this->prophesize('Predis\Client'); + $redis->publish('key', 'test')->shouldBeCalled(); + $redis = $redis->reveal(); + + $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]); + + $handler = new RedisPubSubHandler($redis, 'key'); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } + + public function testRedisHandle() + { + if (!class_exists('Redis')) { + $this->markTestSkipped('The redis ext is required to run this test'); + } + + $redis = $this->createPartialMock('Redis', ['publish']); + + $redis->expects($this->once()) + ->method('publish') + ->with('key', 'test'); + + $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]); + + $handler = new RedisPubSubHandler($redis, 'key'); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } +} From 22fb0872fc8ddde455ee120cef92a360627dba7f Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Thu, 8 Oct 2020 10:22:51 +0200 Subject: [PATCH 280/498] chore(doc:formatters): fix typo --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 3748233b0..9e76b8740 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -153,7 +153,7 @@ - [_LogglyFormatter_](../src/Monolog/Formatter/LogglyFormatter.php): Used to format log records into Loggly messages, only useful for the LogglyHandler. - [_FlowdockFormatter_](../src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. - [_MongoDBFormatter_](../src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. -- [_LogmaticFormatter_](../src/Monolog/Formatter/LogmaticFormatter.php): User to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. +- [_LogmaticFormatter_](../src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. ## Processors From 4813c673bd8eedfd553e15af07950c9100bcc872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Pan=C3=AD=C4=8Dek?= <693432+adrianpanicek@users.noreply.github.com> Date: Tue, 27 Oct 2020 11:04:07 +0100 Subject: [PATCH 281/498] Allow string numeric log levels --- src/Monolog/Logger.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 0fb5196bd..db9ff3f52 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -410,6 +410,10 @@ public static function getLevelName(int $level): string public static function toMonologLevel($level): int { if (is_string($level)) { + if (is_numeric($level)) { + return intval($level); + } + // 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($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); From 39637a5d0e98068d98189ce48a87f3dd61455429 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 29 Oct 2020 16:43:01 +0100 Subject: [PATCH 282/498] =?UTF-8?q?https=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9e54787c1..46e141c00 100644 --- a/composer.json +++ b/composer.json @@ -2,14 +2,14 @@ "name": "monolog/monolog", "description": "Sends your logs to files, sockets, inboxes, databases and various web services", "keywords": ["log", "logging", "psr-3"], - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "type": "library", "license": "MIT", "authors": [ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "require": { From 1b5dcaad88ffde1b6a6418062e7986aaf263d999 Mon Sep 17 00:00:00 2001 From: Anton Perevoshchikov Date: Sat, 7 Nov 2020 17:05:17 +0300 Subject: [PATCH 283/498] Adds return value in handler wrapper --- src/Monolog/Handler/HandlerWrapper.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index 3f2c7a1a7..9bbca380d 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -108,6 +108,8 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface { if ($this->handler instanceof FormattableHandlerInterface) { $this->handler->setFormatter($formatter); + + return $this; } throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); From 6ad9e52f5d3f4122ab2617f169fdda2c5ee12f26 Mon Sep 17 00:00:00 2001 From: idevin Date: Thu, 19 Nov 2020 05:48:57 +0300 Subject: [PATCH 284/498] remove @internal annotation getClass is not internal method --- src/Monolog/Utils.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 5299d441a..f68473e6a 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -15,9 +15,6 @@ final class Utils { const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION | JSON_INVALID_UTF8_SUBSTITUTE; - /** - * @internal - */ public static function getClass($object): string { $class = \get_class($object); From 1106f259c2e7c912c0f4c0098bfbe749e9e0f8b7 Mon Sep 17 00:00:00 2001 From: milos Date: Mon, 30 Nov 2020 17:40:22 +0100 Subject: [PATCH 285/498] add support to define writetimeout in ms --- src/Monolog/Handler/SocketHandler.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 2861e67d7..698360b75 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -352,10 +352,11 @@ private function writeToSocket(string $data): void } } - private function writingIsTimedOut(int $sent): bool + private function writingIsTimedOut($sent) { - $writingTimeout = (int) floor($this->writingTimeout); - if (0 === $writingTimeout) { + // convert to ms + $writingTimeoutMs = $this->writingTimeout * 1000; + if (0 === $writingTimeoutMs) { return false; } @@ -368,7 +369,10 @@ private function writingIsTimedOut(int $sent): bool usleep(100); } - if ((time() - $this->lastWritingAt) >= $writingTimeout) { + // convert to ms + $lastWritingMs = (time() - $this->lastWritingAt) * 1000; + + if ($lastWritingMs >= $writingTimeoutMs) { $this->closeSocket(); return true; From 38367d3f48e673d311d44bc45a50f11a6f3f7e66 Mon Sep 17 00:00:00 2001 From: milos Date: Mon, 30 Nov 2020 17:42:04 +0100 Subject: [PATCH 286/498] add support to define writetimeout in ms --- src/Monolog/Handler/SocketHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 698360b75..c2a254711 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -352,7 +352,7 @@ private function writeToSocket(string $data): void } } - private function writingIsTimedOut($sent) + private function writingIsTimedOut(int $sent): bool { // convert to ms $writingTimeoutMs = $this->writingTimeout * 1000; From 6087181108f9c8f82184aa388b6813025b3e2cf4 Mon Sep 17 00:00:00 2001 From: Victor Bocharsky Date: Mon, 30 Nov 2020 23:01:43 +0200 Subject: [PATCH 287/498] Remove duplicated article in PHPDoc comment --- src/Monolog/Handler/SlackHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index c2b93e610..1535a1804 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -44,7 +44,7 @@ class SlackHandler extends SocketHandler * @param string|null $iconEmoji The emoji name to use (or null) * @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 - * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style + * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured From 279cf6a9004fa611f74995023939492e6d0d0055 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 13:49:22 +0100 Subject: [PATCH 288/498] Migrate to GH actions, add phpstan --- .github/workflows/continuous-integration.yml | 69 ++++++++++++++++++++ .github/workflows/lint.yml | 37 +++++++++++ .github/workflows/phpstan.yml | 46 +++++++++++++ .gitignore | 1 + .travis.yml | 35 ---------- composer.json | 13 +--- phpstan.neon.dist | 16 +++++ src/Monolog/ErrorHandler.php | 1 + src/Monolog/Handler/DynamoDbHandler.php | 1 + src/Monolog/Handler/FirePHPHandler.php | 2 +- src/Monolog/Handler/GelfHandler.php | 2 +- src/Monolog/Handler/HipChatHandler.php | 4 +- src/Monolog/Handler/RavenHandler.php | 2 +- src/Monolog/Handler/RedisHandler.php | 2 +- src/Monolog/Handler/StreamHandler.php | 2 +- src/Monolog/Logger.php | 2 +- src/Monolog/Utils.php | 2 +- 17 files changed, 183 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/continuous-integration.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/phpstan.yml delete mode 100644 .travis.yml create mode 100644 phpstan.neon.dist diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..a05ef5997 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,69 @@ +name: "Continuous Integration" + +on: + - push + - pull_request + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + +jobs: + tests: + name: "CI" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "5.3" + - "5.4" + - "5.5" + - "5.6" + - "7.0" + - "7.1" + - "7.2" + - "7.3" + - "7.4" + - "8.0" + # disabled for now as it leads to PHPUnit installing in a very old 4.3 version due to phpspec/prophecy not allowing 8.1 + # - "8.1" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP 5" + if: "startsWith(matrix.php-version, '5.')" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: "mongo" + + - name: "Install PHP 7+" + if: "!startsWith(matrix.php-version, '5.')" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Install latest dependencies" + run: | + # Remove PHPStan as it requires a newer PHP + composer remove phpstan/phpstan --dev --no-update + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "Run tests" + run: "composer test" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..4daf1c113 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,37 @@ +name: "PHP Lint" + +on: + push: + pull_request: + +jobs: + tests: + name: "Lint" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "5.3" + - "8.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + extensions: "intl" + ini-values: "memory_limit=-1" + php-version: "${{ matrix.php-version }}" + + - name: "Lint PHP files on 5.3" + if: "matrix.php-version == '5.3'" + run: "find src/ -type f -name '*.php' -exclude '*Trait.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" + + - name: "Lint PHP files" + if: "matrix.php-version != '5.3'" + run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 000000000..b26a5573d --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,46 @@ +name: "PHPStan" + +on: + - push + - pull_request + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + +jobs: + tests: + name: "PHPStan" + + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: + - "8.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: Get composer cache directory + id: composercache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Install latest dependencies" + run: "composer update ${{ env.COMPOSER_FLAGS }}" + + - name: Run PHPStan + run: composer phpstan diff --git a/.gitignore b/.gitignore index 0640915db..a3ec4bab3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ composer.lock .DS_Store .php_cs.cache .hg +.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fe999c207..000000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: php - -matrix: - fast_finish: true - include: - - dist: precise - php: 5.3 - env: deps=low - - dist: precise - php: 5.3 - - php: 5.4 - dist: trusty - - php: 5.5 - dist: trusty - - php: 5.6 - dist: xenial - - php: 7.0 - dist: xenial - - php: 7.1 - dist: bionic - - php: 7.2 - dist: bionic - - php: 7.3 - dist: bionic - - php: 7.4 - dist: bionic - -before_script: - - if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi - - if [ "$TRAVIS_PHP_VERSION" == "7.4" ]; then echo "error_reporting = E_ALL & ~E_DEPRECATED" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi - - composer self-update --snapshot - - if [ "$deps" == "low" ]; then composer update -n --prefer-dist --prefer-lowest --prefer-stable; fi - - if [ "$deps" != "low" ]; then composer update -n --prefer-dist; fi - -script: composer test diff --git a/composer.json b/composer.json index e171e2029..d2deab7b8 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "php-amqplib/php-amqplib": "~2.4", "swiftmailer/swiftmailer": "^5.3|^6.0", "php-console/php-console": "^3.1.3", - "php-parallel-lint/php-parallel-lint": "^1.0" + "phpstan/phpstan": "^0.12.59" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", @@ -50,16 +50,9 @@ "provide": { "psr/log-implementation": "1.0.0" }, - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "scripts": { - "test": [ - "parallel-lint . --exclude vendor --exclude src/Monolog/Handler/FormattableHandlerInterface.php --exclude src/Monolog/Handler/FormattableHandlerTrait.php --exclude src/Monolog/Handler/ProcessableHandlerInterface.php --exclude src/Monolog/Handler/ProcessableHandlerTrait.php", - "phpunit" - ] + "test": "vendor/bin/phpunit", + "phpstan": "vendor/bin/phpstan analyse" }, "lock": false } diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 000000000..1fe45df73 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,16 @@ +parameters: + level: 3 + + paths: + - src/ +# - tests/ + + + ignoreErrors: + - '#zend_monitor_|ZEND_MONITOR_#' + - '#RollbarNotifier#' + - '#Predis\\Client#' + - '#^Cannot call method ltrim\(\) on int\|false.$#' + - '#^Access to an undefined property Raven_Client::\$context.$#' + - '#MongoDB\\(Client|Collection)#' + - '#Gelf\\IMessagePublisher#' diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 36ec0098f..5121c2cd0 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -62,6 +62,7 @@ public static function register(LoggerInterface $logger, $errorLevelMap = array( //Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929 class_exists('\\Psr\\Log\\LogLevel', true); + /** @phpstan-ignore-next-line */ $handler = new static($logger); if ($errorLevelMap !== false) { $handler->registerErrorHandler($errorLevelMap); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 237b71f61..8846e0a08 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -77,6 +77,7 @@ protected function write(array $record) if ($this->version === 3) { $formatted = $this->marshaler->marshalItem($filtered); } else { + /** @phpstan-ignore-next-line */ $formatted = $this->client->formatAttributes($filtered); } diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index c30b1843c..2a171bd82 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -72,7 +72,7 @@ protected function createHeader(array $meta, $message) * * @see createHeader() * @param array $record - * @return string + * @return array */ protected function createRecordHeader(array $record) { diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 71e466934..b6cde7c65 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -27,7 +27,7 @@ class GelfHandler extends AbstractProcessingHandler { /** - * @var Publisher the publisher object that sends the message to the server + * @var Publisher|PublisherInterface|IMessagePublisher the publisher object that sends the message to the server */ protected $publisher; diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index 179d62686..30258e36e 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -270,10 +270,10 @@ public function handleBatch(array $records) * will be the highest level from the given records. Datetime will be taken * from the first record. * - * @param $records + * @param array $records * @return array */ - private function combineRecords($records) + private function combineRecords(array $records) { $batchRecord = null; $batchRecords = array(); diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 9d24dfe86..b0298fa6c 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -50,7 +50,7 @@ class RavenHandler extends AbstractProcessingHandler protected $ravenClient; /** - * @var LineFormatter The formatter to use for the logs generated via handleBatch() + * @var FormatterInterface The formatter to use for the logs generated via handleBatch() */ protected $batchFormatter; diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index bb00db509..3725db242 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -36,7 +36,7 @@ class RedisHandler extends AbstractProcessingHandler * @param string $key The key name to push records to * @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 - * @param int $capSize Number of entries to limit list size to + * @param int|false $capSize Number of entries to limit list size to */ public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false) { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index b52607d2e..ad6960cb2 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -154,7 +154,7 @@ private function getDirFromStream($stream) return dirname(substr($stream, 7)); } - return; + return null; } private function createDir() diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index e649af51b..b8b4f55b4 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -522,7 +522,7 @@ public static function getLevelName($level) /** * Converts PSR-3 levels to Monolog ones if necessary * - * @param string|int Level number (monolog) or name (PSR-3) + * @param string|int $level Level number (monolog) or name (PSR-3) * @return int */ public static function toMonologLevel($level) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 712b19692..7f1ba129e 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -168,7 +168,7 @@ private static function throwEncodeError($code, $data) * Function converts the input in place in the passed variable so that it * can be used as a callback for array_walk_recursive. * - * @param mixed &$data Input to check and convert if needed + * @param mixed $data Input to check and convert if needed, passed by ref * @private */ public static function detectAndCleanUtf8(&$data) From d3f4f48f0f1a400296db7fb05380574010187a52 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 13:54:14 +0100 Subject: [PATCH 289/498] Fix lint task --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4daf1c113..da908ccfe 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,7 +30,7 @@ jobs: - name: "Lint PHP files on 5.3" if: "matrix.php-version == '5.3'" - run: "find src/ -type f -name '*.php' -exclude '*Trait.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" + run: "find src/ -type f -name '*.php' -not -name '*Trait.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" - name: "Lint PHP files" if: "matrix.php-version != '5.3'" From 24a9588865006395cd724ac4769c9ec3c7f6de6b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 13:56:13 +0100 Subject: [PATCH 290/498] Disable php 8 build for v1 --- .github/workflows/continuous-integration.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a05ef5997..f4de761b9 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -25,7 +25,8 @@ jobs: - "7.2" - "7.3" - "7.4" - - "8.0" + # disabled for monolog 1.x as not worth the trouble, people should use monolog 2 anyway + # - "8.0" # disabled for now as it leads to PHPUnit installing in a very old 4.3 version due to phpspec/prophecy not allowing 8.1 # - "8.1" From 7c977e451c0af0cc8de233871966fc21c46a42ac Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 13:58:31 +0100 Subject: [PATCH 291/498] Fix lint --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index da908ccfe..8c26a72d0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,7 +30,7 @@ jobs: - name: "Lint PHP files on 5.3" if: "matrix.php-version == '5.3'" - run: "find src/ -type f -name '*.php' -not -name '*Trait.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" + run: "find src/ -type f -name '*.php' -not -name '*Trait.php' -not -name 'FormattableHandlerInterface.php' -not -name 'ProcessableHandlerInterface.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" - name: "Lint PHP files" if: "matrix.php-version != '5.3'" From c5853b9b0fbf5f9c5599574b17016f8c641e8f42 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 14:22:04 +0100 Subject: [PATCH 292/498] Improve build --- .github/workflows/continuous-integration.yml | 27 +++++++++++++++++-- phpstan.neon.dist | 15 ++++++----- src/Monolog/ErrorHandler.php | 11 ++++---- .../Formatter/GelfMessageFormatter.php | 1 + src/Monolog/Formatter/JsonFormatter.php | 2 -- src/Monolog/Formatter/LineFormatter.php | 3 --- src/Monolog/Formatter/MongoDBFormatter.php | 4 +-- src/Monolog/Formatter/NormalizerFormatter.php | 15 +++++------ src/Monolog/Formatter/ScalarFormatter.php | 4 +-- src/Monolog/Formatter/WildfireFormatter.php | 2 +- src/Monolog/Handler/DynamoDbHandler.php | 1 + src/Monolog/Handler/FilterHandler.php | 16 ++++++++--- src/Monolog/Handler/FingersCrossedHandler.php | 16 ++++++++--- .../Handler/FormattableHandlerTrait.php | 3 +-- src/Monolog/Handler/HandlerWrapper.php | 2 +- src/Monolog/Handler/LogglyHandler.php | 6 ++--- src/Monolog/Handler/MandrillHandler.php | 19 ++++++++----- src/Monolog/Handler/OverflowHandler.php | 14 +++++++--- src/Monolog/Handler/PHPConsoleHandler.php | 3 --- .../Handler/ProcessableHandlerTrait.php | 1 - src/Monolog/Handler/SamplingHandler.php | 16 ++++++++--- src/Monolog/Handler/Slack/SlackRecord.php | 6 ++--- src/Monolog/Handler/SwiftMailerHandler.php | 2 ++ src/Monolog/Handler/SyslogUdpHandler.php | 2 +- src/Monolog/Handler/ZendMonitorHandler.php | 2 +- src/Monolog/SignalHandler.php | 3 --- src/Monolog/Test/TestCase.php | 3 --- 27 files changed, 127 insertions(+), 72 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index c22dd6c19..5109833fb 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -22,16 +22,35 @@ jobs: - "8.0" # disabled for now as phpspec/prophecy does not allow 8.1 # - "8.1" + dependencies: [highest] + include: + - php-version: "7.2" + dependencies: lowest + - php-version: "8.0" + dependencies: lowest steps: - name: "Checkout" uses: "actions/checkout@v2" - - name: "Install PHP 7+" + - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp + + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Runs Elasticsearch + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: 7.6.0 - name: Get composer cache directory id: composercache @@ -44,9 +63,13 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- + - name: "Handle lowest dependencies update" + if: "contains(matrix.dependencies, 'lowest')" + run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" + - name: "Install latest dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} - name: "Run tests" - run: "composer test" + run: "composer exec phpunit -- --verbose" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1fe45df73..d343ffece 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,16 +1,19 @@ parameters: - level: 3 + level: 5 + + treatPhpDocTypesAsCertain: false paths: - src/ # - tests/ - ignoreErrors: - '#zend_monitor_|ZEND_MONITOR_#' - - '#RollbarNotifier#' - - '#Predis\\Client#' - '#^Cannot call method ltrim\(\) on int\|false.$#' - - '#^Access to an undefined property Raven_Client::\$context.$#' - '#MongoDB\\(Client|Collection)#' - - '#Gelf\\IMessagePublisher#' + - message: '#Return type \(string\) of method Monolog\\Formatter\\LineFormatter::normalizeException\(\) should be compatible with return type \(array\) of method Monolog\\Formatter\\NormalizerFormatter::normalizeException\(\)#' + paths: + - src/Monolog/Formatter/LineFormatter.php + - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' + paths: + - src/Monolog/Handler/LogglyHandler.php diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 89381b9a7..3cf351a72 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -58,6 +58,7 @@ public function __construct(LoggerInterface $logger) */ public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self { + /** @phpstan-ignore-next-line */ $handler = new static($logger); if ($errorLevelMap !== false) { $handler->registerErrorHandler($errorLevelMap); @@ -74,7 +75,9 @@ public static function register(LoggerInterface $logger, $errorLevelMap = [], $e public function registerExceptionHandler($levelMap = [], $callPrevious = true): self { - $prev = set_exception_handler([$this, 'handleException']); + $prev = set_exception_handler(function (\Throwable $e): void { + $this->handleException($e); + }); $this->uncaughtExceptionLevelMap = $levelMap; foreach ($this->defaultExceptionLevelMap() as $class => $level) { if (!isset($this->uncaughtExceptionLevelMap[$class])) { @@ -145,11 +148,7 @@ protected function defaultErrorLevelMap(): array ]; } - /** - * @private - * @param \Exception $e - */ - public function handleException($e) + private function handleException(\Throwable $e) { $level = LogLevel::ERROR; foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 271628a3b..95d7c1d8c 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -134,6 +134,7 @@ public function format(array $record): Message $message->setAdditional($this->contextPrefix . $key, $val); } + /** @phpstan-ignore-next-line */ if (null === $message->getFile() && isset($record['context']['exception']['file'])) { if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { $message->setFile($matches[1]); diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index c367baa67..59d9f0a01 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -63,8 +63,6 @@ public function isAppendingNewlines(): bool /** * {@inheritdoc} - * - * @suppress PhanTypeComparisonToArray */ public function format(array $record): string { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index c63b39d30..de27f2f70 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -126,9 +126,6 @@ public function stringify($value): string return $this->replaceNewlines($this->convertToString($value)); } - /** - * @suppress PhanParamSignatureMismatch - */ protected function normalizeException(\Throwable $e, int $depth = 0): string { $str = $this->formatException($e); diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 9d41a5057..d85c58c6d 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -118,7 +118,7 @@ protected function formatDate(\DateTimeInterface $value, int $nestingLevel): UTC private function getMongoDbDateTime(\DateTimeInterface $value): UTCDateTime { - return new UTCDateTime((int) (string) floor($value->format('U.u') * 1000)); + return new UTCDateTime((int) floor(((float) $value->format('U.u')) * 1000)); } /** @@ -130,7 +130,7 @@ private function getMongoDbDateTime(\DateTimeInterface $value): UTCDateTime */ private function legacyGetMongoDbDateTime(\DateTimeInterface $value): UTCDateTime { - $milliseconds = floor($value->format('U.u') * 1000); + $milliseconds = floor(((float) $value->format('U.u')) * 1000); $milliseconds = (PHP_INT_SIZE == 8) //64-bit OS? ? (int) $milliseconds diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 41968310e..07f789569 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -24,10 +24,14 @@ class NormalizerFormatter implements FormatterInterface { public const SIMPLE_DATE = "Y-m-d\TH:i:sP"; + /** @var string */ protected $dateFormat; + /** @var int */ protected $maxNormalizeDepth = 9; + /** @var int */ protected $maxNormalizeItemCount = 1000; + /** @var int */ private $jsonEncodeOptions = Utils::DEFAULT_JSON_FLAGS; /** @@ -159,12 +163,7 @@ protected function normalize($data, int $depth = 0) $value = $data->__toString(); } else { // the rest is normalized by json encoding and decoding it - $encoded = $this->toJson($data, true); - if ($encoded === false) { - $value = 'JSON_ERROR'; - } else { - $value = json_decode($encoded, true); - } + $value = json_decode($this->toJson($data, true), true); } return [Utils::getClass($data) => $value]; @@ -248,12 +247,12 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } - public function addJsonEncodeOption($option) + public function addJsonEncodeOption(int $option) { $this->jsonEncodeOptions |= $option; } - public function removeJsonEncodeOption($option) + public function removeJsonEncodeOption(int $option) { $this->jsonEncodeOptions &= ~$option; } diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index 8d560e77c..17402041b 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -33,13 +33,13 @@ public function format(array $record): array /** * @param mixed $value - * @return mixed + * @return string|int|bool|null */ protected function normalizeValue($value) { $normalized = $this->normalize($value); - if (is_array($normalized) || is_object($normalized)) { + if (is_array($normalized)) { return $this->toJson($normalized, true); } diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 2d96739e3..05919d846 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -105,7 +105,7 @@ public function formatBatch(array $records) /** * {@inheritdoc} - * @suppress PhanTypeMismatchReturn + * @return int|bool|string|null|array|object */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 961d7acf2..29f340a05 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -53,6 +53,7 @@ class DynamoDbHandler extends AbstractProcessingHandler */ public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true) { + /** @phpstan-ignore-next-line */ if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) { $this->version = 3; $this->marshaler = new Marshaler; diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 735fdfbd3..2d7a648e0 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -159,9 +159,14 @@ public function getHandler(array $record = null) */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** @@ -169,7 +174,12 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } public function reset() diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 7424b1084..a63fe1483 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -202,9 +202,14 @@ public function getHandler(array $record = null) */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** @@ -212,6 +217,11 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } } diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 00140b4e0..3dbf0f656 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -22,13 +22,12 @@ trait FormattableHandlerTrait { /** - * @var FormatterInterface + * @var ?FormatterInterface */ protected $formatter; /** * {@inheritdoc} - * @suppress PhanTypeMismatchReturn */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index 3f2c7a1a7..e94028be8 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -128,7 +128,7 @@ public function getFormatter(): FormatterInterface public function reset() { if ($this->handler instanceof ResettableInterface) { - return $this->handler->reset(); + $this->handler->reset(); } } } diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index c8befc28d..19710d936 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -68,7 +68,7 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble protected function getCurlHandler(string $endpoint) { if (!array_key_exists($endpoint, $this->curlHandlers)) { - $this->curlHandlers[$endpoint] = $this->loadCurlHandler($endpoint); + $this->curlHandlers[$endpoint] = $this->loadCurlHandle($endpoint); } return $this->curlHandlers[$endpoint]; @@ -79,9 +79,9 @@ protected function getCurlHandler(string $endpoint) * * @param string $endpoint * - * @return resource + * @return resource|\CurlHandle */ - private function loadCurlHandler(string $endpoint) + private function loadCurlHandle(string $endpoint) { $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 2a3b49c5f..95c612a8d 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Swift; +use Swift_Message; /** * MandrillHandler uses cURL to send the emails to the Mandrill API @@ -21,25 +22,27 @@ */ class MandrillHandler extends MailHandler { + /** @var Swift_Message */ protected $message; + /** @var string */ protected $apiKey; /** - * @psalm-param Swift_Message|callable(string, array): 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 - * @param string|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 + * @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 + * @param string|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(string $apiKey, $message, $level = Logger::ERROR, bool $bubble = true) { parent::__construct($level, $bubble); - if (!$message instanceof \Swift_Message && is_callable($message)) { + if (!$message instanceof Swift_Message && is_callable($message)) { $message = $message(); } - if (!$message instanceof \Swift_Message) { + if (!$message instanceof Swift_Message) { throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); } $this->message = $message; @@ -58,9 +61,11 @@ protected function send(string $content, array $records): void $message = clone $this->message; $message->setBody($content, $mime); + /** @phpstan-ignore-next-line */ if (version_compare(Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { + /** @phpstan-ignore-next-line */ $message->setDate(time()); } diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index dbe9b22d1..4c3098656 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -131,9 +131,13 @@ public function handle(array $record): bool */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->handler->setFormatter($formatter); + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } /** @@ -141,6 +145,10 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - return $this->handler->getFormatter(); + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } } diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index aa94e6139..94802d0bb 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -93,9 +93,6 @@ private function initOptions(array $options): array return array_replace($this->options, $options); } - /** - * @suppress PhanTypeMismatchArgument - */ private function initConnector(?Connector $connector = null): Connector { if (!$connector) { diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index c4c38ec5a..71d767bec 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -27,7 +27,6 @@ trait ProcessableHandlerTrait /** * {@inheritdoc} - * @suppress PhanTypeMismatchReturn */ public function pushProcessor(callable $callback): HandlerInterface { diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 6dcf59961..4c33d4a3c 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -100,9 +100,14 @@ public function getHandler(array $record = null) */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** @@ -110,6 +115,11 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index b74a22fbf..6658d0d44 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -77,7 +77,7 @@ class SlackRecord private $excludeFields; /** - * @var FormatterInterface + * @var ?FormatterInterface */ private $formatter; @@ -226,7 +226,7 @@ public function stringify(array $fields): string * * @param ?string $channel * - * @return SlackHandler + * @return static */ public function setChannel(?string $channel = null): self { @@ -240,7 +240,7 @@ public function setChannel(?string $channel = null): self * * @param ?string $username * - * @return SlackHandler + * @return static */ public function setUsername(?string $username = null): self { diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 6b3e49500..2c5c5dac6 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -93,9 +93,11 @@ protected function buildMessage(string $content, array $records): Swift_Message } $message->setBody($content, $mime); + /** @phpstan-ignore-next-line */ if (version_compare(Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { + /** @phpstan-ignore-next-line */ $message->setDate(time()); } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 4c8a6c0f1..270c68ba7 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -94,7 +94,7 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $date $hostname = '-'; } - if ($this->rfc === self::RFC3164) { + if ($this->rfc === self::RFC3164 && ($datetime instanceof \DateTimeImmutable || $datetime instanceof \DateTime)) { $datetime->setTimezone(new \DateTimeZone('UTC')); } $date = $datetime->format($this->dateFormats[$this->rfc]); diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 78a886f15..34fe80fae 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -73,7 +73,7 @@ protected function write(array $record): void * Write to Zend Monitor Events * @param string $type Text displayed in "Class Name (custom)" field * @param string $message Text displayed in "Error String" - * @param mixed $formatted Displayed in Custom Variables tab + * @param array $formatted Displayed in Custom Variables tab * @param int $severity Set the event severity level (-1,0,1) */ protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 4a79fe663..517ab5496 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -41,9 +41,6 @@ public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool if ($callPrevious) { $handler = pcntl_signal_get_handler($signo); - if ($handler === false) { - return $this; - } $this->previousSignalHandler[$signo] = $handler; } else { unset($this->previousSignalHandler[$signo]); diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index ecb8907f3..b996bbc9b 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -49,9 +49,6 @@ protected function getMultipleRecords(): array ]; } - /** - * @suppress PhanTypeMismatchReturn - */ protected function getIdentityFormatter(): FormatterInterface { $formatter = $this->createMock(FormatterInterface::class); From fd305da67bdbda519979e8de52599376788d57f1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 16:39:57 +0100 Subject: [PATCH 293/498] Add support for PHP8 CurlHandler/Socket instead of resources --- src/Monolog/Handler/Curl/Util.php | 10 ++++++---- src/Monolog/Handler/LogglyHandler.php | 7 ++++--- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 9 +++++---- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index b0aeac9cb..cc0b6c39a 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -11,6 +11,8 @@ namespace Monolog\Handler\Curl; +use CurlHandle; + /** * This class is marked as internal and it is not under the BC promise of the package. * @@ -31,10 +33,10 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param resource $ch curl handler - * @param int $retries - * @param bool $closeAfterDone - * @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($ch, int $retries = 5, bool $closeAfterDone = true) { diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 19710d936..6fc7066c6 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; use function array_key_exists; +use CurlHandle; /** * Sends errors to Loggly. @@ -32,7 +33,7 @@ class LogglyHandler extends AbstractProcessingHandler /** * Caches the curl handlers for every given endpoint. * - * @var array + * @var resource[]|CurlHandle[] */ protected $curlHandlers = []; @@ -63,7 +64,7 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble * * @param string $endpoint * - * @return resource + * @return resource|CurlHandle */ protected function getCurlHandler(string $endpoint) { @@ -79,7 +80,7 @@ protected function getCurlHandler(string $endpoint) * * @param string $endpoint * - * @return resource|\CurlHandle + * @return resource|CurlHandle */ private function loadCurlHandle(string $endpoint) { diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 371edb49e..33696d7a4 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -12,6 +12,7 @@ namespace Monolog\Handler\SyslogUdp; use Monolog\Utils; +use Socket; class UdpSocket { @@ -21,7 +22,7 @@ class UdpSocket protected $ip; /** @var int */ protected $port; - /** @var resource|null */ + /** @var resource|Socket|null */ protected $socket; public function __construct(string $ip, int $port = 514) @@ -35,7 +36,7 @@ public function __construct(string $ip, int $port = 514) $domain = AF_UNIX; $protocol = IPPROTO_IP; } - $this->socket = socket_create($domain, SOCK_DGRAM, $protocol); + $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } public function write($line, $header = "") @@ -45,7 +46,7 @@ public function write($line, $header = "") public function close(): void { - if (is_resource($this->socket)) { + if (is_resource($this->socket) || $this->socket instanceof Socket) { socket_close($this->socket); $this->socket = null; } @@ -53,7 +54,7 @@ public function close(): void protected function send(string $chunk): void { - if (!is_resource($this->socket)) { + if (!is_resource($this->socket) && !$this->socket instanceof Socket) { throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); } socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); From ec146b38bdcd61aa056e382b45c1ee7d9b533ed4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Dec 2020 16:54:31 +0100 Subject: [PATCH 294/498] Build tweaks --- .github/workflows/continuous-integration.yml | 24 +++++++++---------- .github/workflows/phpstan.yml | 7 +++++- composer.json | 3 ++- phpstan.neon.dist | 1 + src/Monolog/Formatter/MongoDBFormatter.php | 2 +- .../Formatter/MongoDBFormatterTest.php | 2 +- tests/Monolog/Handler/MongoDBHandlerTest.php | 2 +- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5109833fb..9852d7805 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -40,18 +40,6 @@ jobs: php-version: "${{ matrix.php-version }}" extensions: mongodb, redis, amqp - - name: Configure sysctl limits - run: | - sudo swapoff -a - sudo sysctl -w vm.swappiness=1 - sudo sysctl -w fs.file-max=262144 - sudo sysctl -w vm.max_map_count=262144 - - - name: Runs Elasticsearch - uses: elastic/elastic-github-actions/elasticsearch@master - with: - stack-version: 7.6.0 - - name: Get composer cache directory id: composercache run: echo "::set-output name=dir::$(composer config cache-files-dir)" @@ -63,6 +51,18 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- + - name: Remove elasticsearch/elasticsearch on PHP 8 + if: "startsWith(matrix.php-version, '8.')" + run: 'composer remove elasticsearch/elasticsearch --dev --no-update' + + - name: Add require for mongodb/mongodb to make tests runnable + run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' + + # This does not affect runtime, only tests were fixed in psr/log 1.1.2 so it's + # ok to require this only when running tests + - name: Bump required version of psr/log for tests purposes to fix the --prefer-lowest builds + run: 'composer require ${{ env.COMPOSER_FLAGS }} psr/log:^1.1.2 --no-update' + - name: "Handle lowest dependencies update" if: "contains(matrix.dependencies, 'lowest')" run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index b26a5573d..434324ce8 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -27,6 +27,7 @@ jobs: with: coverage: "none" php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp - name: Get composer cache directory id: composercache @@ -39,8 +40,12 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- + - name: Add require for mongodb/mongodb to make tests runnable + run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' + - name: "Install latest dependencies" - run: "composer update ${{ env.COMPOSER_FLAGS }}" + # --ignore-platform-req=php here needed as long as elasticsearch/elasticsearch does not support php 8 + run: "composer update ${{ env.COMPOSER_FLAGS }} --ignore-platform-req=php" - name: Run PHPStan run: composer phpstan diff --git a/composer.json b/composer.json index 247a67494..37a9ec580 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^6.0", + "elasticsearch/elasticsearch": "^7", + "mongodb/mongodb": "^1.8", "graylog2/gelf-php": "^1.4.2", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index d343ffece..a56c5030f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,7 @@ parameters: level: 5 treatPhpDocTypesAsCertain: false + reportUnmatchedIgnoredErrors: false paths: - src/ diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index d85c58c6d..9241b1b74 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -34,7 +34,7 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri $this->maxNestingLevel = max($maxNestingLevel, 0); $this->exceptionTraceAsString = $exceptionTraceAsString; - $this->isLegacyMongoExt = version_compare(phpversion('mongodb'), '1.1.9', '<='); + $this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare(phpversion('mongodb'), '1.1.9', '<='); } /** diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 140341b44..6a2dd04e5 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -49,7 +49,7 @@ public function testConstruct($traceDepth, $traceAsString, $expectedTraceDepth, $reflTrace->setAccessible(true); $this->assertEquals($expectedTraceAsString, $reflTrace->getValue($formatter)); - $reflDepth = new\ReflectionProperty($formatter, 'maxNestingLevel'); + $reflDepth = new \ReflectionProperty($formatter, 'maxNestingLevel'); $reflDepth->setAccessible(true); $this->assertEquals($expectedTraceDepth, $reflDepth->getValue($formatter)); } diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index a21f207bd..0a9a0bea7 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -45,7 +45,7 @@ public function testHandleWithLibraryClient() $record = $this->getRecord(); $expected = $record; - $expected['datetime'] = $record['datetime']->format(NormalizerFormatter::SIMPLE_DATE); + $expected['datetime'] = new \MongoDB\BSON\UTCDateTime((int) floor(((float) $record['datetime']->format('U.u')) * 1000)); $collection->expects($this->once()) ->method('insertOne') From 1c9c3676e6901c14e6bfdcb379faf4e455c22f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D0=B2=D0=B5=D0=BB=20=D0=93=D0=B2=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D1=8C?= Date: Thu, 10 Dec 2020 14:51:46 +0600 Subject: [PATCH 295/498] Added support for working with BufferHandler (#1481) * Added support for working with BufferHandler Added `handleBatch` method for TelegramBotHandler and fixed `write` method. This is necessary to work with BufferHandler, OverflowHandler etc. --- src/Monolog/Handler/TelegramBotHandler.php | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index bec080b8e..025c89e34 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -120,6 +120,30 @@ public function disableNotification(bool $disableNotification = null): self return $this; } + /** + * {@inheritdoc} + */ + public function handleBatch(array $records): void + { + $messages = []; + + foreach ($records as $record) { + if (!$this->isHandling($record)) { + continue; + } + + if ($this->processors) { + $record = $this->processRecord($record); + } + + $messages[] = $record; + } + + if (!empty($messages)) { + $this->send((string) $this->getFormatter()->formatBatch($messages)); + } + } + /** * @inheritDoc */ From e6e43ca09740d1159aa4f4784092ce8859713dbe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 09:57:10 +0100 Subject: [PATCH 296/498] Use Utils::jsonEncode to encode json correctly --- src/Monolog/Processor/PsrLogMessageProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 3d12522f1..a318af7e4 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -64,7 +64,7 @@ public function __invoke(array $record) } elseif (is_object($val)) { $replacements[$placeholder] = '[object '.Utils::getClass($val).']'; } elseif (is_array($val)) { - $replacements[$placeholder] = 'array'.@json_encode($val); + $replacements[$placeholder] = 'array'.Utils::jsonEncode($val, null, true); } else { $replacements[$placeholder] = '['.gettype($val).']'; } From df4d93f14828b8052665699bd4ba2ab257f6dca2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 14:30:02 +0100 Subject: [PATCH 297/498] Simplify addRecord further by doing a single foreach over all handlers, refs #1489 --- src/Monolog/Logger.php | 74 +++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 4d9ef803c..6188916b3 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -286,47 +286,53 @@ public function useMicrosecondTimestamps(bool $micro) public function addRecord(int $level, string $message, array $context = []): bool { $offset = 0; - foreach ($this->handlers as $handler) { - if ($handler->isHandling(['level' => $level])) { - break; - } - - $offset++; - } - // cut off checked not handleable handlers - $remainedHandlers = array_slice($this->handlers, $offset); + $record = null; - if (!$remainedHandlers) { - return false; - } - - $levelName = static::getLevelName($level); - - $record = [ - 'message' => $message, - 'context' => $context, - 'level' => $level, - 'level_name' => $levelName, - 'channel' => $this->name, - 'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), - 'extra' => [], - ]; + foreach ($this->handlers as $handler) { + if (null === $record) { + // skip creating the record as long as no handler is going to handle it + if (!$handler->isHandling(['level' => $level])) { + continue; + } - try { - foreach ($this->processors as $processor) { - $record = $processor($record); + $levelName = static::getLevelName($level); + + $record = [ + 'message' => $message, + 'context' => $context, + 'level' => $level, + 'level_name' => $levelName, + 'channel' => $this->name, + 'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + 'extra' => [], + ]; + + try { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + } catch (Throwable $e) { + $this->handleException($e, $record); + + return true; + } } - foreach ($remainedHandlers as $handler) { - if (true === $handler->handle($record)) { - break; + // once the record exist, send it to all handlers as long as the bubbling chain is not interrupted + if (null !== $record) { + try { + if (true === $handler->handle($record)) { + break; + } + } catch (Throwable $e) { + $this->handleException($e, $record); + + return true; } } - } catch (Throwable $e) { - $this->handleException($e, $record); } - return true; + return null !== $record; } /** @@ -407,7 +413,7 @@ public static function toMonologLevel($level): int if (is_numeric($level)) { return intval($level); } - + // 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($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); From 31de09b174bfae1ff3c782a8527bd902035188bf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 14:40:08 +0100 Subject: [PATCH 298/498] ADd RedisPubSubHandler to docs, refs #1503 --- doc/02-handlers-formatters-processors.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 9e76b8740..a568824f6 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -76,7 +76,8 @@ ### Log to databases -- [_RedisHandler_](../src/Monolog/Handler/RedisHandler.php): Logs records to a [redis](http://redis.io) server. +- [_RedisHandler_](../src/Monolog/Handler/RedisHandler.php): Logs records to a [redis](http://redis.io) server's key via RPUSH. +- [_RedisPubSubHandler_](../src/Monolog/Handler/RedisPubSubHandler.php): Logs records to a [redis](http://redis.io) server's channel via PUBLISH. - [_MongoDBHandler_](../src/Monolog/Handler/MongoDBHandler.php): Handler to write records in MongoDB via a [Mongo](http://pecl.php.net/package/mongo) extension connection. - [_CouchDBHandler_](../src/Monolog/Handler/CouchDBHandler.php): Logs records to a CouchDB server. @@ -110,8 +111,8 @@ application to crash and may wish to continue to log to other handlers. - [_FallbackGroupHandler_](../src/Monolog/Handler/FallbackGroupHandler.php): This handler extends the _GroupHandler_ ignoring exceptions raised by each child handler, until one has handled without throwing. - This allows you to ignore issues where a remote tcp connection may have died - but you do not want your entire application to crash and may wish to continue + This allows you to ignore issues where a remote tcp connection may have died + but you do not want your entire application to crash and may wish to continue to attempt log to other handlers, until one does not throw. - [_BufferHandler_](../src/Monolog/Handler/BufferHandler.php): This handler will buffer all the log records it receives until `close()` is called at which point it will call `handleBatch()` on the From 80644c65ed532296e665ff7e7b5609634c350873 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 14:56:28 +0100 Subject: [PATCH 299/498] Remove unnecessary condition --- src/Monolog/Logger.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 6188916b3..657bd5177 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -319,16 +319,14 @@ public function addRecord(int $level, string $message, array $context = []): boo } // once the record exist, send it to all handlers as long as the bubbling chain is not interrupted - if (null !== $record) { - try { - if (true === $handler->handle($record)) { - break; - } - } catch (Throwable $e) { - $this->handleException($e, $record); - - return true; + try { + if (true === $handler->handle($record)) { + break; } + } catch (Throwable $e) { + $this->handleException($e, $record); + + return true; } } From f8c98ee2ba046b069a003866a4c47720e26dac73 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 14:56:54 +0100 Subject: [PATCH 300/498] Fix typo --- src/Monolog/Logger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 657bd5177..198e99497 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -318,7 +318,7 @@ public function addRecord(int $level, string $message, array $context = []): boo } } - // once the record exist, 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 { if (true === $handler->handle($record)) { break; From d356586239bf3437ab9c2f1144fc56fde2d486f4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 16:04:54 +0100 Subject: [PATCH 301/498] Type hint fixes --- src/Monolog/Logger.php | 68 +++++++++++++++++++----------------------- src/Monolog/Utils.php | 8 ++--- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 198e99497..927c31276 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -90,7 +90,7 @@ class Logger implements LoggerInterface, ResettableInterface /** * This is a static variable and not a constant to serve as an extension point for custom levels * - * @var string[] $levels Logging levels with the levels as key + * @var array $levels Logging levels with the levels as key */ protected static $levels = [ self::DEBUG => 'DEBUG', @@ -257,20 +257,14 @@ public function getProcessors(): array * Control the use of microsecond resolution timestamps in the 'datetime' * member of new records. * - * On PHP7.0, generating microsecond resolution timestamps by calling - * microtime(true), formatting the result via sprintf() and then parsing - * the resulting string via \DateTime::createFromFormat() can incur - * a measurable runtime overhead vs simple usage of DateTime to capture - * a second resolution timestamp in systems which generate a large number - * of log events. - * - * On PHP7.1 however microseconds are always included by the engine, so - * this setting can be left alone unless you really want to suppress - * microseconds in the output. + * As of PHP7.1 microseconds are always included by the engine, so + * there is no performance penalty and Monolog 2 enabled microseconds + * by default. This function lets you disable them though in case you want + * to suppress microseconds from the output. * * @param bool $micro True to use microtime() to create timestamps */ - public function useMicrosecondTimestamps(bool $micro) + public function useMicrosecondTimestamps(bool $micro): void { $this->microsecondTimestamps = $micro; } @@ -278,10 +272,10 @@ public function useMicrosecondTimestamps(bool $micro) /** * Adds a log record. * - * @param int $level The logging level - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param int $level The logging level + * @param string $message The log message + * @param mixed[] $context The log context + * @return bool Whether the record has been processed */ public function addRecord(int $level, string $message, array $context = []): bool { @@ -378,7 +372,7 @@ public function reset(): void /** * Gets all supported logging levels. * - * @return array Assoc array with human-readable level names => level codes. + * @return array Assoc array with human-readable level names => level codes. */ public static function getLevels(): array { @@ -469,9 +463,9 @@ public function getExceptionHandler(): ?callable * * This method allows for compatibility with common interfaces. * - * @param mixed $level The log level - * @param string $message The log message - * @param array $context The log context + * @param mixed $level The log level + * @param string $message The log message + * @param mixed[] $context The log context */ public function log($level, $message, array $context = []): void { @@ -485,8 +479,8 @@ public function log($level, $message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function debug($message, array $context = []): void { @@ -498,8 +492,8 @@ public function debug($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function info($message, array $context = []): void { @@ -511,8 +505,8 @@ public function info($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function notice($message, array $context = []): void { @@ -524,8 +518,8 @@ public function notice($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function warning($message, array $context = []): void { @@ -537,8 +531,8 @@ public function warning($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function error($message, array $context = []): void { @@ -550,8 +544,8 @@ public function error($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function critical($message, array $context = []): void { @@ -563,8 +557,8 @@ public function critical($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function alert($message, array $context = []): void { @@ -576,8 +570,8 @@ public function alert($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context + * @param string $message The log message + * @param mixed[] $context The log context */ public function emergency($message, array $context = []): void { @@ -606,7 +600,7 @@ public function getTimezone(): DateTimeZone * Delegates exception management to the custom exception handler, * or throws the exception if no custom handler is set. */ - protected function handleException(Throwable $e, array $record) + protected function handleException(Throwable $e, array $record): void { if (!$this->exceptionHandler) { throw $e; diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 1ad63b658..41e24031b 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -15,14 +15,14 @@ final class Utils { const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION | JSON_INVALID_UTF8_SUBSTITUTE; - public static function getClass($object): string + public static function getClass(object $object): string { $class = \get_class($object); return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } - public static function substr(string $string, int $start, ?int $length = null) + public static function substr(string $string, int $start, ?int $length = null): string { if (extension_loaded('mbstring')) { return mb_strcut($string, $start, $length); @@ -139,7 +139,7 @@ public static function handleJsonError(int $code, $data, ?int $encodeFlags = nul * @param mixed $data data that was meant to be encoded * @throws \RuntimeException */ - private static function throwEncodeError(int $code, $data) + private static function throwEncodeError(int $code, $data): void { switch ($code) { case JSON_ERROR_DEPTH: @@ -176,7 +176,7 @@ private static function throwEncodeError(int $code, $data) * * @param mixed $data Input to check and convert if needed, passed by ref */ - private static function detectAndCleanUtf8(&$data) + private static function detectAndCleanUtf8(&$data): void { if (is_string($data) && !preg_match('//u', $data)) { $data = preg_replace_callback( From 9ce043119106fe2d7aa16000791a4992e7321863 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 16:22:14 +0100 Subject: [PATCH 302/498] Add JSON_PARTIAL_OUTPUT_ON_ERROR, closes #1515 --- src/Monolog/Utils.php | 2 +- .../Formatter/NormalizerFormatterTest.php | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 41e24031b..9f906a3ba 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -13,7 +13,7 @@ final class Utils { - const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION | JSON_INVALID_UTF8_SUBSTITUTE; + const DEFAULT_JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION | JSON_INVALID_UTF8_SUBSTITUTE | JSON_PARTIAL_OUTPUT_ON_ERROR; public static function getClass(object $object): string { diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 90dd835f9..00cc1fb90 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -208,11 +208,7 @@ public function testIgnoresRecursiveObjectReferences() restore_error_handler(); - if (PHP_VERSION_ID < 50500) { - $this->assertEquals('[{"bar":{"foo":null}},{"foo":{"bar":null}}]', $res); - } else { - $this->assertEquals('null', $res); - } + $this->assertEquals('[{"bar":{"foo":null}},{"foo":{"bar":null}}]', $res); } public function testCanNormalizeReferences() @@ -224,9 +220,9 @@ public function testCanNormalizeReferences() $formatter->format($y); } - public function testIgnoresInvalidTypes() + public function testToJsonIgnoresInvalidTypes() { - // set up the recursion + // set up the invalid data $resource = fopen(__FILE__, 'r'); // set an error handler to assert that the error is not raised anymore @@ -247,11 +243,7 @@ public function testIgnoresInvalidTypes() restore_error_handler(); - if (PHP_VERSION_ID < 50500) { - $this->assertEquals('[null]', $res); - } else { - $this->assertEquals('null', $res); - } + $this->assertEquals('[null]', $res); } public function testNormalizeHandleLargeArraysWithExactly1000Items() From 863670fa94d8038a23a05f2f1745891f7dc6ee77 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 17:14:21 +0100 Subject: [PATCH 303/498] Avoid sending unicode chars in headers for Wildfire/FirePHPHandler/ChromePHPHandler, fixes #1521 --- src/Monolog/Formatter/WildfireFormatter.php | 11 +++++++++++ src/Monolog/Handler/ChromePHPHandler.php | 2 +- src/Monolog/Utils.php | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 05919d846..20288ab5b 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -36,6 +36,17 @@ class WildfireFormatter extends NormalizerFormatter Logger::EMERGENCY => 'ERROR', ]; + /** + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct(?string $dateFormat = null) + { + parent::__construct($dateFormat); + + // http headers do not like non-ISO-8559-1 characters + $this->removeJsonEncodeOption(JSON_UNESCAPED_UNICODE); + } + /** * {@inheritdoc} */ diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index ef93f660b..44dbf0d48 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -145,7 +145,7 @@ protected function send(): void self::$json['request_uri'] = $_SERVER['REQUEST_URI'] ?? ''; } - $json = Utils::jsonEncode(self::$json, null, true); + $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); $data = base64_encode(utf8_encode($json)); if (strlen($data) > 3 * 1024) { self::$overflowed = true; diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 9f906a3ba..798681987 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -63,7 +63,7 @@ public static function canonicalizePath(string $streamUrl): string * Return the JSON representation of a value * * @param mixed $data - * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @param int $encodeFlags flags to pass to json encode, defaults to DEFAULT_JSON_FLAGS * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null * @throws \RuntimeException if encoding fails and errors are not ignored * @return string when errors are ignored and the encoding fails, "null" is returned which is valid json for null From af59ed294eb91ec89475904ae1fecd68321d5fff Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 10 Dec 2020 20:20:16 +0100 Subject: [PATCH 304/498] Add FluentdFormatter to docs, fixes #1510 --- doc/02-handlers-formatters-processors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index a568824f6..2e830d43c 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -155,6 +155,7 @@ - [_FlowdockFormatter_](../src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. - [_MongoDBFormatter_](../src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. - [_LogmaticFormatter_](../src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. +- [_FluentdFormatter_](../src/Monolog/Formatter/FluentdFormatter.php): Used to format log records to [Fluentd](https://www.fluentd.org/) logs, only useful with the SocketHandler. ## Processors From 1d5456ec07a2786c371e92df993bc93369cdfd40 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 11 Dec 2020 10:41:09 +0100 Subject: [PATCH 305/498] Clarify support situation in readme, fixes #1506 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ca3c6a6b..0d2ad2c12 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,11 @@ can also add your own there if you publish one. ### Requirements -- Monolog 2.x works with PHP 7.2 or above, use Monolog `^1.0` for PHP 5.3+ support. +- 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 where possible to benefit from all the latest features and fixes. ### Submitting bugs and feature requests From 76639ef02bbca5efa6dfb99e7cea6a269f14d421 Mon Sep 17 00:00:00 2001 From: patrickkusebauch Date: Fri, 11 Dec 2020 10:55:38 +0100 Subject: [PATCH 306/498] Elastica up to 7 support --- composer.json | 2 +- src/Monolog/Formatter/ElasticaFormatter.php | 7 +- src/Monolog/Handler/ElasticaHandler.php | 2 +- .../Formatter/ElasticaFormatterTest.php | 7 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 66 ++++++++++++++++++- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 37a9ec580..27d433377 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <3.0", + "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0", "phpstan/phpstan": "^0.12.59" }, diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index c6f3c8e12..d15ea5f28 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -58,6 +58,9 @@ public function getIndex(): string return $this->index; } + /** + * @deprecated since Elastica 7 type has no effect + */ public function getType(): string { return $this->type; @@ -72,7 +75,9 @@ protected function getDocument(array $record): Document { $document = new Document(); $document->setData($record); - $document->setType($this->type); + if(method_exists($document, 'setType')) { + $document->setType($this->type); + } $document->setIndex($this->index); return $document; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 78a8d1ea7..7af68fef6 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -25,7 +25,7 @@ * $client = new \Elastica\Client(); * $options = array( * 'index' => 'elastic_index_name', - * 'type' => 'elastic_doc_type', + * 'type' => 'elastic_doc_type', Types have been removed in Elastica 7 * ); * $handler = new ElasticaHandler($client, $options); * $log = new Logger('application'); diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index e2c977784..d42ca2a55 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -55,9 +55,10 @@ public function testFormat() $this->assertInstanceOf('Elastica\Document', $doc); // Document parameters - $params = $doc->getParams(); - $this->assertEquals('my_index', $params['_index']); - $this->assertEquals('doc_type', $params['_type']); + $this->assertEquals('my_index', $doc->getIndex()); + if(method_exists($doc, 'getType')) { + $this->assertEquals('doc_type', $doc->getType()); + } // Document data values $data = $doc->getData(); diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 453752f23..1bb92ded0 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -156,7 +156,7 @@ public function providerTestConnectionErrors() } /** - * Integration test using localhost Elastic Search server + * Integration test using localhost Elastic Search server version <7 * * @covers Monolog\Handler\ElasticaHandler::__construct * @covers Monolog\Handler\ElasticaHandler::handleBatch @@ -209,6 +209,61 @@ public function testHandleIntegration() $client->request("/{$this->options['index']}", Request::DELETE); } + /** + * Integration test using localhost Elastic Search server version 7+ + * + * @covers Monolog\Handler\ElasticaHandler::__construct + * @covers Monolog\Handler\ElasticaHandler::handleBatch + * @covers Monolog\Handler\ElasticaHandler::bulkSend + * @covers Monolog\Handler\ElasticaHandler::getDefaultFormatter + */ + public function testHandleIntegrationNewESVersion() + { + $msg = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => [], + 'message' => 'log', + ]; + + $expected = $msg; + $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); + $expected['context'] = [ + 'class' => '[object] (stdClass: {})', + 'foo' => 7, + 0 => 'bar', + ]; + + $client = new Client(); + $handler = new ElasticaHandler($client, $this->options); + + try { + $handler->handleBatch([$msg]); + } catch (\RuntimeException $e) { + $this->markTestSkipped("Cannot connect to Elastic Search server on localhost"); + } + + // check document id from ES server response + $documentId = $this->getCreatedDocId($client->getLastResponse()); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + + // retrieve document source from ES and validate + $document = $this->getDocSourceFromElastic( + $client, + $this->options['index'], + null, + $documentId + ); + $this->assertEquals($expected, $document); + + // remove test index from ES + $client->request("/{$this->options['index']}", Request::DELETE); + } + + /** * Return last created document id from ES response * @param Response $response Elastica Response object @@ -226,13 +281,18 @@ protected function getCreatedDocId(Response $response) * Retrieve document by id from Elasticsearch * @param Client $client Elastica client * @param string $index - * @param string $type + * @param ?string $type * @param string $documentId * @return array */ protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) { - $resp = $client->request("/{$index}/{$type}/{$documentId}", Request::GET); + if($type === null) { + $path = "/{$index}/{$documentId}"; + } else { + $path = "/{$index}/{$type}/{$documentId}"; + } + $resp = $client->request($path, Request::GET); $data = $resp->getData(); if (!empty($data['_source'])) { return $data['_source']; From 61e5ff2b360042c3dabbfd42973200d882971f28 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 11 Dec 2020 13:11:35 +0100 Subject: [PATCH 307/498] Fix more instances of bad FormattableHandlerInterface usages --- src/Monolog/Handler/BufferHandler.php | 15 ++++++++++++--- src/Monolog/Handler/FingersCrossedHandler.php | 1 + src/Monolog/Handler/GroupHandler.php | 5 ++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 7a5902849..fbf5effa4 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -27,6 +27,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa { use ProcessableHandlerTrait; + /** @var HandlerInterface */ protected $handler; protected $bufferSize = 0; protected $bufferLimit; @@ -137,9 +138,13 @@ public function reset() */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->handler->setFormatter($formatter); + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } /** @@ -147,6 +152,10 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - return $this->handler->getFormatter(); + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index a63fe1483..2253e71f5 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -37,6 +37,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa { use ProcessableHandlerTrait; + /** @var HandlerInterface */ protected $handler; protected $activationStrategy; protected $buffering = true; diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 51218568c..a7d8a3179 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -23,6 +23,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset { use ProcessableHandlerTrait; + /** @var HandlerInterface[] */ protected $handlers; protected $bubble; @@ -116,7 +117,9 @@ public function close(): void public function setFormatter(FormatterInterface $formatter): HandlerInterface { foreach ($this->handlers as $handler) { - $handler->setFormatter($formatter); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); + } } return $this; From 9fc7a8a810bbe40de9757ec748ba2e60b99805a5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 11 Dec 2020 13:31:25 +0100 Subject: [PATCH 308/498] Allow changing the date format after normalizer creation, fixes #1459 --- src/Monolog/Formatter/NormalizerFormatter.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 07f789569..4daef8142 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -65,6 +65,18 @@ public function formatBatch(array $records) return $records; } + public function getDateFormat(): string + { + return $this->dateFormat; + } + + public function setDateFormat(string $dateFormat): self + { + $this->dateFormat = $dateFormat; + + return $this; + } + /** * The maximum number of normalization levels to go through */ From 79d12135dd08837f5a595d9699fa56a5303f1c05 Mon Sep 17 00:00:00 2001 From: patrickkusebauch Date: Sat, 12 Dec 2020 22:21:42 +0100 Subject: [PATCH 309/498] Fixed new Url --- tests/Monolog/Handler/ElasticaHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 1bb92ded0..e66b13945 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -288,7 +288,7 @@ protected function getCreatedDocId(Response $response) protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) { if($type === null) { - $path = "/{$index}/{$documentId}"; + $path = "/{$index}/_doc/{$documentId}"; } else { $path = "/{$index}/{$type}/{$documentId}"; } From ff4378dfbe29fff2b3550784a9f4208059f2b846 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Dec 2020 13:26:29 +0100 Subject: [PATCH 310/498] Mark elasticaFormatters $type arg as deprecated --- src/Monolog/Formatter/ElasticaFormatter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index d15ea5f28..21787bc4f 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -26,15 +26,15 @@ class ElasticaFormatter extends NormalizerFormatter protected $index; /** - * @var string Elastic search document type + * @var ?string Elastic search document type */ protected $type; /** - * @param string $index Elastic Search index name - * @param string $type Elastic Search document type + * @param string $index Elastic Search index name + * @param ?string $type Elastic Search document type, deprecated as of Elastica 7 */ - public function __construct(string $index, string $type) + public function __construct(string $index, ?string $type) { // elasticsearch requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\TH:i:s.uP'); From 3ee78ae7313327e199b4fcc2a28f1d2d0d48d0ba Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Dec 2020 13:34:59 +0100 Subject: [PATCH 311/498] Simplify timeout handling and really allow millisecond precision, refs #1517 --- src/Monolog/Handler/SocketHandler.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index c2a254711..db02714bf 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -35,6 +35,7 @@ class SocketHandler extends AbstractProcessingHandler private $persistent = false; private $errno; private $errstr; + /** @var ?float */ private $lastWritingAt; /** @@ -355,13 +356,12 @@ private function writeToSocket(string $data): void private function writingIsTimedOut(int $sent): bool { // convert to ms - $writingTimeoutMs = $this->writingTimeout * 1000; - if (0 === $writingTimeoutMs) { + if (0 === $this->writingTimeout) { return false; } if ($sent !== $this->lastSentBytes) { - $this->lastWritingAt = time(); + $this->lastWritingAt = microtime(true); $this->lastSentBytes = $sent; return false; @@ -369,10 +369,7 @@ private function writingIsTimedOut(int $sent): bool usleep(100); } - // convert to ms - $lastWritingMs = (time() - $this->lastWritingAt) * 1000; - - if ($lastWritingMs >= $writingTimeoutMs) { + if ((microtime(true) - $this->lastWritingAt) >= $this->writingTimeout) { $this->closeSocket(); return true; From 546dc0843d290b0fc9d1cf7170e0e252847a7eba Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Dec 2020 13:49:05 +0100 Subject: [PATCH 312/498] Fix comparison --- src/Monolog/Handler/SocketHandler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index db02714bf..7e8e0187a 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -26,9 +26,9 @@ class SocketHandler extends AbstractProcessingHandler /** @var resource|null */ private $resource; /** @var float */ - private $timeout = 0; + private $timeout = 0.0; /** @var float */ - private $writingTimeout = 10; + private $writingTimeout = 10.0; private $lastSentBytes = null; /** @var int */ private $chunkSize = null; @@ -356,7 +356,7 @@ private function writeToSocket(string $data): void private function writingIsTimedOut(int $sent): bool { // convert to ms - if (0 === $this->writingTimeout) { + if (0.0 == $this->writingTimeout) { return false; } From 2209ddd84e7ef1256b7af205d0717fb62cfc9c33 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Dec 2020 13:56:38 +0100 Subject: [PATCH 313/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 757643df9..53ee097b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.26.0 (2020-12-14) + + * Added $dateFormat and $removeUsedContextFields arguments to PsrLogMessageProcessor (backport from 2.x) + ### 1.25.5 (2020-07-23) * Fixed array access on null in RavenHandler From 1cb1cde8e8dd0f70cc0fe51354a59acad9302084 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Dec 2020 14:15:25 +0100 Subject: [PATCH 314/498] Update changelog --- CHANGELOG.md | 15 +++++++++++++++ src/Monolog/Handler/SyslogUdp/UdpSocket.php | 4 ++-- src/Monolog/Handler/SyslogUdpHandler.php | 4 ++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 073247ada..e5b27842d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +### 2.2.0 (2020-12-14) + + * Added JSON_PARTIAL_OUTPUT_ON_ERROR to default json encoding flags, to avoid dropping entire context data or even records due to an invalid subset of it somewhere + * Added setDateFormat to NormalizerFormatter (and Line/Json formatters by extension) to allow changing this after object creation + * Added RedisPubSubHandler to log records to a Redis channel using PUBLISH + * Added support for Elastica 7, and deprecated the $type argument of ElasticaFormatter which is not in use anymore as of Elastica 7 + * Added support for millisecond write timeouts in SocketHandler, you can now pass floats to setWritingTimeout, e.g. 0.2 is 200ms + * Added support for unix sockets in SyslogUdpHandler (set $port to 0 to make the $host a unix socket) + * Added handleBatch support for TelegramBotHandler + * Added RFC5424e extended date format including milliseconds to SyslogUdpHandler + * Added support for configuring handlers with numeric level values in strings (coming from e.g. env vars) + * Fixed Wildfire/FirePHP/ChromePHP handling of unicode characters + * Fixed PHP 8 issues in SyslogUdpHandler + * Fixed internal type error when mbstring is missing + ### 2.1.1 (2020-07-23) * Fixed removing of json encoding options diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 33696d7a4..228a705ab 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -33,8 +33,8 @@ public function __construct(string $ip, int $port = 514) $protocol = SOL_UDP; // Check if we are using unix sockets. if ($port === 0) { - $domain = AF_UNIX; - $protocol = IPPROTO_IP; + $domain = AF_UNIX; + $protocol = IPPROTO_IP; } $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index fdfabf345..a31ae9a01 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -38,8 +38,8 @@ class SyslogUdpHandler extends AbstractSyslogHandler protected $rfc; /** - * @param string $host - * @param int $port + * @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 string|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 From 8b3a2a0e3fd8fdfb27ed19bd2b6d0b9a11c34296 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 15 Dec 2020 23:19:41 +0100 Subject: [PATCH 315/498] Set theme jekyll-theme-midnight --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 000000000..18854876c --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight \ No newline at end of file From dafbb2597429004be51735534a803e3e2d90fa44 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 15 Dec 2020 23:20:45 +0100 Subject: [PATCH 316/498] Set theme jekyll-theme-slate --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 18854876c..c74188174 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-midnight \ No newline at end of file +theme: jekyll-theme-slate \ No newline at end of file From 78bd7bd33313c3a7ad1f2b0fc0c11a203d4e3826 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 15 Dec 2020 23:21:44 +0100 Subject: [PATCH 317/498] Fix build badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d2ad2c12..0a46feeb3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Monolog - Logging for PHP [![Build Status](https://travis-ci.org/Seldaek/monolog.svg?branch=master)](https://travis-ci.org/Seldaek/monolog) +# Monolog - Logging for PHP [![Continuous Integration](https://github.com/Seldaek/monolog/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/Seldaek/monolog/actions) [![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) From 0dba253d2d239e64bb0cc369a61c9d7f44553138 Mon Sep 17 00:00:00 2001 From: Sam Reed Date: Tue, 12 Jan 2021 09:29:53 +0000 Subject: [PATCH 318/498] Add phpstan.neon.dist to .gitattributes export-ignore --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 5d13ab73e..02e43648e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ /doc export-ignore /tests export-ignore /.* export-ignore +/phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore /UPGRADE.md From 7066e39078a4f117147a6304abb9e73a8e8abf55 Mon Sep 17 00:00:00 2001 From: Marc van der Meulen Date: Fri, 15 Jan 2021 17:25:19 +0100 Subject: [PATCH 319/498] When we reset the FilterHandler we should call the handler we are wrapping --- src/Monolog/Handler/FilterHandler.php | 4 ++++ tests/Monolog/Handler/FilterHandlerTest.php | 23 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 2d7a648e0..36e2cd0fa 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -185,5 +185,9 @@ public function getFormatter(): FormatterInterface public function reset() { $this->resetProcessors(); + + if ($this->getHandler() instanceof ResettableInterface) { + $this->getHandler()->reset(); + } } } diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index d91a5777b..6058fade2 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -180,4 +180,27 @@ public function testHandleEmptyBatch() $handler->handleBatch(array()); $this->assertSame(array(), $test->getRecords()); } + + /** + * @covers Monolog\Handler\FilterHandler::handle + * @covers Monolog\Handler\FilterHandler::reset + */ + public function testResetTestHandler() + { + $test = new TestHandler(); + $handler = new FilterHandler($test, [Logger::INFO, Logger::ERROR]); + + $handler->handle($this->getRecord(Logger::INFO)); + $this->assertTrue($test->hasInfoRecords()); + + $handler->handle($this->getRecord(Logger::ERROR)); + $this->assertTrue($test->hasErrorRecords()); + + $handler->reset(); + + $this->assertFalse($test->hasInfoRecords()); + $this->assertFalse($test->hasInfoRecords()); + + $this->assertSame(array(), $test->getRecords()); + } } From c497cc646a95f09e197ce4bb4fb4f4da6c0e3920 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 27 Jan 2021 17:04:26 +0100 Subject: [PATCH 320/498] Add docs about reset() --- doc/01-usage.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/01-usage.md b/doc/01-usage.md index 78ba83ddb..fa37614ee 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -7,6 +7,7 @@ - [Adding extra data in the records](#adding-extra-data-in-the-records) - [Leveraging channels](#leveraging-channels) - [Customizing the log format](#customizing-the-log-format) +- [Long running processes and avoiding memory leaks](#long-running-processes-and-avoiding-memory-leaks) ## Installation @@ -226,4 +227,22 @@ $securityLogger->pushHandler($stream); You may also reuse the same formatter between multiple handlers and share those handlers between multiple loggers. +## Long running processes and avoiding memory leaks + +When logging lots of data or especially when running background workers which +are long-lived processes and do lots of logging over long periods of time, the +memory usage of buffered handlers like FingersCrossedHandler or BufferHandler +can rise quickly. + +Monolog provides the `ResettableInterface` for this use case, allowing you to +end a log cycle and get things back to their initial state. + +Calling `$logger->reset();` means flushing/cleaning all buffers, resetting internal +state, and getting it back to a state in which it can receive log records again. + +This is the conceptual equivalent of ending a web request, and can be done +between every background job you process, or whenever appropriate. It reduces memory +usage and also helps keep logs focused on the task at hand, avoiding log leaks +between different jobs. + [Handlers, Formatters and Processors](02-handlers-formatters-processors.md) → From c1971982c3b792e488726468046b1ef977934c6a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 9 Feb 2021 14:27:42 +0100 Subject: [PATCH 321/498] Fix links in docs --- doc/02-handlers-formatters-processors.md | 164 +++++++++++------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 2e830d43c..c4db5d08c 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -15,79 +15,79 @@ ### Log to files and syslog -- [_StreamHandler_](../src/Monolog/Handler/StreamHandler.php): Logs records into any PHP stream, use this for log files. -- [_RotatingFileHandler_](../src/Monolog/Handler/RotatingFileHandler.php): Logs records to a file and creates one logfile per day. +- [_StreamHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/StreamHandler.php): Logs records into any PHP stream, use this for log files. +- [_RotatingFileHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RotatingFileHandler.php): Logs records to a file and creates one logfile per day. It will also delete files older than `$maxFiles`. You should use [logrotate](https://linux.die.net/man/8/logrotate) for high profile setups though, this is just meant as a quick and dirty solution. -- [_SyslogHandler_](../src/Monolog/Handler/SyslogHandler.php): Logs records to the syslog. -- [_ErrorLogHandler_](../src/Monolog/Handler/ErrorLogHandler.php): Logs records to PHP's +- [_SyslogHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SyslogHandler.php): Logs records to the syslog. +- [_ErrorLogHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ErrorLogHandler.php): Logs records to PHP's [`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function. -- [_ProcessHandler_](../src/Monolog/Handler/ProcessHandler.php): Logs records to the [STDIN](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29) of any process, specified by a command. +- [_ProcessHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ProcessHandler.php): Logs records to the [STDIN](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29) of any process, specified by a command. ### Send alerts and emails -- [_NativeMailerHandler_](../src/Monolog/Handler/NativeMailerHandler.php): Sends emails using PHP's +- [_NativeMailerHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NativeMailerHandler.php): Sends emails using PHP's [`mail()`](http://php.net/manual/en/function.mail.php) function. -- [_SwiftMailerHandler_](../src/Monolog/Handler/SwiftMailerHandler.php): Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. -- [_PushoverHandler_](../src/Monolog/Handler/PushoverHandler.php): Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. -- [_FlowdockHandler_](../src/Monolog/Handler/FlowdockHandler.php): Logs records to a [Flowdock](https://www.flowdock.com/) account. -- [_SlackWebhookHandler_](../src/Monolog/Handler/SlackWebhookHandler.php): Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks. -- [_SlackHandler_](../src/Monolog/Handler/SlackHandler.php): Logs records to a [Slack](https://www.slack.com/) account using the Slack API (complex setup). -- [_SendGridHandler_](../src/Monolog/Handler/SendGridHandler.php): Sends emails via the SendGrid API. -- [_MandrillHandler_](../src/Monolog/Handler/MandrillHandler.php): Sends emails via the [`Mandrill API`](https://mandrillapp.com/api/docs/) using a [`Swift_Message`](http://swiftmailer.org/) instance. -- [_FleepHookHandler_](../src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. -- [_IFTTTHandler_](../src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. -- [_TelegramBotHandler_](../src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. -- [_HipChatHandler_](../src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) +- [_SwiftMailerHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SwiftMailerHandler.php): Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. +- [_PushoverHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PushoverHandler.php): Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. +- [_FlowdockHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FlowdockHandler.php): Logs records to a [Flowdock](https://www.flowdock.com/) account. +- [_SlackWebhookHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SlackWebhookHandler.php): Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks. +- [_SlackHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SlackHandler.php): Logs records to a [Slack](https://www.slack.com/) account using the Slack API (complex setup). +- [_SendGridHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SendGridHandler.php): Sends emails via the SendGrid API. +- [_MandrillHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/MandrillHandler.php): Sends emails via the [`Mandrill API`](https://mandrillapp.com/api/docs/) using a [`Swift_Message`](http://swiftmailer.org/) instance. +- [_FleepHookHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. +- [_IFTTTHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. +- [_TelegramBotHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. +- [_HipChatHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) ### Log specific servers and networked logging -- [_SocketHandler_](../src/Monolog/Handler/SocketHandler.php): Logs records to [sockets](http://php.net/fsockopen), use this +- [_SocketHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SocketHandler.php): Logs records to [sockets](http://php.net/fsockopen), use this for UNIX and TCP sockets. See an [example](sockets.md). -- [_AmqpHandler_](../src/Monolog/Handler/AmqpHandler.php): Logs records to an [AMQP](http://www.amqp.org/) compatible +- [_AmqpHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/AmqpHandler.php): Logs records to an [AMQP](http://www.amqp.org/) compatible server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+) or [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. -- [_GelfHandler_](../src/Monolog/Handler/GelfHandler.php): Logs records to a [Graylog2](http://www.graylog2.org) server. +- [_GelfHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/GelfHandler.php): Logs records to a [Graylog2](http://www.graylog2.org) server. Requires package [graylog2/gelf-php](https://github.com/bzikarsky/gelf-php). -- [_CubeHandler_](../src/Monolog/Handler/CubeHandler.php): Logs records to a [Cube](http://square.github.com/cube/) server. -- [_ZendMonitorHandler_](../src/Monolog/Handler/ZendMonitorHandler.php): Logs records to the Zend Monitor present in Zend Server. -- [_NewRelicHandler_](../src/Monolog/Handler/NewRelicHandler.php): Logs records to a [NewRelic](http://newrelic.com/) application. -- [_LogglyHandler_](../src/Monolog/Handler/LogglyHandler.php): Logs records to a [Loggly](http://www.loggly.com/) account. -- [_RollbarHandler_](../src/Monolog/Handler/RollbarHandler.php): Logs records to a [Rollbar](https://rollbar.com/) account. -- [_SyslogUdpHandler_](../src/Monolog/Handler/SyslogUdpHandler.php): Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. -- [_LogEntriesHandler_](../src/Monolog/Handler/LogEntriesHandler.php): Logs records to a [LogEntries](http://logentries.com/) account. -- [_InsightOpsHandler_](../src/Monolog/Handler/InsightOpsHandler.php): Logs records to an [InsightOps](https://www.rapid7.com/products/insightops/) account. -- [_LogmaticHandler_](../src/Monolog/Handler/LogmaticHandler.php): Logs records to a [Logmatic](http://logmatic.io/) account. -- [_SqsHandler_](../src/Monolog/Handler/SqsHandler.php): Logs records to an [AWS SQS](http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-sqs.html) queue. -- [_RavenHandler_](../src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using +- [_CubeHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/CubeHandler.php): Logs records to a [Cube](http://square.github.com/cube/) server. +- [_ZendMonitorHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ZendMonitorHandler.php): Logs records to the Zend Monitor present in Zend Server. +- [_NewRelicHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NewRelicHandler.php): Logs records to a [NewRelic](http://newrelic.com/) application. +- [_LogglyHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogglyHandler.php): Logs records to a [Loggly](http://www.loggly.com/) account. +- [_RollbarHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RollbarHandler.php): Logs records to a [Rollbar](https://rollbar.com/) account. +- [_SyslogUdpHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SyslogUdpHandler.php): Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. +- [_LogEntriesHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogEntriesHandler.php): Logs records to a [LogEntries](http://logentries.com/) account. +- [_InsightOpsHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/InsightOpsHandler.php): Logs records to an [InsightOps](https://www.rapid7.com/products/insightops/) account. +- [_LogmaticHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogmaticHandler.php): Logs records to a [Logmatic](http://logmatic.io/) account. +- [_SqsHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SqsHandler.php): Logs records to an [AWS SQS](http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-sqs.html) queue. +- [_RavenHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using [raven](https://packagist.org/packages/raven/raven). **Deprecated** and removed in Monolog 2.0, use sentry/sentry 2.x and the [Sentry\Monolog\Handler](https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php) class instead. ### Logging in development -- [_FirePHPHandler_](../src/Monolog/Handler/FirePHPHandler.php): Handler for [FirePHP](http://www.firephp.org/), providing +- [_FirePHPHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FirePHPHandler.php): Handler for [FirePHP](http://www.firephp.org/), providing inline `console` messages within [FireBug](http://getfirebug.com/). -- [_ChromePHPHandler_](../src/Monolog/Handler/ChromePHPHandler.php): Handler for [ChromePHP](http://www.chromephp.com/), providing +- [_ChromePHPHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ChromePHPHandler.php): Handler for [ChromePHP](http://www.chromephp.com/), providing inline `console` messages within Chrome. -- [_BrowserConsoleHandler_](../src/Monolog/Handler/BrowserConsoleHandler.php): Handler to send logs to browser's Javascript `console` with +- [_BrowserConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/BrowserConsoleHandler.php): Handler to send logs to browser's Javascript `console` with no browser extension required. Most browsers supporting `console` API are supported. -- [_PHPConsoleHandler_](../src/Monolog/Handler/PHPConsoleHandler.php): Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing +- [_PHPConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PHPConsoleHandler.php): Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing inline `console` and notification popup messages within Chrome. ### Log to databases -- [_RedisHandler_](../src/Monolog/Handler/RedisHandler.php): Logs records to a [redis](http://redis.io) server's key via RPUSH. -- [_RedisPubSubHandler_](../src/Monolog/Handler/RedisPubSubHandler.php): Logs records to a [redis](http://redis.io) server's channel via PUBLISH. -- [_MongoDBHandler_](../src/Monolog/Handler/MongoDBHandler.php): Handler to write records in MongoDB via a +- [_RedisHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RedisHandler.php): Logs records to a [redis](http://redis.io) server's key via RPUSH. +- [_RedisPubSubHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RedisPubSubHandler.php): Logs records to a [redis](http://redis.io) server's channel via PUBLISH. +- [_MongoDBHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/MongoDBHandler.php): Handler to write records in MongoDB via a [Mongo](http://pecl.php.net/package/mongo) extension connection. -- [_CouchDBHandler_](../src/Monolog/Handler/CouchDBHandler.php): Logs records to a CouchDB server. -- [_DoctrineCouchDBHandler_](../src/Monolog/Handler/DoctrineCouchDBHandler.php): Logs records to a CouchDB server via the Doctrine CouchDB ODM. -- [_ElasticsearchHandler_](../src/Monolog/Handler/ElasticsearchHandler.php): Logs records to an Elasticsearch server. -- [_DynamoDbHandler_](../src/Monolog/Handler/DynamoDbHandler.php): Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php). +- [_CouchDBHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/CouchDBHandler.php): Logs records to a CouchDB server. +- [_DoctrineCouchDBHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/DoctrineCouchDBHandler.php): Logs records to a CouchDB server via the Doctrine CouchDB ODM. +- [_ElasticsearchHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ElasticsearchHandler.php): Logs records to an Elasticsearch server. +- [_DynamoDbHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/DynamoDbHandler.php): Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php). ### Wrappers / Special Handlers -- [_FingersCrossedHandler_](../src/Monolog/Handler/FingersCrossedHandler.php): A very interesting wrapper. It takes a handler as +- [_FingersCrossedHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FingersCrossedHandler.php): A very interesting wrapper. It takes a handler as a parameter and will accumulate log records of all levels until a record exceeds the defined severity level. At which point it delivers all records, including those of lower severity, to the handler it wraps. This means that @@ -95,7 +95,7 @@ when it happens you will have the full information, including debug and info records. This provides you with all the information you need, but only when you need it. -- [_DeduplicationHandler_](../src/Monolog/Handler/DeduplicationHandler.php): Useful if you are sending notifications or emails +- [_DeduplicationHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/DeduplicationHandler.php): Useful if you are sending notifications or emails when critical errors occur. It takes a handler as a parameter and will accumulate log records of all levels until the end of the request (or `flush()` is called). At that point it delivers all records to the handler @@ -105,71 +105,71 @@ database is unreachable for example all your requests will fail and that can result in a lot of notifications being sent. Adding this handler reduces the amount of notifications to a manageable level. -- [_WhatFailureGroupHandler_](../src/Monolog/Handler/WhatFailureGroupHandler.php): This handler extends the _GroupHandler_ ignoring +- [_WhatFailureGroupHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/WhatFailureGroupHandler.php): This handler extends the _GroupHandler_ ignoring exceptions raised by each child handler. This allows you to ignore issues where a remote tcp connection may have died but you do not want your entire application to crash and may wish to continue to log to other handlers. -- [_FallbackGroupHandler_](../src/Monolog/Handler/FallbackGroupHandler.php): This handler extends the _GroupHandler_ ignoring +- [_FallbackGroupHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FallbackGroupHandler.php): This handler extends the _GroupHandler_ ignoring exceptions raised by each child handler, until one has handled without throwing. This allows you to ignore issues where a remote tcp connection may have died but you do not want your entire application to crash and may wish to continue to attempt log to other handlers, until one does not throw. -- [_BufferHandler_](../src/Monolog/Handler/BufferHandler.php): This handler will buffer all the log records it receives +- [_BufferHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/BufferHandler.php): This handler will buffer all the log records it receives until `close()` is called at which point it will call `handleBatch()` on the handler it wraps with all the log messages at once. This is very useful to send an email with all records at once for example instead of having one mail for every log record. -- [_GroupHandler_](../src/Monolog/Handler/GroupHandler.php): This handler groups other handlers. Every record received is +- [_GroupHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/GroupHandler.php): This handler groups other handlers. Every record received is sent to all the handlers it is configured with. -- [_FilterHandler_](../src/Monolog/Handler/FilterHandler.php): This handler only lets records of the given levels through +- [_FilterHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FilterHandler.php): This handler only lets records of the given levels through to the wrapped handler. -- [_SamplingHandler_](../src/Monolog/Handler/SamplingHandler.php): Wraps around another handler and lets you sample records +- [_SamplingHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SamplingHandler.php): Wraps around another handler and lets you sample records if you only want to store some of them. -- [_NoopHandler_](../src/Monolog/Handler/NoopHandler.php): This handler handles anything by doing nothing. It does not stop +- [_NoopHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NoopHandler.php): This handler handles anything by doing nothing. It does not stop processing the rest of the stack. This can be used for testing, or to disable a handler when overriding a configuration. -- [_NullHandler_](../src/Monolog/Handler/NullHandler.php): Any record it can handle will be thrown away. This can be used +- [_NullHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NullHandler.php): Any record it can handle will be thrown away. This can be used to put on top of an existing handler stack to disable it temporarily. -- [_PsrHandler_](../src/Monolog/Handler/PsrHandler.php): Can be used to forward log records to an existing PSR-3 logger -- [_TestHandler_](../src/Monolog/Handler/TestHandler.php): Used for testing, it records everything that is sent to it and +- [_PsrHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PsrHandler.php): Can be used to forward log records to an existing PSR-3 logger +- [_TestHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/TestHandler.php): Used for testing, it records everything that is sent to it and has accessors to read out the information. -- [_HandlerWrapper_](../src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create +- [_HandlerWrapper_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/HandlerWrapper.php): A simple handler wrapper you can inherit from to create your own wrappers easily. -- [_OverflowHandler_](../src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it +- [_OverflowHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/OverflowHandler.php): This handler will buffer all the log messages it receives, up until a configured threshold of number of messages of a certain level is reached, after it will pass all log messages to the wrapped handler. Useful for applying in batch processing when you're only interested in significant failures instead of minor, single erroneous events. ## Formatters -- [_LineFormatter_](../src/Monolog/Formatter/LineFormatter.php): Formats a log record into a one-line string. -- [_HtmlFormatter_](../src/Monolog/Formatter/HtmlFormatter.php): Used to format log records into a human readable html table, mainly suitable for emails. -- [_NormalizerFormatter_](../src/Monolog/Formatter/NormalizerFormatter.php): Normalizes objects/resources down to strings so a record can easily be serialized/encoded. -- [_ScalarFormatter_](../src/Monolog/Formatter/ScalarFormatter.php): Used to format log records into an associative array of scalar values. -- [_JsonFormatter_](../src/Monolog/Formatter/JsonFormatter.php): Encodes a log record into json. -- [_WildfireFormatter_](../src/Monolog/Formatter/WildfireFormatter.php): Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler. -- [_ChromePHPFormatter_](../src/Monolog/Formatter/ChromePHPFormatter.php): Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler. -- [_GelfMessageFormatter_](../src/Monolog/Formatter/GelfMessageFormatter.php): Used to format log records into Gelf message instances, only useful for the GelfHandler. -- [_LogstashFormatter_](../src/Monolog/Formatter/LogstashFormatter.php): Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest). -- [_ElasticaFormatter_](../src/Monolog/Formatter/ElasticaFormatter.php): Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler. -- [_LogglyFormatter_](../src/Monolog/Formatter/LogglyFormatter.php): Used to format log records into Loggly messages, only useful for the LogglyHandler. -- [_FlowdockFormatter_](../src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. -- [_MongoDBFormatter_](../src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. -- [_LogmaticFormatter_](../src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. -- [_FluentdFormatter_](../src/Monolog/Formatter/FluentdFormatter.php): Used to format log records to [Fluentd](https://www.fluentd.org/) logs, only useful with the SocketHandler. +- [_LineFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LineFormatter.php): Formats a log record into a one-line string. +- [_HtmlFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/HtmlFormatter.php): Used to format log records into a human readable html table, mainly suitable for emails. +- [_NormalizerFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/NormalizerFormatter.php): Normalizes objects/resources down to strings so a record can easily be serialized/encoded. +- [_ScalarFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ScalarFormatter.php): Used to format log records into an associative array of scalar values. +- [_JsonFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/JsonFormatter.php): Encodes a log record into json. +- [_WildfireFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/WildfireFormatter.php): Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler. +- [_ChromePHPFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ChromePHPFormatter.php): Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler. +- [_GelfMessageFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/GelfMessageFormatter.php): Used to format log records into Gelf message instances, only useful for the GelfHandler. +- [_LogstashFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogstashFormatter.php): Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest). +- [_ElasticaFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ElasticaFormatter.php): Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler. +- [_LogglyFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogglyFormatter.php): Used to format log records into Loggly messages, only useful for the LogglyHandler. +- [_FlowdockFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. +- [_MongoDBFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. +- [_LogmaticFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. +- [_FluentdFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FluentdFormatter.php): Used to format log records to [Fluentd](https://www.fluentd.org/) logs, only useful with the SocketHandler. ## Processors -- [_PsrLogMessageProcessor_](../src/Monolog/Processor/PsrLogMessageProcessor.php): Processes a log record's message according to PSR-3 rules, replacing `{foo}` with the value from `$context['foo']`. -- [_IntrospectionProcessor_](../src/Monolog/Processor/IntrospectionProcessor.php): Adds the line/file/class/method from which the log call originated. -- [_WebProcessor_](../src/Monolog/Processor/WebProcessor.php): Adds the current request URI, request method and client IP to a log record. -- [_MemoryUsageProcessor_](../src/Monolog/Processor/MemoryUsageProcessor.php): Adds the current memory usage to a log record. -- [_MemoryPeakUsageProcessor_](../src/Monolog/Processor/MemoryPeakUsageProcessor.php): Adds the peak memory usage to a log record. -- [_ProcessIdProcessor_](../src/Monolog/Processor/ProcessIdProcessor.php): Adds the process id to a log record. -- [_UidProcessor_](../src/Monolog/Processor/UidProcessor.php): Adds a unique identifier to a log record. -- [_GitProcessor_](../src/Monolog/Processor/GitProcessor.php): Adds the current git branch and commit to a log record. -- [_MercurialProcessor_](../src/Monolog/Processor/MercurialProcessor.php): Adds the current hg branch and commit to a log record. -- [_TagProcessor_](../src/Monolog/Processor/TagProcessor.php): Adds an array of predefined tags to a log record. -- [_HostnameProcessor_](../src/Monolog/Processor/HostnameProcessor.php): Adds the current hostname to a log record. +- [_PsrLogMessageProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/PsrLogMessageProcessor.php): Processes a log record's message according to PSR-3 rules, replacing `{foo}` with the value from `$context['foo']`. +- [_IntrospectionProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/IntrospectionProcessor.php): Adds the line/file/class/method from which the log call originated. +- [_WebProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/WebProcessor.php): Adds the current request URI, request method and client IP to a log record. +- [_MemoryUsageProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/MemoryUsageProcessor.php): Adds the current memory usage to a log record. +- [_MemoryPeakUsageProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/MemoryPeakUsageProcessor.php): Adds the peak memory usage to a log record. +- [_ProcessIdProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/ProcessIdProcessor.php): Adds the process id to a log record. +- [_UidProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/UidProcessor.php): Adds a unique identifier to a log record. +- [_GitProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/GitProcessor.php): Adds the current git branch and commit to a log record. +- [_MercurialProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/MercurialProcessor.php): Adds the current hg branch and commit to a log record. +- [_TagProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/TagProcessor.php): Adds an array of predefined tags to a log record. +- [_HostnameProcessor_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Processor/HostnameProcessor.php): Adds the current hostname to a log record. ## Third Party Packages From cdba0c569301974809a3a8eadcf49928bcb78c7b Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sat, 27 Feb 2021 14:47:59 +0300 Subject: [PATCH 322/498] Deprecated setMethods() usages moving to onlyMethods() --- tests/Monolog/Handler/AmqpHandlerTest.php | 4 ++-- tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php | 2 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 2 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 2 +- tests/Monolog/Handler/ElasticsearchHandlerTest.php | 2 +- tests/Monolog/Handler/FlowdockHandlerTest.php | 2 +- tests/Monolog/Handler/GelfHandlerTest.php | 2 +- tests/Monolog/Handler/InsightOpsHandlerTest.php | 2 +- tests/Monolog/Handler/LogEntriesHandlerTest.php | 2 +- tests/Monolog/Handler/LogmaticHandlerTest.php | 2 +- tests/Monolog/Handler/PHPConsoleHandlerTest.php | 6 +++--- tests/Monolog/Handler/ProcessHandlerTest.php | 6 +++--- tests/Monolog/Handler/PushoverHandlerTest.php | 2 +- tests/Monolog/Handler/RollbarHandlerTest.php | 2 +- tests/Monolog/Handler/SlackHandlerTest.php | 2 +- tests/Monolog/Handler/SocketHandlerTest.php | 2 +- tests/Monolog/Handler/SyslogUdpHandlerTest.php | 8 ++++---- tests/Monolog/Handler/TelegramBotHandlerTest.php | 2 +- tests/Monolog/Handler/UdpSocketTest.php | 4 ++-- tests/Monolog/Handler/ZendMonitorHandlerTest.php | 2 +- tests/Monolog/LoggerTest.php | 2 +- 21 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index a3b6bff93..b3df820fb 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -33,7 +33,7 @@ public function testHandleAmqpExt() $messages = []; $exchange = $this->getMockBuilder('AMQPExchange') - ->setMethods(['publish', 'setName']) + ->onlyMethods(['publish', 'setName']) ->disableOriginalConstructor() ->getMock(); @@ -85,7 +85,7 @@ public function testHandlePhpAmqpLib() $messages = []; $exchange = $this->getMockBuilder('PhpAmqpLib\Channel\AMQPChannel') - ->setMethods(['basic_publish', '__destruct']) + ->onlyMethods(['basic_publish', '__destruct']) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php index 80546aaf5..1d5aa14bc 100644 --- a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php +++ b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -26,7 +26,7 @@ protected function setUp(): void public function testHandle() { $client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient') - ->setMethods(['postDocument']) + ->onlyMethods(['postDocument']) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 0a291253c..2d8f9f6dd 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -24,7 +24,7 @@ public function setUp(): void } $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') - ->setMethods(['formatAttributes', '__call']) + ->onlyMethods(['formatAttributes', '__call']) ->disableOriginalConstructor() ->getMock(); } diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index e66b13945..b08bce2ed 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -43,7 +43,7 @@ public function setUp(): void // base mock Elastica Client object $this->client = $this->getMockBuilder('Elastica\Client') - ->setMethods(['addDocuments']) + ->onlyMethods(['addDocuments']) ->disableOriginalConstructor() ->getMock(); } diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 2cc982b38..764c54c95 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -42,7 +42,7 @@ public function setUp(): void // base mock Elasticsearch Client object $this->client = $this->getMockBuilder('Elasticsearch\Client') - ->setMethods(['bulk']) + ->onlyMethods(['bulk']) ->disableOriginalConstructor() ->getMock(); } diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index ec8ad0878..04bf063dd 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -65,7 +65,7 @@ private function createHandler($token = 'myToken') $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\FlowdockHandler') ->setConstructorArgs($constructorArgs) - ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); $reflectionProperty = new \ReflectionProperty('Monolog\Handler\SocketHandler', 'connectionString'); diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 41de094d0..6a23423df 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -44,7 +44,7 @@ protected function getHandler($messagePublisher) protected function getMessagePublisher() { return $this->getMockBuilder('Gelf\Publisher') - ->setMethods(['publish']) + ->onlyMethods(['publish']) ->disableOriginalConstructor() ->getMock(); } diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index db6b1e051..9c98d3796 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -58,7 +58,7 @@ private function createHandler() $args = array('testToken', 'us', $useSSL, Logger::DEBUG, true); $this->resource = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder(InsightOpsHandler::class) - ->setMethods(array('fsockopen', 'streamSetTimeout', 'closeSocket')) + ->onlyMethods(array('fsockopen', 'streamSetTimeout', 'closeSocket')) ->setConstructorArgs($args) ->getMock(); diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 92a206d65..034d6ab8b 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -63,7 +63,7 @@ private function createHandler() $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\LogEntriesHandler') ->setConstructorArgs($args) - ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); $reflectionProperty = new \ReflectionProperty('Monolog\Handler\SocketHandler', 'connectionString'); diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index de33c6bbc..c30a17942 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -63,7 +63,7 @@ private function createHandler() $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\LogmaticHandler') ->setConstructorArgs($args) - ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); $reflectionProperty = new \ReflectionProperty('Monolog\Handler\SocketHandler', 'connectionString'); diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 1169419fb..98d8a4b2b 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -60,7 +60,7 @@ protected function initDebugDispatcherMock(Connector $connector) { return $this->getMockBuilder('PhpConsole\Dispatcher\Debug') ->disableOriginalConstructor() - ->setMethods(['dispatchDebug']) + ->onlyMethods(['dispatchDebug']) ->setConstructorArgs([$connector, $connector->getDumper()]) ->getMock(); } @@ -69,7 +69,7 @@ protected function initErrorDispatcherMock(Connector $connector) { return $this->getMockBuilder('PhpConsole\Dispatcher\Errors') ->disableOriginalConstructor() - ->setMethods(['dispatchError', 'dispatchException']) + ->onlyMethods(['dispatchError', 'dispatchException']) ->setConstructorArgs([$connector, $connector->getDumper()]) ->getMock(); } @@ -78,7 +78,7 @@ protected function initConnectorMock() { $connector = $this->getMockBuilder('PhpConsole\Connector') ->disableOriginalConstructor() - ->setMethods([ + ->onlyMethods([ 'sendMessage', 'onShutDown', 'isActiveClient', diff --git a/tests/Monolog/Handler/ProcessHandlerTest.php b/tests/Monolog/Handler/ProcessHandlerTest.php index 70619e700..7a71c4d22 100644 --- a/tests/Monolog/Handler/ProcessHandlerTest.php +++ b/tests/Monolog/Handler/ProcessHandlerTest.php @@ -40,7 +40,7 @@ public function testWriteOpensProcessAndWritesToStdInOfProcess() ]; $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler'); - $mockBuilder->setMethods(['writeProcessInput']); + $mockBuilder->onlyMethods(['writeProcessInput']); // using echo as command, as it is most probably available $mockBuilder->setConstructorArgs([self::DUMMY_COMMAND]); @@ -126,7 +126,7 @@ public function testConstructWithValidCwdWorks() public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueException() { $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler'); - $mockBuilder->setMethods(['selectErrorStream']); + $mockBuilder->onlyMethods(['selectErrorStream']); $mockBuilder->setConstructorArgs([self::DUMMY_COMMAND]); $handler = $mockBuilder->getMock(); @@ -159,7 +159,7 @@ public function testStartupWithErrorsThrowsUnexpectedValueException() public function testWritingWithErrorsOnStdOutOfProcessThrowsInvalidArgumentException() { $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler'); - $mockBuilder->setMethods(['readProcessErrors']); + $mockBuilder->onlyMethods(['readProcessErrors']); // using echo as command, as it is most probably available $mockBuilder->setConstructorArgs([self::DUMMY_COMMAND]); diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 6a295c92e..2c77d30ca 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -118,7 +118,7 @@ private function createHandler($token = 'myToken', $user = 'myUser', $title = 'M $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\PushoverHandler') ->setConstructorArgs($constructorArgs) - ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); $reflectionProperty = new \ReflectionProperty('Monolog\Handler\SocketHandler', 'connectionString'); diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 7419ef820..40442105c 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -64,7 +64,7 @@ private function setupRollbarLoggerMock() $this->rollbarLogger = $this->getMockBuilder(RollbarLogger::class) ->setConstructorArgs(array($config)) - ->setMethods(array('log')) + ->onlyMethods(array('log')) ->getMock(); $this->rollbarLogger diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index 4a7833498..c6e30a75f 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -132,7 +132,7 @@ private function createHandler($token = 'myToken', $channel = 'channel1', $usern $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\SlackHandler') ->setConstructorArgs($constructorArgs) - ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); $reflectionProperty = new \ReflectionProperty('Monolog\Handler\SocketHandler', 'connectionString'); diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index f1377f078..272dd704a 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -298,7 +298,7 @@ private function setMockHandler(array $methods = []) $finalMethods = array_merge($defaultMethods, $newMethods); $this->handler = $this->getMockBuilder('Monolog\Handler\SocketHandler') - ->setMethods($finalMethods) + ->onlyMethods($finalMethods) ->setConstructorArgs(['localhost:1234']) ->getMock(); diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 87be81720..7696d67e6 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -35,7 +35,7 @@ public function testWeSplitIntoLines() $time = '2014-01-07T12:34:56+00:00'; $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') - ->setMethods(['write']) + ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); $socket->expects($this->at(0)) @@ -56,7 +56,7 @@ public function testSplitWorksOnEmptyMsg() $handler->setFormatter($this->getIdentityFormatter()); $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') - ->setMethods(['write']) + ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); $socket->expects($this->never()) @@ -75,7 +75,7 @@ public function testRfc() $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", 'debug', true, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) - ->setMethods(array('getDateTime')) + ->onlyMethods(array('getDateTime')) ->getMock(); $handler->method('getDateTime') @@ -85,7 +85,7 @@ public function testRfc() $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') ->setConstructorArgs(array('lol', 999)) - ->setMethods(array('write')) + ->onlyMethods(array('write')) ->getMock(); $socket->expects($this->at(0)) ->method('write') diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index ad524e94c..55a96b837 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -47,7 +47,7 @@ private function createHandler( $this->handler = $this->getMockBuilder(TelegramBotHandler::class) ->setConstructorArgs($constructorArgs) - ->setMethods(['send']) + ->onlyMethods(['send']) ->getMock(); $this->handler->expects($this->atLeast(1)) diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index 530091cde..c14fa8d48 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -22,7 +22,7 @@ class UdpSocketTest extends TestCase public function testWeDoNotTruncateShortMessages() { $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') - ->setMethods(['send']) + ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); @@ -36,7 +36,7 @@ public function testWeDoNotTruncateShortMessages() public function testLongMessagesAreTruncated() { $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') - ->setMethods(['send']) + ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index a3ee0188d..e8fe55c50 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -36,7 +36,7 @@ public function testWrite() ]; $zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler') - ->setMethods(['writeZendMonitorCustomEvent', 'getDefaultFormatter']) + ->onlyMethods(['writeZendMonitorCustomEvent', 'getDefaultFormatter']) ->getMock(); $formatterMock = $this->getMockBuilder('Monolog\Formatter\NormalizerFormatter') diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 0163fafa9..bd5ae20d3 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -239,7 +239,7 @@ public function testProcessorsAreCalledOnlyOnce() $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor') ->disableOriginalConstructor() - ->setMethods(['__invoke']) + ->onlyMethods(['__invoke']) ->getMock() ; $processor->expects($this->once()) From 227343f20bafffdd8eaa1714cf1a85b974712a22 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sat, 27 Feb 2021 15:01:34 +0300 Subject: [PATCH 323/498] Fix of absent formatAttributes method issue --- tests/Monolog/Handler/DynamoDbHandlerTest.php | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 2d8f9f6dd..b6df9baed 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -17,14 +17,27 @@ class DynamoDbHandlerTest extends TestCase { private $client; + private $isV3; + public function setUp(): void { if (!class_exists('Aws\DynamoDb\DynamoDbClient')) { $this->markTestSkipped('aws/aws-sdk-php not installed'); } + $this->isV3 = defined('Aws\Sdk::VERSION') && version_compare(\Aws\Sdk::VERSION, '3.0', '>='); + + $implementedMethods = ['__call']; + $absentMethods = []; + if ($this->isV3) { + $absentMethods[] = 'formatAttributes'; + } else { + $implementedMethods[] = 'formatAttributes'; + } + $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') - ->onlyMethods(['formatAttributes', '__call']) + ->onlyMethods($implementedMethods) + ->addMethods($absentMethods) ->disableOriginalConstructor() ->getMock(); } @@ -53,8 +66,7 @@ public function testHandle() $handler = new DynamoDbHandler($this->client, 'foo'); $handler->setFormatter($formatter); - $isV3 = defined('Aws\Sdk::VERSION') && version_compare(\Aws\Sdk::VERSION, '3.0', '>='); - if ($isV3) { + if ($this->isV3) { $expFormatted = array('foo' => array('N' => 1), 'bar' => array('N' => 2)); } else { $expFormatted = $formatted; @@ -66,7 +78,7 @@ public function testHandle() ->with($record) ->will($this->returnValue($formatted)); $this->client - ->expects($isV3 ? $this->never() : $this->once()) + ->expects($this->isV3 ? $this->never() : $this->once()) ->method('formatAttributes') ->with($this->isType('array')) ->will($this->returnValue($formatted)); From 67294a3a5ff7a3e878baf13cacf1956e71136a61 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sat, 27 Feb 2021 15:18:06 +0300 Subject: [PATCH 324/498] Fix of Predis\Client mock creation Predis\Client uses __call method to process commands (rPush, lTrim), getPartialMock() doesn't work with addMethods() --- tests/Monolog/Handler/RedisHandlerTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index b6cc8524e..7ee409a16 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -109,7 +109,10 @@ public function testPredisHandleCapped() { $redis = $this->createPartialMock('Predis\Client', ['transaction']); - $redisTransaction = $this->createPartialMock('Predis\Client', ['rPush', 'lTrim']); + $redisTransaction = $this->getMockBuilder('Predis\Client') + ->disableOriginalConstructor() + ->addMethods(['rPush', 'lTrim']) + ->getMock(); $redisTransaction->expects($this->once()) ->method('rPush') From 240a159d449b884053460fa7b2774d8d995d7df8 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sat, 27 Feb 2021 15:36:32 +0300 Subject: [PATCH 325/498] Fix of PhpAmqpLib\Channel\AMQPChannel mock creation __destruct was removed in v2.5.0, but version check is impossible (\PhpAmqpLib\Package::VERSION was introduced in v2.11.1) --- tests/Monolog/Handler/AmqpHandlerTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index b3df820fb..c2de874c6 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -84,8 +84,13 @@ public function testHandlePhpAmqpLib() $messages = []; + $methodsToMock = ['basic_publish']; + if (method_exists('PhpAmqpLib\Channel\AMQPChannel', '__destruct')) { + $methodsToMock[] = '__destruct'; + } + $exchange = $this->getMockBuilder('PhpAmqpLib\Channel\AMQPChannel') - ->onlyMethods(['basic_publish', '__destruct']) + ->onlyMethods($methodsToMock) ->disableOriginalConstructor() ->getMock(); From 2bc1351c1e04f5ab7a9bba9ee486b31e65b2dfb1 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sat, 27 Feb 2021 15:54:03 +0300 Subject: [PATCH 326/498] Fix of SyslogUdpHandler mock creation 'datetime' value inside of getRecordWithMessage() result is enough, getDateTime() method is missing & not being used --- tests/Monolog/Handler/SyslogUdpHandlerTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 7696d67e6..129ee3743 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -75,12 +75,9 @@ public function testRfc() $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", 'debug', true, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) - ->onlyMethods(array('getDateTime')) + ->onlyMethods([]) ->getMock(); - $handler->method('getDateTime') - ->willReturn($time); - $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') From f6802992d212d05d16600e5419eed525506863ba Mon Sep 17 00:00:00 2001 From: Yi Yang Date: Thu, 11 Mar 2021 15:05:33 -0800 Subject: [PATCH 327/498] #1539 fix timezone when it's DateTimeImmutable --- src/Monolog/Handler/SyslogUdpHandler.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index a31ae9a01..2bf3da699 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -97,9 +97,12 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $date } if ($this->rfc === self::RFC3164 && ($datetime instanceof \DateTimeImmutable || $datetime instanceof \DateTime)) { - $datetime->setTimezone(new \DateTimeZone('UTC')); + $dateNew = $datetime->setTimezone(new \DateTimeZone('UTC')); + $date = $dateNew->format($this->dateFormats[$this->rfc]); + } + else { + $date = $datetime->format($this->dateFormats[$this->rfc]); } - $date = $datetime->format($this->dateFormats[$this->rfc]); if ($this->rfc === self::RFC3164) { return "<$priority>" . From 0e46f8872c04c8115c73e4e23f78f5a4c5e66a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 27 Mar 2021 12:40:00 +0200 Subject: [PATCH 328/498] MailHandler: Use array access to compare first character --- src/Monolog/Handler/MailHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 3bbfd5655..7d702e7d0 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -70,7 +70,7 @@ protected function getHighestRecord(array $records): array protected function isHtmlBody(string $body): bool { - return substr($body, 0, 1) === '<'; + return $body[0] === '<'; } /** From 53d53af502fc44fa0b546933c3e569d97cab2b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 27 Mar 2021 13:43:44 +0200 Subject: [PATCH 329/498] Update to handle empty string --- src/Monolog/Handler/MailHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 7d702e7d0..7a7b787d8 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -70,7 +70,7 @@ protected function getHighestRecord(array $records): array protected function isHtmlBody(string $body): bool { - return $body[0] === '<'; + return ($body[0] ?? null) === '<'; } /** From c7a5ecca6cf4edd993badc49d54555a6ae9bf888 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sun, 4 Apr 2021 21:34:05 +0300 Subject: [PATCH 330/498] Fix of DynamoDbClient::formatAttributes Looks like formatAttributes() was removed before v3, so switching to method existence check instead of version check --- tests/Monolog/Handler/DynamoDbHandlerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index b6df9baed..bd11abf4f 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -29,10 +29,10 @@ public function setUp(): void $implementedMethods = ['__call']; $absentMethods = []; - if ($this->isV3) { - $absentMethods[] = 'formatAttributes'; - } else { + if (method_exists('Aws\DynamoDb\DynamoDbClient', 'formatAttributes')) { $implementedMethods[] = 'formatAttributes'; + } else { + $absentMethods[] = 'formatAttributes'; } $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') From 812d63b1719237779a87f47b9aa24fb59f3abec3 Mon Sep 17 00:00:00 2001 From: Victor Pryazhnikov Date: Sun, 18 Apr 2021 21:33:01 +0300 Subject: [PATCH 331/498] Fix of incorrect DynamoDB mock creation addMethods([]) breaks the methods configured at onlyMethods() call --- tests/Monolog/Handler/DynamoDbHandlerTest.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index bd11abf4f..2b237bfa5 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -35,11 +35,14 @@ public function setUp(): void $absentMethods[] = 'formatAttributes'; } - $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') + $clientMockBuilder = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') ->onlyMethods($implementedMethods) - ->addMethods($absentMethods) - ->disableOriginalConstructor() - ->getMock(); + ->disableOriginalConstructor(); + if ($absentMethods) { + $clientMockBuilder->addMethods($absentMethods); + } + + $this->client = $clientMockBuilder->getMock(); } public function testConstruct() From df3b93b701f0fbd35249ab93ceee1a327ff8fa68 Mon Sep 17 00:00:00 2001 From: David Schneider Date: Fri, 7 May 2021 11:35:18 +0200 Subject: [PATCH 332/498] Set StreamHandler stream chunk size, fixes #1552 This ensures atomic log record writing to the output stream. --- src/Monolog/Handler/StreamHandler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 344bd3053..5a1266651 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -23,6 +23,8 @@ */ class StreamHandler extends AbstractProcessingHandler { + protected const MAX_CHUNK_SIZE = 2147483647; + /** @var resource|null */ protected $stream; protected $url; @@ -46,6 +48,7 @@ public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true parent::__construct($level, $bubble); if (is_resource($stream)) { $this->stream = $stream; + stream_set_chunk_size($this->stream, self::MAX_CHUNK_SIZE); } elseif (is_string($stream)) { $this->url = Utils::canonicalizePath($stream); } else { @@ -110,6 +113,7 @@ protected function write(array $record): void throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); } + stream_set_chunk_size($this->stream, self::MAX_CHUNK_SIZE); } if ($this->useLocking) { From 2e37d0bbd11ffa49f566f6099c73a96f451c19fa Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 15 May 2021 01:18:18 +0200 Subject: [PATCH 333/498] Fix deprecation warning on PHP 8.1 --- src/Monolog/Logger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index b8b4f55b4..7d26b2916 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -321,7 +321,7 @@ public function addRecord($level, $message, array $context = array()) if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) { $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone); } else { - $ts = new \DateTime(null, static::$timezone); + $ts = new \DateTime('now', static::$timezone); } $ts->setTimezone(static::$timezone); From c6b00f05152ae2c9b04a448f99c7590beb6042f5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 28 May 2021 10:32:12 +0200 Subject: [PATCH 334/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ee097b1..08cbe786a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.26.1 (2021-05-28) + + * Fixed PHP 8.1 deprecation warning + ### 1.26.0 (2020-12-14) * Added $dateFormat and $removeUsedContextFields arguments to PsrLogMessageProcessor (backport from 2.x) From 37ab9fc188624e5a010d38ac26f652334cc154e8 Mon Sep 17 00:00:00 2001 From: Thomas Landauer Date: Fri, 25 Jun 2021 01:05:59 +0200 Subject: [PATCH 335/498] Adding anchor to link --- doc/message-structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/message-structure.md b/doc/message-structure.md index 63c6f19bd..571df4190 100644 --- a/doc/message-structure.md +++ b/doc/message-structure.md @@ -6,7 +6,7 @@ The table below describes which keys are always available for every log message. key | type | description -----------|---------------------------|------------------------------------------------------------------------------- message | string | The log message. When the `PsrLogMessageProcessor` is used this string may contain placeholders that will be replaced by variables from the context, e.g., "User {username} logged in" with `['username' => 'John']` as context will be written as "User John logged in". -level | int | Severity of the log message. See log levels described in [01-usage.md](01-usage.md). +level | int | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels). level_name | string | String representation of log level. context | array | Arbitrary data passed with the construction of the message. For example the username of the current user or their IP address. channel | string | The channel this message was logged to. This is the name that was passed when the logger was created with `new Logger($channel)`. From 01d104aa781db1cdcd045d40432ede89c1411d9b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 28 May 2021 10:29:33 +0200 Subject: [PATCH 336/498] Add Record/Level/LevelName type aliases and improve phpstan type coverage to level 6 --- phpstan.neon.dist | 7 +- src/Monolog/ErrorHandler.php | 85 +++++++++++++------ src/Monolog/Formatter/ChromePHPFormatter.php | 2 + src/Monolog/Formatter/ElasticaFormatter.php | 6 +- .../Formatter/ElasticsearchFormatter.php | 8 +- src/Monolog/Formatter/FlowdockFormatter.php | 4 + src/Monolog/Formatter/FormatterInterface.php | 6 ++ .../Formatter/GelfMessageFormatter.php | 2 + src/Monolog/Formatter/HtmlFormatter.php | 7 +- src/Monolog/Formatter/JsonFormatter.php | 20 ++++- src/Monolog/Formatter/LineFormatter.php | 16 +++- src/Monolog/Formatter/MongoDBFormatter.php | 52 ++++++++---- src/Monolog/Formatter/NormalizerFormatter.php | 11 ++- src/Monolog/Formatter/ScalarFormatter.php | 2 + src/Monolog/Formatter/WildfireFormatter.php | 11 ++- src/Monolog/Handler/AbstractHandler.php | 12 +++ .../Handler/AbstractProcessingHandler.php | 9 ++ src/Monolog/Handler/AbstractSyslogHandler.php | 6 ++ src/Monolog/Handler/AmqpHandler.php | 5 ++ src/Monolog/Handler/BrowserConsoleHandler.php | 20 +++++ src/Monolog/Handler/BufferHandler.php | 7 ++ src/Monolog/Handler/ChromePHPHandler.php | 3 + src/Monolog/Handler/CouchDBHandler.php | 4 + src/Monolog/Handler/CubeHandler.php | 12 ++- src/Monolog/Handler/Curl/Util.php | 1 + src/Monolog/Handler/DeduplicationHandler.php | 8 ++ .../Handler/DoctrineCouchDBHandler.php | 1 + src/Monolog/Handler/DynamoDbHandler.php | 4 + src/Monolog/Handler/ElasticaHandler.php | 11 ++- src/Monolog/Handler/ElasticsearchHandler.php | 12 +-- src/Monolog/Handler/ErrorLogHandler.php | 4 +- src/Monolog/Handler/FilterHandler.php | 20 ++++- .../ActivationStrategyInterface.php | 4 + .../ChannelLevelActivationStrategy.php | 14 ++- src/Monolog/Handler/FingersCrossedHandler.php | 25 +++++- src/Monolog/Handler/FirePHPHandler.php | 17 +++- src/Monolog/Handler/FleepHookHandler.php | 4 + src/Monolog/Handler/FlowdockHandler.php | 6 +- src/Monolog/Handler/GroupHandler.php | 1 + src/Monolog/Handler/HandlerInterface.php | 9 ++ src/Monolog/Handler/IFTTTHandler.php | 2 + src/Monolog/Handler/LogglyHandler.php | 2 + src/Monolog/Handler/MailHandler.php | 8 ++ src/Monolog/Handler/MongoDBHandler.php | 3 + src/Monolog/Handler/NativeMailerHandler.php | 12 +-- src/Monolog/Handler/NewRelicHandler.php | 8 +- src/Monolog/Handler/OverflowHandler.php | 5 +- src/Monolog/Handler/PHPConsoleHandler.php | 31 ++++++- src/Monolog/Handler/ProcessHandler.php | 4 +- .../Handler/ProcessableHandlerInterface.php | 8 +- .../Handler/ProcessableHandlerTrait.php | 7 ++ src/Monolog/Handler/PushoverHandler.php | 28 +++++- src/Monolog/Handler/RedisHandler.php | 7 ++ src/Monolog/Handler/RedisPubSubHandler.php | 2 + src/Monolog/Handler/RollbarHandler.php | 2 + src/Monolog/Handler/RotatingFileHandler.php | 6 ++ src/Monolog/Handler/SamplingHandler.php | 10 ++- src/Monolog/Handler/SendGridHandler.php | 16 ++-- src/Monolog/Handler/Slack/SlackRecord.php | 24 +++++- src/Monolog/Handler/SlackHandler.php | 13 ++- src/Monolog/Handler/SlackWebhookHandler.php | 4 +- src/Monolog/Handler/SocketHandler.php | 41 +++++++-- src/Monolog/Handler/SqsHandler.php | 4 +- src/Monolog/Handler/StreamHandler.php | 18 ++-- src/Monolog/Handler/SwiftMailerHandler.php | 8 +- src/Monolog/Handler/SyslogHandler.php | 2 + src/Monolog/Handler/SyslogUdp/UdpSocket.php | 5 ++ src/Monolog/Handler/SyslogUdpHandler.php | 10 +++ src/Monolog/Handler/TelegramBotHandler.php | 8 +- src/Monolog/Handler/TestHandler.php | 37 +++++++- src/Monolog/Handler/ZendMonitorHandler.php | 9 +- src/Monolog/Logger.php | 34 ++++++-- src/Monolog/Processor/GitProcessor.php | 10 ++- src/Monolog/Processor/HostnameProcessor.php | 4 + .../Processor/IntrospectionProcessor.php | 18 ++-- .../Processor/MemoryPeakUsageProcessor.php | 3 + .../Processor/MemoryUsageProcessor.php | 3 + src/Monolog/Processor/MercurialProcessor.php | 10 ++- src/Monolog/Processor/ProcessIdProcessor.php | 3 + src/Monolog/Processor/ProcessorInterface.php | 5 ++ .../Processor/PsrLogMessageProcessor.php | 3 +- src/Monolog/Processor/TagProcessor.php | 13 +++ src/Monolog/Processor/UidProcessor.php | 4 + src/Monolog/Processor/WebProcessor.php | 15 +++- src/Monolog/Registry.php | 3 +- src/Monolog/SignalHandler.php | 22 ++++- src/Monolog/Test/TestCase.php | 15 +++- tests/Monolog/ErrorHandlerTest.php | 4 +- 88 files changed, 791 insertions(+), 180 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index a56c5030f..04ba0f33d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 5 + level: 6 treatPhpDocTypesAsCertain: false reportUnmatchedIgnoredErrors: false @@ -18,3 +18,8 @@ parameters: - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' paths: - src/Monolog/Handler/LogglyHandler.php + + # blocked by https://github.com/phpstan/phpstan/issues/5091 + - '#has unknown class Monolog\\Handler\\Record#' + - '#::processRecord#' + - '#is incompatible with native type array.#' diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 3cf351a72..e7d244bba 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -25,19 +25,30 @@ */ class ErrorHandler { + /** @var LoggerInterface */ private $logger; - private $previousExceptionHandler; - private $uncaughtExceptionLevelMap; - - private $previousErrorHandler; - private $errorLevelMap; - private $handleOnlyReportedErrors; - - private $hasFatalErrorHandler; - private $fatalLevel; - private $reservedMemory; + /** @var ?callable */ + private $previousExceptionHandler = null; + /** @var array an array of class name to LogLevel::* constant mapping */ + private $uncaughtExceptionLevelMap = []; + + /** @var callable|true|null */ + private $previousErrorHandler = null; + /** @var array an array of E_* constant to LogLevel::* constant mapping */ + private $errorLevelMap = []; + /** @var bool */ + private $handleOnlyReportedErrors = true; + + /** @var bool */ + private $hasFatalErrorHandler = false; + /** @var LogLevel::* */ + private $fatalLevel = LogLevel::ALERT; + /** @var ?string */ + private $reservedMemory = null; + /** @var ?mixed */ private $lastFatalTrace; + /** @var int[] */ private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; public function __construct(LoggerInterface $logger) @@ -50,10 +61,10 @@ public function __construct(LoggerInterface $logger) * * By default it will handle errors, exceptions and fatal errors * - * @param LoggerInterface $logger - * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling - * @param array|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling - * @param string|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling + * @param LoggerInterface $logger + * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling + * @param array|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 * @return ErrorHandler */ public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self @@ -73,7 +84,11 @@ public static function register(LoggerInterface $logger, $errorLevelMap = [], $e return $handler; } - public function registerExceptionHandler($levelMap = [], $callPrevious = true): self + /** + * @param array $levelMap an array of class name to LogLevel::* constant mapping + * @return $this + */ + public function registerExceptionHandler(array $levelMap = [], bool $callPrevious = true): self { $prev = set_exception_handler(function (\Throwable $e): void { $this->handleException($e); @@ -91,12 +106,18 @@ public function registerExceptionHandler($levelMap = [], $callPrevious = true): return $this; } - public function registerErrorHandler(array $levelMap = [], $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true): self + /** + * @param array $levelMap an array of E_* constant to LogLevel::* constant mapping + * @return $this + */ + public function registerErrorHandler(array $levelMap = [], bool $callPrevious = true, int $errorTypes = -1, bool $handleOnlyReportedErrors = true): self { $prev = set_error_handler([$this, 'handleError'], $errorTypes); $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); if ($callPrevious) { $this->previousErrorHandler = $prev ?: true; + } else { + $this->previousErrorHandler = null; } $this->handleOnlyReportedErrors = $handleOnlyReportedErrors; @@ -105,20 +126,23 @@ public function registerErrorHandler(array $levelMap = [], $callPrevious = true, } /** - * @param string|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling - * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done + * @param LogLevel::*|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT + * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done */ public function registerFatalHandler($level = null, int $reservedMemorySize = 20): self { register_shutdown_function([$this, 'handleFatalError']); $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); - $this->fatalLevel = $level; + $this->fatalLevel = null === $level ? LogLevel::ALERT : $level; $this->hasFatalErrorHandler = true; return $this; } + /** + * @return array + */ protected function defaultExceptionLevelMap(): array { return [ @@ -127,6 +151,9 @@ protected function defaultExceptionLevelMap(): array ]; } + /** + * @return array + */ protected function defaultErrorLevelMap(): array { return [ @@ -148,7 +175,10 @@ protected function defaultErrorLevelMap(): array ]; } - private function handleException(\Throwable $e) + /** + * @phpstan-return never + */ + private function handleException(\Throwable $e): void { $level = LogLevel::ERROR; foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { @@ -177,11 +207,13 @@ private function handleException(\Throwable $e) /** * @private + * + * @param mixed[] $context */ - public function handleError($code, $message, $file = '', $line = 0, $context = []) + public function handleError(int $code, string $message, string $file = '', int $line = 0, array $context = []): bool { if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { - return; + return false; } // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries @@ -197,7 +229,7 @@ public function handleError($code, $message, $file = '', $line = 0, $context = [ if ($this->previousErrorHandler === true) { return false; } elseif ($this->previousErrorHandler) { - return ($this->previousErrorHandler)($code, $message, $file, $line, $context); + return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context); } return true; @@ -206,14 +238,14 @@ public function handleError($code, $message, $file = '', $line = 0, $context = [ /** * @private */ - public function handleFatalError() + public function handleFatalError(): void { $this->reservedMemory = ''; $lastError = error_get_last(); if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) { $this->logger->log( - $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, + $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace] ); @@ -226,6 +258,9 @@ public function handleFatalError() } } + /** + * @param int $code + */ private static function codeToString($code): string { switch ($code) { diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 2b4d649c8..424282abd 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -22,6 +22,8 @@ class ChromePHPFormatter implements FormatterInterface { /** * Translates Monolog log levels to Wildfire levels. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 'log', diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 21787bc4f..4dcebda7a 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -17,6 +17,8 @@ * Format a log message into an Elastica Document * * @author Jelle Vink + * + * @phpstan-import-type Record from \Monolog\Logger */ class ElasticaFormatter extends NormalizerFormatter { @@ -68,8 +70,8 @@ public function getType(): string /** * Convert a log message into an Elastica Document - * @param array $record - * @return Document + * + * @phpstan-param Record $record */ protected function getDocument(array $record): Document { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 84affef35..5442cb793 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use DateTime; +use DateTimeInterface; /** * Format a log message into an Elasticsearch record @@ -37,7 +37,7 @@ class ElasticsearchFormatter extends NormalizerFormatter public function __construct(string $index, string $type) { // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. - parent::__construct(DateTime::ISO8601); + parent::__construct(DateTimeInterface::ISO8601); $this->index = $index; $this->type = $type; @@ -76,8 +76,8 @@ public function getType(): string /** * Convert a log message into an Elasticsearch record * - * @param array $record Log message - * @return array + * @param mixed[] $record Log message + * @return mixed[] */ protected function getDocument(array $record): array { diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 301b74b24..f7f2e81a7 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -36,6 +36,8 @@ public function __construct(string $source, string $sourceEmail) /** * {@inheritdoc} + * + * @return mixed[] */ public function format(array $record): array { @@ -70,6 +72,8 @@ public function format(array $record): array /** * {@inheritdoc} + * + * @return mixed[][] */ public function formatBatch(array $records): array { diff --git a/src/Monolog/Formatter/FormatterInterface.php b/src/Monolog/Formatter/FormatterInterface.php index 7442134ec..19617ec5f 100644 --- a/src/Monolog/Formatter/FormatterInterface.php +++ b/src/Monolog/Formatter/FormatterInterface.php @@ -15,6 +15,8 @@ * Interface for formatters * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ interface FormatterInterface { @@ -23,6 +25,8 @@ interface FormatterInterface * * @param array $record A record to format * @return mixed The formatted record + * + * @phpstan-param Record $record */ public function format(array $record); @@ -31,6 +35,8 @@ public function format(array $record); * * @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); } diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 95d7c1d8c..3ca84c33b 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -47,6 +47,8 @@ class GelfMessageFormatter extends NormalizerFormatter /** * Translates Monolog log levels to Graylog2 log priorities. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 7, diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 90db3f2a0..10a4311cb 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -25,6 +25,8 @@ class HtmlFormatter extends NormalizerFormatter { /** * Translates Monolog log levels to html color priorities. + * + * @var array */ protected $logLevels = [ Logger::DEBUG => '#CCCCCC', @@ -79,7 +81,6 @@ protected function addTitle(string $title, int $level): string /** * Formats a log record. * - * @param array $record A record to format * @return string The formatted record */ public function format(array $record): string @@ -113,7 +114,6 @@ public function format(array $record): string /** * Formats a set of log records. * - * @param array $records A set of records to format * @return string The formatted set of records */ public function formatBatch(array $records): string @@ -126,6 +126,9 @@ public function formatBatch(array $records): string return $message; } + /** + * @param mixed $data + */ protected function convertToString($data): string { if (null === $data || is_scalar($data)) { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 59d9f0a01..16421e225 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -19,21 +19,26 @@ * This can be useful to log to databases or remote APIs * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ class JsonFormatter extends NormalizerFormatter { public const BATCH_MODE_JSON = 1; public const BATCH_MODE_NEWLINES = 2; + /** @var self::BATCH_MODE_* */ protected $batchMode; + /** @var bool */ protected $appendNewline; + /** @var bool */ protected $ignoreEmptyContextAndExtra; + /** @var bool */ + protected $includeStacktraces = false; /** - * @var bool + * @param self::BATCH_MODE_* $batchMode */ - protected $includeStacktraces = false; - public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false) { $this->batchMode = $batchMode; @@ -101,6 +106,9 @@ public function formatBatch(array $records): string } } + /** + * @return void + */ public function includeStacktraces(bool $include = true) { $this->includeStacktraces = $include; @@ -108,6 +116,8 @@ public function includeStacktraces(bool $include = true) /** * Return a JSON-encoded array of records. + * + * @phpstan-param Record[] $records */ protected function formatBatchJson(array $records): string { @@ -117,6 +127,8 @@ protected function formatBatchJson(array $records): string /** * Use new lines to separate records instead of a * JSON-encoded array. + * + * @phpstan-param Record[] $records */ protected function formatBatchNewlines(array $records): string { @@ -175,6 +187,8 @@ protected function normalize($data, int $depth = 0) /** * Normalizes given exception with or without its own stack trace based on * `includeStacktraces` property. + * + * {@inheritDoc} */ protected function normalizeException(Throwable $e, int $depth = 0): array { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index de27f2f70..fa87cf359 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -25,9 +25,13 @@ class LineFormatter extends NormalizerFormatter { public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + /** @var string */ protected $format; + /** @var bool */ protected $allowInlineLineBreaks; + /** @var bool */ protected $ignoreEmptyContextAndExtra; + /** @var bool */ protected $includeStacktraces; /** @@ -44,7 +48,7 @@ public function __construct(?string $format = null, ?string $dateFormat = null, parent::__construct($dateFormat); } - public function includeStacktraces(bool $include = true) + public function includeStacktraces(bool $include = true): void { $this->includeStacktraces = $include; if ($this->includeStacktraces) { @@ -52,12 +56,12 @@ public function includeStacktraces(bool $include = true) } } - public function allowInlineLineBreaks(bool $allow = true) + public function allowInlineLineBreaks(bool $allow = true): void { $this->allowInlineLineBreaks = $allow; } - public function ignoreEmptyContextAndExtra(bool $ignore = true) + public function ignoreEmptyContextAndExtra(bool $ignore = true): void { $this->ignoreEmptyContextAndExtra = $ignore; } @@ -121,6 +125,9 @@ public function formatBatch(array $records): string return $message; } + /** + * @param mixed $value + */ public function stringify($value): string { return $this->replaceNewlines($this->convertToString($value)); @@ -139,6 +146,9 @@ protected function normalizeException(\Throwable $e, int $depth = 0): string return $str; } + /** + * @param mixed $data + */ protected function convertToString($data): string { if (null === $data || is_bool($data)) { diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 9241b1b74..0c1197ed3 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -21,8 +21,11 @@ */ class MongoDBFormatter implements FormatterInterface { + /** @var bool */ private $exceptionTraceAsString; + /** @var int */ private $maxNestingLevel; + /** @var bool */ private $isLegacyMongoExt; /** @@ -39,6 +42,8 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri /** * {@inheritDoc} + * + * @return scalar[] */ public function format(array $record): array { @@ -47,40 +52,48 @@ public function format(array $record): array /** * {@inheritDoc} + * + * @return array */ public function formatBatch(array $records): array { + $formatted = []; foreach ($records as $key => $record) { - $records[$key] = $this->format($record); + $formatted[$key] = $this->format($record); } - return $records; + return $formatted; } /** - * @return array|string Array except when max nesting level is reached then a string "[...]" + * @param mixed[] $array + * @return mixed[]|string Array except when max nesting level is reached then a string "[...]" */ - protected function formatArray(array $record, int $nestingLevel = 0) + protected function formatArray(array $array, int $nestingLevel = 0) { - if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) { - foreach ($record as $name => $value) { - if ($value instanceof \DateTimeInterface) { - $record[$name] = $this->formatDate($value, $nestingLevel + 1); - } elseif ($value instanceof \Throwable) { - $record[$name] = $this->formatException($value, $nestingLevel + 1); - } elseif (is_array($value)) { - $record[$name] = $this->formatArray($value, $nestingLevel + 1); - } elseif (is_object($value)) { - $record[$name] = $this->formatObject($value, $nestingLevel + 1); - } + if ($this->maxNestingLevel > 0 && $nestingLevel > $this->maxNestingLevel) { + return '[...]'; + } + + foreach ($array as $name => $value) { + if ($value instanceof \DateTimeInterface) { + $array[$name] = $this->formatDate($value, $nestingLevel + 1); + } elseif ($value instanceof \Throwable) { + $array[$name] = $this->formatException($value, $nestingLevel + 1); + } elseif (is_array($value)) { + $array[$name] = $this->formatArray($value, $nestingLevel + 1); + } elseif (is_object($value)) { + $array[$name] = $this->formatObject($value, $nestingLevel + 1); } - } else { - $record = '[...]'; } - return $record; + return $array; } + /** + * @param mixed $value + * @return mixed[]|string + */ protected function formatObject($value, int $nestingLevel) { $objectVars = get_object_vars($value); @@ -89,6 +102,9 @@ protected function formatObject($value, int $nestingLevel) return $this->formatArray($objectVars, $nestingLevel); } + /** + * @return mixed[]|string + */ protected function formatException(\Throwable $exception, int $nestingLevel) { $formattedException = [ diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 4daef8142..29288543f 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -123,7 +123,7 @@ public function setJsonPrettyPrint(bool $enable): self /** * @param mixed $data - * @return int|bool|string|null|array + * @return scalar|array */ protected function normalize($data, int $depth = 0) { @@ -189,7 +189,7 @@ protected function normalize($data, int $depth = 0) } /** - * @return array + * @return mixed[] */ protected function normalizeException(Throwable $e, int $depth = 0) { @@ -248,6 +248,9 @@ protected function toJson($data, bool $ignoreErrors = false): string return Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors); } + /** + * @return string + */ protected function formatDate(\DateTimeInterface $date) { // in case the date format isn't custom then we defer to the custom DateTimeImmutable @@ -259,12 +262,12 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } - public function addJsonEncodeOption(int $option) + public function addJsonEncodeOption(int $option): void { $this->jsonEncodeOptions |= $option; } - public function removeJsonEncodeOption(int $option) + public function removeJsonEncodeOption(int $option): void { $this->jsonEncodeOptions &= ~$option; } diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index 17402041b..c8889b5b1 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -21,6 +21,8 @@ class ScalarFormatter extends NormalizerFormatter { /** * {@inheritdoc} + * + * @phpstan-return scalar[] $record */ public function format(array $record): array { diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 20288ab5b..5ee94d71f 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -19,11 +19,15 @@ * @author Eric Clemmons (@ericclemmons) * @author Christophe Coevoet * @author Kirill chEbba Chebunin + * + * @phpstan-import-type Level from \Monolog\Logger */ class WildfireFormatter extends NormalizerFormatter { /** * Translates Monolog log levels to Wildfire levels. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 'LOG', @@ -49,6 +53,8 @@ public function __construct(?string $dateFormat = null) /** * {@inheritdoc} + * + * @return string */ public function format(array $record): string { @@ -108,6 +114,8 @@ public function format(array $record): string /** * {@inheritdoc} + * + * @phpstan-return never */ public function formatBatch(array $records) { @@ -116,7 +124,8 @@ public function formatBatch(array $records) /** * {@inheritdoc} - * @return int|bool|string|null|array|object + * + * @return scalar|array|object */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index c9405bfbf..6d0fdae2a 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -18,10 +18,17 @@ * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano + * + * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractHandler extends Handler implements ResettableInterface { + /** + * @var int + * @phpstan-var Level + */ protected $level = Logger::DEBUG; + /** @var bool */ protected $bubble = true; /** @@ -59,6 +66,8 @@ public function setLevel($level): self * Gets minimum logging level at which this handler will be triggered. * * @return int + * + * @phpstan-return Level */ public function getLevel(): int { @@ -90,6 +99,9 @@ public function getBubble(): bool return $this->bubble; } + /** + * {@inheritDoc} + */ public function reset() { } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 1100260ca..eaff86ac7 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -18,6 +18,10 @@ * * @author Jordi Boggiano * @author Christophe Coevoet + * + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level 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 { @@ -46,9 +50,14 @@ public function handle(array $record): bool /** * Writes the record down to the log of the implementing handler + * + * @phpstan-param FormattedRecord $record */ abstract protected function write(array $record): void; + /** + * @return void + */ public function reset() { parent::reset(); diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index b7f249d7b..55a3384d7 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -17,13 +17,18 @@ /** * Common syslog functionality + * + * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractSyslogHandler extends AbstractProcessingHandler { + /** @var int */ protected $facility; /** * Translates Monolog log levels to syslog log priorities. + * @var array + * @phpstan-var array */ protected $logLevels = [ Logger::DEBUG => LOG_DEBUG, @@ -38,6 +43,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * List of valid log facility names. + * @var array */ protected $facilities = [ 'auth' => LOG_AUTH, diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 33fffccd8..d91f1b68a 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -18,6 +18,9 @@ use PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; +/** + * @phpstan-import-type Record from \Monolog\Logger + */ class AmqpHandler extends AbstractProcessingHandler { /** @@ -108,6 +111,8 @@ public function handleBatch(array $records): void /** * Gets the routing key for the AMQP exchange + * + * @phpstan-param Record $record */ protected function getRoutingKey(array $record): string { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 310591c7c..6245def42 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -19,10 +19,14 @@ * Handler sending logs to browser's javascript console with no browser extension required * * @author Olivier Poitrey + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class BrowserConsoleHandler extends AbstractProcessingHandler { + /** @var bool */ protected static $initialized = false; + /** @var FormattedRecord[] */ protected static $records = []; /** @@ -165,6 +169,9 @@ private static function generateScript(): string return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } + /** + * @return string[] + */ private static function handleStyles(string $formatted): array { $args = []; @@ -205,6 +212,10 @@ private static function handleCustomStyles(string $style, string $string): strin }, $style); } + /** + * @param mixed[] $dict + * @return mixed[] + */ private static function dump(string $title, array $dict): array { $script = []; @@ -229,13 +240,22 @@ private static function quote(string $arg): string return '"' . addcslashes($arg, "\"\n\\") . '"'; } + /** + * @param mixed $args + */ private static function call(...$args): string { $method = array_shift($args); + if (!is_string($method)) { + throw new \UnexpectedValueException('Expected the first arg to be a string, got: '.var_export($method, true)); + } return static::call_array($method, $args); } + /** + * @param mixed[] $args + */ private static function call_array(string $method, array $args): string { return 'c.' . $method . '(' . implode(', ', $args) . ');'; diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index fbf5effa4..874fd0d9f 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -22,6 +22,8 @@ * sending one per log message. * * @author Christophe Coevoet + * + * @phpstan-import-type Record from \Monolog\Logger */ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { @@ -29,10 +31,15 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa /** @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; /** diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 44dbf0d48..d9b587674 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -42,6 +42,7 @@ 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}'; + /** @var bool */ protected static $initialized = false; /** @@ -53,12 +54,14 @@ class ChromePHPHandler extends AbstractProcessingHandler */ protected static $overflowed = false; + /** @var mixed[] */ protected static $json = [ 'version' => self::VERSION, 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [], ]; + /** @var bool */ protected static $sendHeaders = true; /** diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index b2d1e1897..526576132 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -22,8 +22,12 @@ */ class CouchDBHandler extends AbstractProcessingHandler { + /** @var mixed[] */ private $options; + /** + * @param mixed[] $options + */ public function __construct(array $options = [], $level = Logger::DEBUG, bool $bubble = true) { $this->options = array_merge([ diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 00d38e990..d40ac4354 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -22,11 +22,17 @@ */ class CubeHandler extends AbstractProcessingHandler { - private $udpConnection; - private $httpConnection; + /** @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 $acceptedSchemes = ['http', 'udp']; /** @@ -53,7 +59,7 @@ public function __construct(string $url, $level = Logger::DEBUG, bool $bubble = $this->scheme = $urlInfo['scheme']; $this->host = $urlInfo['host']; - $this->port = $urlInfo['port']; + $this->port = (int) $urlInfo['port']; parent::__construct($level, $bubble); } diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index cc0b6c39a..7213e8ee2 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -20,6 +20,7 @@ */ final class Util { + /** @var array */ private static $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 864c29ae0..be27c03ae 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -32,6 +32,8 @@ * same way. * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ class DeduplicationHandler extends BufferHandler { @@ -100,6 +102,9 @@ public function flush(): void } } + /** + * @phpstan-param Record $record + */ private function isDuplicate(array $record): bool { if (!file_exists($this->deduplicationStore)) { @@ -166,6 +171,9 @@ private function collectLogs(): void $this->gc = false; } + /** + * @phpstan-param Record $record + */ private function appendRecord(array $record): void { file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index b80490d13..ebd52c3a0 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -23,6 +23,7 @@ */ class DoctrineCouchDBHandler extends AbstractProcessingHandler { + /** @var CouchDBClient */ private $client; public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 29f340a05..9948ef190 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -86,6 +86,10 @@ protected function write(array $record): void ]); } + /** + * @param mixed[] $record + * @return mixed[] + */ protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 7af68fef6..3c6f8795b 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Elastica\Document; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\ElasticaFormatter; use Monolog\Logger; @@ -41,13 +42,13 @@ class ElasticaHandler extends AbstractProcessingHandler protected $client; /** - * @var array Handler config options + * @var mixed[] Handler config options */ protected $options = []; /** * @param Client $client Elastica Client object - * @param array $options Handler configuration + * @param mixed[] $options Handler configuration * @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 */ @@ -85,6 +86,9 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); } + /** + * @return mixed[] + */ public function getOptions(): array { return $this->options; @@ -109,6 +113,9 @@ public function handleBatch(array $records): void /** * Use Elasticsearch bulk API to send list of documents + * + * @param Document[] $documents + * * @throws \RuntimeException */ protected function bulkSend(array $documents): void diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 7a7ef0596..fddcc5be3 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -49,13 +49,13 @@ class ElasticsearchHandler extends AbstractProcessingHandler protected $client; /** - * @var array Handler config options + * @var mixed[] Handler config options */ protected $options = []; /** * @param Client $client Elasticsearch Client object - * @param array $options Handler configuration + * @param mixed[] $options Handler configuration * @param string|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 */ @@ -96,7 +96,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface /** * Getter options * - * @return array + * @return mixed[] */ public function getOptions(): array { @@ -123,7 +123,7 @@ public function handleBatch(array $records): void /** * Use Elasticsearch bulk API to send list of documents * - * @param array $records + * @param array[] $records Records + _index/_type keys * @throws \RuntimeException */ protected function bulkSend(array $records): void @@ -162,7 +162,7 @@ protected function bulkSend(array $records): void * * Only the first error is converted into an exception. * - * @param array $responses returned by $this->client->bulk() + * @param mixed[] $responses returned by $this->client->bulk() */ protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException { @@ -178,7 +178,7 @@ protected function createExceptionFromResponses(array $responses): Elasticsearch /** * Creates elasticsearch exception from error array * - * @param array $error + * @param mixed[] $error */ protected function createExceptionFromError(array $error): ElasticsearchRuntimeException { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 737c0705d..fb0ebf2f4 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -25,7 +25,9 @@ class ErrorLogHandler extends AbstractProcessingHandler public const OPERATING_SYSTEM = 0; public const SAPI = 4; + /** @var int */ protected $messageType; + /** @var bool */ protected $expandNewlines; /** @@ -49,7 +51,7 @@ public function __construct(int $messageType = self::OPERATING_SYSTEM, $level = } /** - * @return array With all available types + * @return int[] With all available types */ public static function getAvailableTypes(): array { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 36e2cd0fa..cad7637df 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; +use Psr\Log\LogLevel; /** * Simple handler wrapper that filters records based on a list of levels @@ -22,6 +23,10 @@ * * @author Hennadiy Verkh * @author Jordi Boggiano + * + * @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 { @@ -30,7 +35,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * Handler or factory callable($record, $this) * - * @var callable|\Monolog\Handler\HandlerInterface + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface */ protected $handler; @@ -38,6 +44,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * Minimum level for logs that are passed to handler * * @var int[] + * @phpstan-var Level[] */ protected $acceptedLevels; @@ -49,12 +56,14 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese protected $bubble; /** - * @psalm-param HandlerInterface|callable(?array, HandlerInterface): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @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 Level|LevelName|LogLevel::*|array $minLevelOrList */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) { @@ -67,6 +76,9 @@ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel } } + /** + * @phpstan-return Level[] + */ public function getAcceptedLevels(): array { return array_flip($this->acceptedLevels); @@ -75,6 +87,8 @@ public function getAcceptedLevels(): 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 Level|LevelName|LogLevel::*|array $minLevelOrList */ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self { @@ -141,6 +155,8 @@ public function handleBatch(array $records): void * 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(array $record = null) { diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index 1ba99c73d..0aa5607b1 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -15,11 +15,15 @@ * Interface for activation strategies for the FingersCrossedHandler. * * @author Johannes M. Schmitt + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ActivationStrategyInterface { /** * Returns whether the given record activates the handler. + * + * @phpstan-param Record $record */ public function isHandlerActivated(array $record): bool; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index f98ecfac1..599d76c6b 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -32,6 +32,9 @@ * * * @author Mike Meessen + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { @@ -41,13 +44,15 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private $defaultActionLevel; /** - * @var array + * @var array */ private $channelToActionLevel; /** - * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $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 $channelToActionLevel An array that maps channel names to action levels. + * + * @phpstan-param array $channelToActionLevel */ public function __construct($defaultActionLevel, array $channelToActionLevel = []) { @@ -55,6 +60,9 @@ public function __construct($defaultActionLevel, array $channelToActionLevel = [ $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } + /** + * @phpstan-param Record $record + */ public function isHandlerActivated(array $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 2253e71f5..45801ec7d 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -32,23 +32,40 @@ * Monolog\Handler\FingersCrossed\ namespace. * * @author Jordi Boggiano + * + * @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; - /** @var HandlerInterface */ + /** + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface + */ 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; /** - * @psalm-param HandlerInterface|callable(?array, FingersCrossedHandler): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @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 @@ -171,7 +188,7 @@ private function flushBuffer(): void return $record['level'] >= $level; }); if (count($this->buffer) > 0) { - $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); + $this->getHandler(end($this->buffer))->handleBatch($this->buffer); } } @@ -185,6 +202,8 @@ private function flushBuffer(): void * 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(array $record = null) { diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index c96386304..f57677c86 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -18,6 +18,8 @@ * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. * * @author Eric Clemmons (@ericclemmons) + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FirePHPHandler extends AbstractProcessingHandler { @@ -45,6 +47,7 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet + * @var bool */ protected static $initialized = false; @@ -54,14 +57,15 @@ class FirePHPHandler extends AbstractProcessingHandler */ protected static $messageIndex = 1; + /** @var bool */ protected static $sendHeaders = true; /** * Base header creation function used by init headers & record headers * - * @param array $meta Wildfire Plugin, Protocol & Structure Indexes - * @param string $message Log message - * @return array Complete header string ready for the client as key and message as value + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * @return array Complete header string ready for the client as key and message as value */ protected function createHeader(array $meta, string $message): array { @@ -73,7 +77,11 @@ protected function createHeader(array $meta, string $message): array /** * Creates message header from record * + * @return array + * * @see createHeader() + * + * @phpstan-param FormattedRecord $record */ protected function createRecordHeader(array $record): array { @@ -98,6 +106,8 @@ protected function getDefaultFormatter(): FormatterInterface * * @see createHeader() * @see sendHeader() + * + * @return array */ protected function getInitHeaders(): array { @@ -124,7 +134,6 @@ protected function sendHeader(string $header, string $content): void * * @see sendHeader() * @see sendInitHeaders() - * @param array $record */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 5087009ff..815844072 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -22,6 +22,8 @@ * * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation * @author Ando Roots + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FleepHookHandler extends SocketHandler { @@ -104,6 +106,8 @@ private function buildHeader(string $content): string /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index 062af418d..c12fe334f 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -26,6 +26,8 @@ * * @author Dominik Liebler * @see https://www.flowdock.com/api/push + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FlowdockHandler extends SocketHandler { @@ -72,8 +74,6 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { @@ -94,6 +94,8 @@ protected function generateDataStream(array $record): string /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index a7d8a3179..7265d87a3 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -25,6 +25,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset /** @var HandlerInterface[] */ protected $handlers; + /** @var bool */ protected $bubble; /** diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index 68aed1866..affcc51fc 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -15,6 +15,9 @@ * Interface that all Monolog Handlers must implement * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface { @@ -30,6 +33,8 @@ interface HandlerInterface * @param array $record Partial log record containing only a level key * * @return bool + * + * @phpstan-param array{level: Level} $record */ public function isHandling(array $record): bool; @@ -46,6 +51,8 @@ public function isHandling(array $record): bool; * @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(array $record): bool; @@ -53,6 +60,8 @@ public function handle(array $record): bool; * Handles a set of records at once. * * @param array $records The records to handle (an array of record arrays) + * + * @phpstan-param Record[] $records */ public function handleBatch(array $records): void; diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 921c9f245..c8ed6ff7e 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -27,7 +27,9 @@ */ class IFTTTHandler extends AbstractProcessingHandler { + /** @var string */ private $eventName; + /** @var string */ private $secretKey; /** diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 6fc7066c6..cd110bf73 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -37,8 +37,10 @@ class LogglyHandler extends AbstractProcessingHandler */ protected $curlHandlers = []; + /** @var string */ protected $token; + /** @var string[] */ protected $tag = []; /** diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 7a7b787d8..a0148a587 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -18,6 +18,8 @@ * Base class for all mail handlers * * @author Gyula Sallai + * + * @phpstan-import-type Record from \Monolog\Logger */ abstract class MailHandler extends AbstractProcessingHandler { @@ -45,6 +47,8 @@ public function handleBatch(array $records): void * * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content + * + * @phpstan-param Record[] $records */ abstract protected function send(string $content, array $records): void; @@ -56,6 +60,10 @@ protected function write(array $record): void $this->send((string) $record['formatted'], [$record]); } + /** + * @phpstan-param Record[] $records + * @phpstan-return Record + */ protected function getHighestRecord(array $records): array { $highestRecord = null; diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index e7539174e..477bcd647 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -33,8 +33,11 @@ */ class MongoDBHandler extends AbstractProcessingHandler { + /** @var \MongoDB\Collection */ private $collection; + /** @var Client|Manager */ private $manager; + /** @var string */ private $namespace; /** diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index cd205611a..c2ef64e60 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -24,7 +24,7 @@ class NativeMailerHandler extends MailHandler { /** * The email addresses to which the message will be sent - * @var array + * @var string[] */ protected $to; @@ -36,13 +36,13 @@ class NativeMailerHandler extends MailHandler /** * Optional headers for the message - * @var array + * @var string[] */ protected $headers = []; /** * Optional parameters for the message - * @var array + * @var string[] */ protected $parameters = []; @@ -65,7 +65,7 @@ class NativeMailerHandler extends MailHandler protected $encoding = 'utf-8'; /** - * @param string|array $to The receiver of the mail + * @param string|string[] $to The receiver of the mail * @param string $subject The subject of the mail * @param string $from The sender of the mail * @param string|int $level The minimum logging level at which this handler will be triggered @@ -84,7 +84,7 @@ public function __construct($to, string $subject, string $from, $level = Logger: /** * Add headers to the message * - * @param string|array $headers Custom added headers + * @param string|string[] $headers Custom added headers */ public function addHeader($headers): self { @@ -101,7 +101,7 @@ public function addHeader($headers): self /** * Add parameters to the message * - * @param string|array $parameters Custom added parameters + * @param string|string[] $parameters Custom added parameters */ public function addParameter($parameters): self { diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 177ad21a9..25df54270 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -30,14 +30,14 @@ class NewRelicHandler extends AbstractProcessingHandler /** * Name of the New Relic application that will receive logs from this handler. * - * @var string|null + * @var ?string */ protected $appName; /** * Name of the current transaction * - * @var string|null + * @var ?string */ protected $transactionName; @@ -135,6 +135,8 @@ protected function isNewRelicEnabled(): bool /** * Returns the appname where this log should be sent. Each log can override the default appname, set in this * handler's constructor, by providing the appname in it's context. + * + * @param mixed[] $context */ protected function getAppName(array $context): ?string { @@ -148,6 +150,8 @@ protected function getAppName(array $context): ?string /** * Returns the name of the current transaction. Each log can override the default transaction name, set in this * handler's constructor, by providing the transaction_name in it's context + * + * @param mixed[] $context */ protected function getTransactionName(array $context): ?string { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 4c3098656..04760749f 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -87,10 +87,7 @@ public function __construct( * 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 array $record The record to handle - * - * @return Boolean 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. + * {@inheritdoc} */ public function handle(array $record): bool { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 94802d0bb..d596c0461 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -37,9 +37,12 @@ * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin + * + * @phpstan-import-type Record from \Monolog\Logger */ class PHPConsoleHandler extends AbstractProcessingHandler { + /** @var array */ private $options = [ 'enabled' => true, // bool Is PHP Console server enabled 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... @@ -67,10 +70,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler private $connector; /** - * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details - * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param string|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. + * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details + * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) + * @param string|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. * @throws \RuntimeException */ public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) @@ -83,6 +86,10 @@ public function __construct(array $options = [], ?Connector $connector = null, $ $this->connector = $this->initConnector($connector); } + /** + * @param array $options + * @return array + */ private function initOptions(array $options): array { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); @@ -153,6 +160,9 @@ public function getConnector(): Connector return $this->connector; } + /** + * @return array + */ public function getOptions(): array { return $this->options; @@ -181,6 +191,9 @@ protected function write(array $record): void } } + /** + * @phpstan-param Record $record + */ private function handleDebugRecord(array $record): void { $tags = $this->getRecordTags($record); @@ -191,11 +204,17 @@ private function handleDebugRecord(array $record): void $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } + /** + * @phpstan-param Record $record + */ private function handleExceptionRecord(array $record): void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } + /** + * @phpstan-param Record $record + */ private function handleErrorRecord(array $record): void { $context = $record['context']; @@ -209,6 +228,10 @@ private function handleErrorRecord(array $record): void ); } + /** + * @phpstan-param Record $record + * @return string + */ private function getRecordTags(array &$record) { $tags = null; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 36e30b87a..97549949d 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -44,12 +44,12 @@ class ProcessHandler extends AbstractProcessingHandler private $cwd; /** - * @var array + * @var resource[] */ private $pipes = []; /** - * @var array + * @var array */ protected const DESCRIPTOR_SPEC = [ 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 41b52ce5f..a74876170 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -17,13 +17,15 @@ * Interface to describe loggers that have processors * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessableHandlerInterface { /** * Adds a processor in the stack. * - * @psalm-param ProcessorInterface|callable(array): array $callback + * @psalm-param ProcessorInterface|callable(Record): Record $callback * * @param ProcessorInterface|callable $callback * @return HandlerInterface self @@ -33,10 +35,10 @@ public function pushProcessor(callable $callback): HandlerInterface; /** * Removes the processor on top of the stack and returns it. * - * @psalm-return callable(array): array + * @psalm-return ProcessorInterface|callable(Record): Record $callback * * @throws \LogicException In case the processor stack is empty - * @return callable + * @return callable|ProcessorInterface */ public function popProcessor(): callable; } diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 71d767bec..f3cdd2a34 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -12,16 +12,20 @@ namespace Monolog\Handler; use Monolog\ResettableInterface; +use Monolog\Processor\ProcessorInterface; /** * Helper trait for implementing ProcessableInterface * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ trait ProcessableHandlerTrait { /** * @var callable[] + * @phpstan-var array */ protected $processors = []; @@ -49,6 +53,9 @@ public function popProcessor(): callable /** * Processes a record. + * + * @phpstan-param Record $record + * @phpstan-return Record */ protected function processRecord(array $record): array { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 3bb99c759..12cc101cd 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -19,24 +19,35 @@ * * @author Sebastian Göttschkes * @see https://www.pushover.net/api + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class PushoverHandler extends SocketHandler { + /** @var string */ private $token; + /** @var array */ private $users; + /** @var ?string */ private $title; - private $user; + /** @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 + * @var array */ private $parameterNames = [ 'token' => true, @@ -57,7 +68,7 @@ class PushoverHandler extends SocketHandler /** * Sounds the api supports by default * @see https://pushover.net/api#sounds - * @var array + * @var string[] */ private $sounds = [ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', @@ -81,6 +92,8 @@ class PushoverHandler extends SocketHandler * 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 $users */ public function __construct( string $token, @@ -113,6 +126,9 @@ protected function generateDataStream(array $record): string return $this->buildHeader($content) . $content; } + /** + * @phpstan-param FormattedRecord $record + */ private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. @@ -177,6 +193,9 @@ protected function write(array $record): void $this->user = null; } + /** + * @param int|string $value + */ public function setHighPriorityLevel($value): self { $this->highPriorityLevel = Logger::toMonologLevel($value); @@ -184,6 +203,9 @@ public function setHighPriorityLevel($value): self return $this; } + /** + * @param int|string $value + */ public function setEmergencyLevel($value): self { $this->emergencyLevel = Logger::toMonologLevel($value); diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 46482b61d..02ee1c14e 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -25,11 +25,16 @@ * $log->pushHandler($redis); * * @author Thomas Tourlourat + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class RedisHandler extends AbstractProcessingHandler { + /** @var \Predis\Client|\Redis */ private $redisClient; + /** @var string */ private $redisKey; + /** @var int */ protected $capSize; /** @@ -67,6 +72,8 @@ protected function write(array $record): void /** * Write and cap the collection * Writes the record to the redis list and caps its + * + * @phpstan-param FormattedRecord $record */ protected function writeCapped(array $record): void { diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index c9b13198b..f6db48032 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -28,7 +28,9 @@ */ class RedisPubSubHandler extends AbstractProcessingHandler { + /** @var \Predis\Client|\Redis */ private $redisClient; + /** @var string */ private $channelKey; /** diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 979d651e3..fdc4abb97 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -38,6 +38,7 @@ class RollbarHandler extends AbstractProcessingHandler */ protected $rollbarLogger; + /** @var string[] */ protected $levelMap = [ Logger::DEBUG => 'debug', Logger::INFO => 'info', @@ -56,6 +57,7 @@ class RollbarHandler extends AbstractProcessingHandler */ private $hasRecords = false; + /** @var bool */ protected $initialized = false; /** diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index f61e5eb6e..949fd1b80 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -30,11 +30,17 @@ class RotatingFileHandler extends StreamHandler public const FILE_PER_MONTH = 'Y-m'; public const FILE_PER_YEAR = 'Y'; + /** @var string */ protected $filename; + /** @var int */ protected $maxFiles; + /** @var bool */ protected $mustRotate; + /** @var \DateTimeImmutable */ protected $nextRotation; + /** @var string */ protected $filenameFormat; + /** @var string */ protected $dateFormat; /** diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 4c33d4a3c..d76f1d351 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -26,13 +26,17 @@ * * @author Bryan Davis * @author Kunal Mehta + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; /** - * @var callable|HandlerInterface $handler + * @var HandlerInterface|callable + * @phpstan-var HandlerInterface|callable(Record, HandlerInterface): HandlerInterface */ protected $handler; @@ -42,7 +46,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter protected $factor; /** - * @psalm-param HandlerInterface|callable(array, HandlerInterface): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(Record, HandlerInterface): HandlerInterface $handler * * @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) @@ -81,6 +85,8 @@ public function handle(array $record): bool * * 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(array $record = null) diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index e774d309b..3dcf91550 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -40,7 +40,7 @@ class SendGridHandler extends MailHandler /** * The email addresses to which the message will be sent - * @var array + * @var string[] */ protected $to; @@ -51,13 +51,13 @@ class SendGridHandler extends MailHandler protected $subject; /** - * @param string $apiUser The SendGrid API User - * @param string $apiKey The SendGrid API Key - * @param string $from The sender of the email - * @param string|array $to The recipients of the email - * @param string $subject The subject of the mail - * @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 + * @param string $apiUser The SendGrid API User + * @param string $apiKey The SendGrid API Key + * @param string $from The sender of the email + * @param string|string[] $to The recipients of the email + * @param string $subject The subject of the mail + * @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 */ public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 6658d0d44..53f2e760d 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -23,6 +23,8 @@ * @author Haralan Dobrev * @see https://api.slack.com/incoming-webhooks * @see https://api.slack.com/docs/message-attachments + * + * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler */ class SlackRecord { @@ -72,7 +74,7 @@ class SlackRecord /** * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] - * @var array + * @var string[] */ private $excludeFields; @@ -86,6 +88,9 @@ class SlackRecord */ private $normalizerFormatter; + /** + * @param string[] $excludeFields + */ public function __construct( ?string $channel = null, ?string $username = null, @@ -114,6 +119,9 @@ public function __construct( /** * Returns required data in format that Slack * is expecting. + * + * @phpstan-param FormattedRecord $record + * @phpstan-return string[] */ public function getSlackData(array $record): array { @@ -208,6 +216,8 @@ public function getAttachmentColor(int $level): string /** * Stringifies an array of key/value pairs to be used in attachment fields + * + * @param mixed[] $fields */ public function stringify(array $fields): string { @@ -285,6 +295,9 @@ public function includeContextAndExtra(bool $includeContextAndExtra = false): se return $this; } + /** + * @param string[] $excludeFields + */ public function excludeFields(array $excludeFields = []): self { $this->excludeFields = $excludeFields; @@ -302,7 +315,8 @@ public function setFormatter(?FormatterInterface $formatter = null): self /** * Generates attachment field * - * @param string|array $value + * @param string|mixed[] $value + * @return array{title: string, value: string, short: false} */ private function generateAttachmentField(string $title, $value): array { @@ -319,6 +333,9 @@ private function generateAttachmentField(string $title, $value): array /** * Generates a collection of attachment fields from array + * + * @param mixed[] $data + * @return array */ private function generateAttachmentFields(array $data): array { @@ -332,6 +349,9 @@ private function generateAttachmentFields(array $data): array /** * Get a copy of record with fields excluded according to $this->excludeFields + * + * @phpstan-param FormattedRecord $record + * @return mixed[] */ private function removeExcludedFields(array $record): array { diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 1535a1804..67e97474c 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -21,6 +21,8 @@ * * @author Greg Kedzierski * @see https://api.slack.com/ + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SlackHandler extends SocketHandler { @@ -46,7 +48,7 @@ class SlackHandler extends SocketHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ public function __construct( @@ -102,6 +104,8 @@ protected function generateDataStream(array $record): string /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { @@ -110,6 +114,10 @@ private function buildContent(array $record): string return http_build_query($dataArray); } + /** + * @phpstan-param FormattedRecord $record + * @return string[] + */ protected function prepareContentData(array $record): array { $dataArray = $this->slackRecord->getSlackData($record); @@ -224,6 +232,9 @@ public function includeContextAndExtra(bool $includeContextAndExtra): self return $this; } + /** + * @param string[] $excludeFields + */ public function excludeFields(array $excludeFields): self { $this->slackRecord->excludeFields($excludeFields); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 17d12b064..33ac13874 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -46,7 +46,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param string|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 - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ public function __construct( string $webhookUrl, @@ -87,8 +87,6 @@ public function getWebhookUrl(): string /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 7e8e0187a..4a1d7bf10 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -18,10 +18,15 @@ * * @author Pablo de Leon Belloc * @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 { + /** @var string */ private $connectionString; + /** @var float */ private $connectionTimeout; /** @var resource|null */ private $resource; @@ -29,14 +34,18 @@ class SocketHandler extends AbstractProcessingHandler private $timeout = 0.0; /** @var float */ private $writingTimeout = 10.0; + /** @var ?int */ private $lastSentBytes = null; /** @var int */ private $chunkSize = null; + /** @var bool */ private $persistent = false; - private $errno; - private $errstr; + /** @var ?int */ + private $errno = null; + /** @var ?string */ + private $errstr = null; /** @var ?float */ - private $lastWritingAt; + private $lastWritingAt = null; /** * @param string $connectionString Socket connection string @@ -53,7 +62,7 @@ public function __construct(string $connectionString, $level = Logger::DEBUG, bo /** * Connect (if necessary) and write to the socket * - * @param array $record + * {@inheritDoc} * * @throws \UnexpectedValueException * @throws \RuntimeException @@ -208,6 +217,8 @@ public function isConnected(): bool /** * Wrapper to allow mocking + * + * @return resource|bool */ protected function pfsockopen() { @@ -216,6 +227,8 @@ protected function pfsockopen() /** * Wrapper to allow mocking + * + * @return resource|bool */ protected function fsockopen() { @@ -226,6 +239,8 @@ protected function fsockopen() * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-timeout.php + * + * @return bool */ protected function streamSetTimeout() { @@ -239,6 +254,8 @@ protected function streamSetTimeout() * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-chunk-size.php + * + * @return int|bool */ protected function streamSetChunkSize() { @@ -247,29 +264,32 @@ protected function streamSetChunkSize() /** * Wrapper to allow mocking + * + * @return int|bool */ - protected function fwrite($data) + protected function fwrite(string $data) { return @fwrite($this->resource, $data); } /** * Wrapper to allow mocking + * + * @return mixed[]|bool */ protected function streamGetMetadata() { return stream_get_meta_data($this->resource); } - private function validateTimeout($value) + private function validateTimeout(float $value): void { - $ok = filter_var($value, FILTER_VALIDATE_FLOAT); - if ($ok === false || $value < 0) { + if ($value < 0) { throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); } } - private function connectIfNotConnected() + private function connectIfNotConnected(): void { if ($this->isConnected()) { return; @@ -277,6 +297,9 @@ private function connectIfNotConnected() $this->connect(); } + /** + * @phpstan-param FormattedRecord $record + */ protected function generateDataStream(array $record): string { return (string) $record['formatted']; diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index a98c87bf7..2d531458b 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -41,9 +41,7 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Log } /** - * Writes the record down to the log of the implementing handler. - * - * @param array $record + * {@inheritdoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 5a1266651..4ef049f30 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -20,6 +20,8 @@ * Can be used to store into php://stderr, remote and local files, etc. * * @author Jordi Boggiano + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class StreamHandler extends AbstractProcessingHandler { @@ -27,12 +29,16 @@ class StreamHandler extends AbstractProcessingHandler /** @var resource|null */ protected $stream; - protected $url; - /** @var string|null */ - private $errorMessage; + /** @var ?string */ + protected $url = null; + /** @var ?string */ + private $errorMessage = null; + /** @var ?int */ protected $filePermission; + /** @var bool */ protected $useLocking; - private $dirCreated; + /** @var true|null */ + private $dirCreated = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write @@ -132,13 +138,15 @@ protected function write(array $record): void * Write to stream * @param resource $stream * @param array $record + * + * @phpstan-param FormattedRecord $record */ protected function streamWrite($stream, array $record): void { fwrite($stream, (string) $record['formatted']); } - private function customErrorHandler($code, $msg): bool + private function customErrorHandler(int $code, string $msg): bool { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 2c5c5dac6..aa2181b25 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -21,14 +21,18 @@ * SwiftMailerHandler uses Swift_Mailer to send the emails * * @author Gyula Sallai + * + * @phpstan-import-type Record from \Monolog\Logger */ class SwiftMailerHandler extends MailHandler { + /** @var \Swift_Mailer */ protected $mailer; + /** @var Swift_Message|callable(string, Record[]): Swift_Message */ private $messageTemplate; /** - * @psalm-param Swift_Message|callable(string, array): Swift_Message $message + * @psalm-param Swift_Message|callable(string, Record[]): Swift_Message $message * * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced @@ -67,6 +71,8 @@ protected function getSubjectFormatter(?string $format): FormatterInterface * @param string $content formatted email body to be sent * @param array $records Log records that formed the content * @return Swift_Message + * + * @phpstan-param Record[] $records */ protected function buildMessage(string $content, array $records): Swift_Message { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 20594cedd..12636e533 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -28,7 +28,9 @@ */ class SyslogHandler extends AbstractSyslogHandler { + /** @var string */ protected $ident; + /** @var int */ protected $logopts; /** diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 228a705ab..30b5186bd 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -39,6 +39,11 @@ public function __construct(string $ip, int $port = 514) $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } + /** + * @param string $line + * @param string $header + * @return void + */ public function write($line, $header = "") { $this->send($this->assembleMessage($line, $header)); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 2bf3da699..d1821ca73 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -27,14 +27,18 @@ class SyslogUdpHandler extends AbstractSyslogHandler const RFC5424 = 1; const RFC5424e = 2; + /** @var array */ private $dateFormats = array( self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, self::RFC5424e => \DateTime::RFC3339_EXTENDED, ); + /** @var UdpSocket */ protected $socket; + /** @var string */ protected $ident; + /** @var self::RFC* */ protected $rfc; /** @@ -45,6 +49,8 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @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. + * + * @phpstan-param self::RFC* $rfc */ public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) { @@ -72,6 +78,10 @@ public function close(): void $this->socket->close(); } + /** + * @param string|string[] $message + * @return string[] + */ private function splitMessageIntoLines($message): array { if (is_array($message)) { diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 025c89e34..9ea79a97d 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -33,7 +33,7 @@ class TelegramBotHandler extends AbstractProcessingHandler private const BOT_API = 'https://api.telegram.org/bot'; /** - * @var array AVAILABLE_PARSE_MODES The available values of parseMode according to the Telegram api documentation + * The available values of parseMode according to the Telegram api documentation */ private const AVAILABLE_PARSE_MODES = [ 'HTML', @@ -59,19 +59,19 @@ class TelegramBotHandler extends AbstractProcessingHandler * 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|null + * @var ?string */ private $parseMode; /** * Disables link previews for links in the message. - * @var bool|null + * @var ?bool */ private $disableWebPagePreview; /** * Sends the message silently. Users will receive a notification with no sound. - * @var bool|null + * @var ?bool */ private $disableNotification; diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 9fa77b9fa..03b51cd66 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Used for testing purposes. @@ -64,24 +65,42 @@ * @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 Record[] */ protected $records = []; + /** @var array */ protected $recordsByLevel = []; + /** @var bool */ private $skipReset = false; + /** + * @return array + * + * @phpstan-return Record[] + */ public function getRecords() { return $this->records; } + /** + * @return void + */ public function clear() { $this->records = []; $this->recordsByLevel = []; } + /** + * @return void + */ public function reset() { if (!$this->skipReset) { @@ -89,6 +108,9 @@ public function reset() } } + /** + * @return void + */ public function setSkipReset(bool $skipReset) { $this->skipReset = $skipReset; @@ -105,6 +127,9 @@ public function hasRecords($level): bool /** * @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 $record + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecord($record, $level): bool { @@ -136,6 +161,8 @@ public function hasRecordThatContains(string $message, $level): bool /** * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatMatches(string $regex, $level): bool { @@ -145,10 +172,11 @@ public function hasRecordThatMatches(string $regex, $level): bool } /** - * @psalm-param callable(array, 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) { @@ -176,6 +204,11 @@ protected function write(array $record): void $this->records[] = $record; } + /** + * @param string $method + * @param mixed[] $args + * @return bool + */ public function __call($method, $args) { if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 34fe80fae..dc99f8f09 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -20,13 +20,15 @@ * * @author Christian Bergau * @author Jason Davis + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class ZendMonitorHandler extends AbstractProcessingHandler { /** * Monolog level / ZendMonitor Custom Event priority map * - * @var array + * @var array */ protected $levelMap = []; @@ -75,6 +77,8 @@ protected function write(array $record): void * @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 { @@ -89,6 +93,9 @@ public function getDefaultFormatter(): FormatterInterface return new NormalizerFormatter(); } + /** + * @return array + */ public function getLevelMap(): array { return $this->levelMap; diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 927c31276..0b7cb4483 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -15,6 +15,7 @@ use Monolog\Handler\HandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; +use Psr\Log\LogLevel; use Throwable; /** @@ -24,6 +25,10 @@ * and uses them to store records that are added to it. * * @author Jordi Boggiano + * + * @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 { @@ -91,6 +96,8 @@ class Logger implements LoggerInterface, ResettableInterface * This is a static variable and not a constant to serve as an extension point for custom levels * * @var array $levels Logging levels with the levels as key + * + * @phpstan-var array $levels Logging levels with the levels as key */ protected static $levels = [ self::DEBUG => 'DEBUG', @@ -276,6 +283,8 @@ public function useMicrosecondTimestamps(bool $micro): void * @param string $message The log message * @param mixed[] $context The log context * @return bool Whether the record has been processed + * + * @phpstan-param Level $level */ public function addRecord(int $level, string $message, array $context = []): bool { @@ -383,6 +392,9 @@ public static function getLevels(): array * Gets the name of the logging level. * * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level $level + * @phpstan-return LevelName */ public static function getLevelName(int $level): string { @@ -398,11 +410,15 @@ public static function getLevelName(int $level): string * * @param string|int $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-return Level */ public static function toMonologLevel($level): int { if (is_string($level)) { if (is_numeric($level)) { + /** @phpstan-ignore-next-line */ return intval($level); } @@ -413,18 +429,21 @@ public static function toMonologLevel($level): int return constant(__CLASS__ . '::' . $upper); } - throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } if (!is_int($level)) { - throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } + /** @phpstan-ignore-next-line */ return $level; } /** * Checks whether the Logger has a handler that listens on the given level + * + * @phpstan-param Level $level */ public function isHandling(int $level): bool { @@ -463,9 +482,11 @@ public function getExceptionHandler(): ?callable * * This method allows for compatibility with common interfaces. * - * @param mixed $level The log level - * @param string $message The log message - * @param mixed[] $context The log context + * @param int|string $level The log level + * @param string $message The log message + * @param mixed[] $context The log context + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function log($level, $message, array $context = []): void { @@ -599,6 +620,9 @@ public function getTimezone(): DateTimeZone /** * 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, array $record): void { diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 6abd3d8cd..337ef2268 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -21,8 +21,10 @@ */ class GitProcessor implements ProcessorInterface { + /** @var int */ private $level; - private static $cache; + /** @var array{branch: string, commit: string}|array|null */ + private static $cache = null; /** * @param string|int $level The minimum logging level at which this Processor will be triggered @@ -32,6 +34,9 @@ public function __construct($level = Logger::DEBUG) $this->level = Logger::toMonologLevel($level); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -44,6 +49,9 @@ public function __invoke(array $record): array return $record; } + /** + * @return array{branch: string, commit: string}|array + */ private static function getGitInfo(): array { if (self::$cache) { diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index 7c23db8b1..91fda7d6d 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -16,6 +16,7 @@ */ class HostnameProcessor implements ProcessorInterface { + /** @var string */ private static $host; public function __construct() @@ -23,6 +24,9 @@ public function __construct() self::$host = (string) gethostname(); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['hostname'] = self::$host; diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index c0cc014e4..5a3e93c9a 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -26,19 +26,21 @@ */ class IntrospectionProcessor implements ProcessorInterface { + /** @var int */ private $level; - + /** @var string[] */ private $skipClassesPartials; - + /** @var int */ private $skipStackFramesCount; - + /** @var string[] */ private $skipFunctions = [ 'call_user_func', 'call_user_func_array', ]; /** - * @param string|int $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 + * @param string[] $skipClassesPartials */ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { @@ -47,6 +49,9 @@ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = $this->skipStackFramesCount = $skipStackFramesCount; } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -97,7 +102,10 @@ public function __invoke(array $record): array return $record; } - private function isTraceClassOrSkippedFunction(array $trace, int $index) + /** + * @param array[] $trace + */ + private function isTraceClassOrSkippedFunction(array $trace, int $index): bool { if (!isset($trace[$index])) { return false; diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index a1eef61ab..37c756fcb 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -19,6 +19,9 @@ */ class MemoryPeakUsageProcessor extends MemoryProcessor { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $usage = memory_get_peak_usage($this->realUsage); diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index 653c76d10..e141921e9 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -19,6 +19,9 @@ */ class MemoryUsageProcessor extends MemoryProcessor { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $usage = memory_get_usage($this->realUsage); diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index d50f71386..9aeb3e3a8 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -20,8 +20,10 @@ */ class MercurialProcessor implements ProcessorInterface { + /** @var int */ private $level; - private static $cache; + /** @var array{branch: string, revision: string}|array|null */ + private static $cache = null; /** * @param string|int $level The minimum logging level at which this Processor will be triggered @@ -31,6 +33,9 @@ public function __construct($level = Logger::DEBUG) $this->level = Logger::toMonologLevel($level); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -43,6 +48,9 @@ public function __invoke(array $record): array return $record; } + /** + * @return array{branch: string, revision: string}|array + */ private static function getMercurialInfo(): array { if (self::$cache) { diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 7851fff6d..3b939a951 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -18,6 +18,9 @@ */ class ProcessIdProcessor implements ProcessorInterface { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['process_id'] = getmypid(); diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index 9e2ded19b..5defb7eb4 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -15,11 +15,16 @@ * An optional interface to allow labelling Monolog processors. * * @author Nicolas Grekas + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessorInterface { /** * @return array The processed record + * + * @phpstan-param Record $record + * @phpstan-return Record */ public function __invoke(array $record); } diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 7b80e57d7..2c2a00e75 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -41,8 +41,7 @@ public function __construct(?string $dateFormat = null, bool $removeUsedContextF } /** - * @param array $record - * @return array + * {@inheritDoc} */ public function __invoke(array $record): array { diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index 199760ad8..80f18747a 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -18,13 +18,20 @@ */ class TagProcessor implements ProcessorInterface { + /** @var string[] */ private $tags; + /** + * @param string[] $tags + */ public function __construct(array $tags = []) { $this->setTags($tags); } + /** + * @param string[] $tags + */ public function addTags(array $tags = []): self { $this->tags = array_merge($this->tags, $tags); @@ -32,6 +39,9 @@ public function addTags(array $tags = []): self return $this; } + /** + * @param string[] $tags + */ public function setTags(array $tags = []): self { $this->tags = $tags; @@ -39,6 +49,9 @@ public function setTags(array $tags = []): self return $this; } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['tags'] = $this->tags; diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 0c97ab6cd..a27b74dbf 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -20,6 +20,7 @@ */ class UidProcessor implements ProcessorInterface, ResettableInterface { + /** @var string */ private $uid; public function __construct(int $length = 7) @@ -31,6 +32,9 @@ public function __construct(int $length = 7) $this->uid = $this->generateUid($length); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['uid'] = $this->uid; diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 6c32b2d11..155e81575 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -19,7 +19,7 @@ class WebProcessor implements ProcessorInterface { /** - * @var array|\ArrayAccess + * @var array|\ArrayAccess */ protected $serverData; @@ -28,7 +28,7 @@ class WebProcessor implements ProcessorInterface * * Array is structured as [key in record.extra => key in $serverData] * - * @var array + * @var array */ protected $extraFields = [ 'url' => 'REQUEST_URI', @@ -39,8 +39,8 @@ class WebProcessor implements ProcessorInterface ]; /** - * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer + * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data + * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer */ public function __construct($serverData = null, array $extraFields = null) { @@ -69,6 +69,9 @@ public function __construct($serverData = null, array $extraFields = null) } } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // skip processing if for some reason request data @@ -89,6 +92,10 @@ public function addExtraField(string $extraName, string $serverName): self return $this; } + /** + * @param mixed[] $extra + * @return mixed[] + */ private function appendExtraFields(array $extra): array { foreach ($this->extraFields as $extraName => $serverName) { diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index 78fb97e58..ae94ae6cc 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -51,6 +51,7 @@ 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) { @@ -122,7 +123,7 @@ public static function getInstance($name): Logger * Gets Logger instance from the registry via static method call * * @param string $name Name of the requested Logger instance - * @param array $arguments Arguments passed to static method call + * @param mixed[] $arguments Arguments passed to static method call * @throws \InvalidArgumentException If named Logger instance is not in the registry * @return Logger Requested instance of Logger */ diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 517ab5496..62f45e394 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -22,10 +22,14 @@ */ class SignalHandler { + /** @var LoggerInterface */ private $logger; + /** @var array SIG_DFL, SIG_IGN or previous callable */ private $previousSignalHandler = []; + /** @var array */ private $signalLevelMap = []; + /** @var array */ private $signalRestartSyscalls = []; public function __construct(LoggerInterface $logger) @@ -33,12 +37,21 @@ public function __construct(LoggerInterface $logger) $this->logger = $logger; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self + /** + * @param int|string $level Level or level name + * @param bool $callPrevious + * @param bool $restartSyscalls + * @param bool|null $async + * @return $this + */ + 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); + if ($callPrevious) { $handler = pcntl_signal_get_handler($signo); $this->previousSignalHandler[$signo] = $handler; @@ -57,7 +70,10 @@ public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool return $this; } - public function handleSignal($signo, array $siginfo = null): void + /** + * @param mixed $siginfo + */ + public function handleSignal(int $signo, $siginfo = null): void { static $signals = []; @@ -80,7 +96,7 @@ public function handleSignal($signo, array $siginfo = null): void return; } - if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if ($this->previousSignalHandler[$signo] === SIG_DFL) { if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill') ) { diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index b996bbc9b..1824fde45 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -17,15 +17,23 @@ /** * Lets you easily generate log records and a dummy formatter for testing purposes - * * + * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class TestCase extends \PHPUnit\Framework\TestCase { /** + * @param mixed[] $context + * * @return array Record + * + * @phpstan-param Level $level + * @phpstan-return Record */ - protected function getRecord($level = Logger::WARNING, $message = 'test', array $context = []): array + protected function getRecord(int $level = Logger::WARNING, string $message = 'test', array $context = []): array { return [ 'message' => (string) $message, @@ -38,6 +46,9 @@ protected function getRecord($level = Logger::WARNING, $message = 'test', array ]; } + /** + * @phpstan-return Record[] + */ protected function getMultipleRecords(): array { return [ diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 69cb3e505..05123f2af 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -54,8 +54,8 @@ public function testHandleError() public function fatalHandlerProvider() { return [ - [null, 10, str_repeat(' ', 1024 * 10), null], - [E_ALL, 15, str_repeat(' ', 1024 * 15), E_ALL], + [null, 10, str_repeat(' ', 1024 * 10), LogLevel::ALERT], + [LogLevel::DEBUG, 15, str_repeat(' ', 1024 * 15), LogLevel::DEBUG], ]; } From 13d40f953f9266bfff881302406132cfd11e22a3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 28 May 2021 21:59:26 +0200 Subject: [PATCH 337/498] More type fixes towards level 7 --- src/Monolog/Handler/AbstractHandler.php | 6 +++++- src/Monolog/Handler/AbstractSyslogHandler.php | 2 -- src/Monolog/Handler/AmqpHandler.php | 2 -- src/Monolog/Handler/BufferHandler.php | 2 -- src/Monolog/Handler/ChromePHPHandler.php | 4 ---- src/Monolog/Handler/DynamoDbHandler.php | 3 --- src/Monolog/Handler/ElasticaHandler.php | 2 -- src/Monolog/Handler/ElasticsearchHandler.php | 2 -- src/Monolog/Handler/ErrorLogHandler.php | 2 -- src/Monolog/Handler/GelfHandler.php | 2 -- src/Monolog/Handler/IFTTTHandler.php | 2 -- src/Monolog/Handler/LogglyHandler.php | 2 -- src/Monolog/Handler/MandrillHandler.php | 2 -- src/Monolog/Handler/MongoDBHandler.php | 2 -- src/Monolog/Handler/NativeMailerHandler.php | 2 -- src/Monolog/Handler/NewRelicHandler.php | 2 -- src/Monolog/Handler/NullHandler.php | 6 ++++++ src/Monolog/Handler/OverflowHandler.php | 2 -- src/Monolog/Handler/PHPConsoleHandler.php | 2 -- src/Monolog/Handler/ProcessHandler.php | 2 -- src/Monolog/Handler/PsrHandler.php | 2 -- src/Monolog/Handler/RedisHandler.php | 2 -- src/Monolog/Handler/RedisPubSubHandler.php | 2 -- src/Monolog/Handler/RollbarHandler.php | 2 -- src/Monolog/Handler/SendGridHandler.php | 2 -- src/Monolog/Handler/SlackHandler.php | 2 -- src/Monolog/Handler/SlackWebhookHandler.php | 2 -- src/Monolog/Handler/SocketHandler.php | 4 +--- src/Monolog/Handler/StreamHandler.php | 2 -- src/Monolog/Handler/SwiftMailerHandler.php | 2 -- src/Monolog/Handler/TelegramBotHandler.php | 1 - src/Monolog/Handler/ZendMonitorHandler.php | 2 -- src/Monolog/Processor/MercurialProcessor.php | 10 ++++++++-- src/Monolog/SignalHandler.php | 7 ++++++- 34 files changed, 26 insertions(+), 67 deletions(-) diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 6d0fdae2a..1f4679513 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\ResettableInterface; +use Psr\Log\LogLevel; /** * Base Handler class providing basic level/bubble support @@ -20,6 +21,7 @@ * @author Jordi Boggiano * * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ abstract class AbstractHandler extends Handler implements ResettableInterface { @@ -34,6 +36,8 @@ abstract class AbstractHandler extends Handler implements ResettableInterface /** * @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 Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG, bool $bubble = true) { @@ -52,7 +56,7 @@ public function isHandling(array $record): bool /** * Sets minimum logging level at which this handler will be triggered. * - * @param int|string $level Level or level name + * @param Level|LevelName|LogLevel::* $level Level or level name * @return self */ public function setLevel($level): self diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 55a3384d7..673561abf 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -61,8 +61,6 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant - * @param string|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($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index d91f1b68a..ea7f5d3f6 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -36,8 +36,6 @@ class AmqpHandler extends AbstractProcessingHandler /** * @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 - * @param string|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($exchange, ?string $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 874fd0d9f..e4b46a97f 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -45,8 +45,6 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa /** * @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 string|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 * @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, $level = Logger::DEBUG, bool $bubble = true, bool $flushOnOverflow = false) diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index d9b587674..27214665e 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -64,10 +64,6 @@ class ChromePHPHandler extends AbstractProcessingHandler /** @var bool */ protected static $sendHeaders = true; - /** - * @param string|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($level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 9948ef190..9973fc3bb 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -48,9 +48,6 @@ class DynamoDbHandler extends AbstractProcessingHandler */ protected $marshaler; - /** - * @param int|string $level - */ public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true) { /** @phpstan-ignore-next-line */ diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 3c6f8795b..26f2187c4 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -49,8 +49,6 @@ class ElasticaHandler extends AbstractProcessingHandler /** * @param Client $client Elastica Client object * @param mixed[] $options Handler configuration - * @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 */ public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index fddcc5be3..44787dbe1 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -56,8 +56,6 @@ class ElasticsearchHandler extends AbstractProcessingHandler /** * @param Client $client Elasticsearch Client object * @param mixed[] $options Handler configuration - * @param string|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(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index fb0ebf2f4..5b75b0002 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -32,8 +32,6 @@ class ErrorLogHandler extends AbstractProcessingHandler /** * @param int $messageType Says where the error should go. - * @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 * @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, $level = Logger::DEBUG, bool $bubble = true, bool $expandNewlines = false) diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index d6965fa7d..5a4c8ac92 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -31,8 +31,6 @@ class GelfHandler extends AbstractProcessingHandler /** * @param PublisherInterface $publisher a publisher object - * @param string|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(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index c8ed6ff7e..502f8c3cc 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -35,8 +35,6 @@ class IFTTTHandler extends AbstractProcessingHandler /** * @param string $eventName The name of the IFTTT Maker event that should be triggered * @param string $secretKey A valid IFTTT secret key - * @param string|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(string $eventName, string $secretKey, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index cd110bf73..27ab9dc0f 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -45,8 +45,6 @@ class LogglyHandler extends AbstractProcessingHandler /** * @param string $token API token supplied by Loggly - * @param string|int $level The minimum logging level to trigger this handler - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. * * @throws MissingExtensionException If the curl extension is missing */ diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 95c612a8d..f49dc1c4c 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -32,8 +32,6 @@ class MandrillHandler extends MailHandler * * @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 - * @param string|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(string $apiKey, $message, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 477bcd647..306309119 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -46,8 +46,6 @@ class MongoDBHandler extends AbstractProcessingHandler * @param Client|Manager $mongodb MongoDB library or driver client * @param string $database Database name * @param string $collection Collection name - * @param string|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($mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index c2ef64e60..6f2f965b9 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -68,8 +68,6 @@ class NativeMailerHandler extends MailHandler * @param string|string[] $to The receiver of the mail * @param string $subject The subject of the mail * @param string $from The sender of the mail - * @param string|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 * @param int $maxColumnWidth The maximum column width that the message lines will have */ public function __construct($to, string $subject, string $from, $level = Logger::ERROR, bool $bubble = true, int $maxColumnWidth = 70) diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 25df54270..114d749eb 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -52,8 +52,6 @@ class NewRelicHandler extends AbstractProcessingHandler /** * {@inheritDoc} * - * @param string|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. * @param string|null $appName * @param bool $explodeArrays * @param string|null $transactionName diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 1f0078acb..482e7f682 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Blackhole @@ -20,6 +21,9 @@ * to put on top of an existing stack to override it temporarily. * * @author Jordi Boggiano + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class NullHandler extends Handler { @@ -30,6 +34,8 @@ class NullHandler extends Handler /** * @param string|int $level The minimum logging level at which this handler will be triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG) { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 04760749f..77bd618a5 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -61,8 +61,6 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter /** * @param HandlerInterface $handler * @param int[] $thresholdMap Dictionary of logger level => threshold - * @param int|string $level The minimum logging level at which this handler will be triggered - * @param bool $bubble */ public function __construct( HandlerInterface $handler, diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index d596c0461..16edf1010 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -72,8 +72,6 @@ class PHPConsoleHandler extends AbstractProcessingHandler /** * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param string|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. * @throws \RuntimeException */ public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 97549949d..d057efae8 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -60,8 +60,6 @@ class ProcessHandler extends AbstractProcessingHandler /** * @param string $command Command for the process to start. Absolute paths are recommended, * especially if you do not use the $cwd parameter. - * @param string|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. * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in. * @throws \InvalidArgumentException */ diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index cba96a556..36e19cccf 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -40,8 +40,6 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied - * @param string|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(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 02ee1c14e..938eee6b2 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -40,8 +40,6 @@ class RedisHandler extends AbstractProcessingHandler /** * @param \Predis\Client|\Redis $redis The redis instance * @param string $key The key name to push records to - * @param string|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 * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true, int $capSize = 0) diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index f6db48032..45218b305 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -36,8 +36,6 @@ class RedisPubSubHandler extends AbstractProcessingHandler /** * @param \Predis\Client|\Redis $redis The redis instance * @param string $key The channel key to publish records to - * @param string|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($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index fdc4abb97..2d94da422 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -62,8 +62,6 @@ class RollbarHandler extends AbstractProcessingHandler /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token - * @param string|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(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 3dcf91550..02ccc4fec 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -56,8 +56,6 @@ class SendGridHandler extends MailHandler * @param string $from The sender of the email * @param string|string[] $to The recipients of the email * @param string $subject The subject of the mail - * @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 */ public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 67e97474c..13ad8b714 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -44,8 +44,6 @@ class SlackHandler extends SocketHandler * @param string|null $username Name of a bot * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) * @param string|null $iconEmoji The emoji name to use (or null) - * @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 * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 33ac13874..1c934774c 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -44,8 +44,6 @@ class SlackWebhookHandler extends AbstractProcessingHandler * @param string|null $iconEmoji The emoji name to use (or null) * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param string|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 * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ public function __construct( diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 4a1d7bf10..e35cac92d 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -48,9 +48,7 @@ class SocketHandler extends AbstractProcessingHandler private $lastWritingAt = null; /** - * @param string $connectionString Socket connection string - * @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 + * @param string $connectionString Socket connection string */ public function __construct(string $connectionString, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 4ef049f30..51eb02688 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -42,8 +42,6 @@ class StreamHandler extends AbstractProcessingHandler /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write - * @param string|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 * @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 * diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index aa2181b25..e0e182dbb 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -36,8 +36,6 @@ class SwiftMailerHandler extends MailHandler * * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced - * @param string|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(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 9ea79a97d..78774ce8a 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -78,7 +78,6 @@ class TelegramBotHandler extends AbstractProcessingHandler /** * @param string $apiKey Telegram bot access token provided by BotFather * @param string $channel Telegram channel name - * @inheritDoc */ public function __construct( string $apiKey, diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index dc99f8f09..7c9577cac 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -33,8 +33,6 @@ class ZendMonitorHandler extends AbstractProcessingHandler protected $levelMap = []; /** - * @param string|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. * @throws MissingExtensionException */ public function __construct($level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 9aeb3e3a8..d4a628f55 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -12,21 +12,27 @@ namespace Monolog\Processor; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Injects Hg branch and Hg revision number in all records * * @author Jonathan A. Schweder + * + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class MercurialProcessor implements ProcessorInterface { - /** @var int */ + /** @var Level */ private $level; /** @var array{branch: string, revision: string}|array|null */ private static $cache = null; /** - * @param string|int $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 Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG) { diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 62f45e394..b1fafc019 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -19,13 +19,16 @@ * Monolog POSIX signal handler * * @author Robert Gust-Bardon + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class SignalHandler { /** @var LoggerInterface */ private $logger; - /** @var array SIG_DFL, SIG_IGN or previous callable */ + /** @var array SIG_DFL, SIG_IGN or previous callable */ private $previousSignalHandler = []; /** @var array */ private $signalLevelMap = []; @@ -43,6 +46,8 @@ public function __construct(LoggerInterface $logger) * @param bool $restartSyscalls * @param bool|null $async * @return $this + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self { From 4ef5da80ad69865199fbc95e8498e3e38d522f04 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 28 May 2021 22:07:02 +0200 Subject: [PATCH 338/498] Fix CS --- src/Monolog/Formatter/ElasticaFormatter.php | 2 +- src/Monolog/Formatter/MongoDBFormatter.php | 4 ++-- src/Monolog/Formatter/NormalizerFormatter.php | 2 +- src/Monolog/Formatter/ScalarFormatter.php | 2 +- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- src/Monolog/Handler/DynamoDbHandler.php | 2 +- src/Monolog/Handler/ElasticaHandler.php | 4 ++-- src/Monolog/Handler/ElasticsearchHandler.php | 4 ++-- src/Monolog/Handler/ErrorLogHandler.php | 4 ++-- src/Monolog/Handler/FirePHPHandler.php | 5 +++-- src/Monolog/Handler/IFTTTHandler.php | 4 ++-- src/Monolog/Handler/LogglyHandler.php | 2 +- src/Monolog/Handler/NativeMailerHandler.php | 6 +++--- src/Monolog/Handler/PHPConsoleHandler.php | 1 + src/Monolog/Handler/ProcessableHandlerInterface.php | 2 +- src/Monolog/Handler/RedisPubSubHandler.php | 4 ++-- src/Monolog/Handler/Slack/SlackRecord.php | 3 +++ src/Monolog/Handler/SyslogUdpHandler.php | 2 +- src/Monolog/Handler/TelegramBotHandler.php | 5 ++++- src/Monolog/Handler/TestHandler.php | 6 +++--- src/Monolog/Processor/WebProcessor.php | 2 +- src/Monolog/SignalHandler.php | 8 ++++---- tests/Monolog/Formatter/ElasticaFormatterTest.php | 2 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 9 ++++----- tests/Monolog/Handler/MongoDBHandlerTest.php | 1 - tests/Monolog/Handler/TelegramBotHandlerTest.php | 3 +-- 26 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 4dcebda7a..9504d89c8 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -77,7 +77,7 @@ protected function getDocument(array $record): Document { $document = new Document(); $document->setData($record); - if(method_exists($document, 'setType')) { + if (method_exists($document, 'setType')) { $document->setType($this->type); } $document->setIndex($this->index); diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 0c1197ed3..adf2ce1a5 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -66,7 +66,7 @@ public function formatBatch(array $records): array } /** - * @param mixed[] $array + * @param mixed[] $array * @return mixed[]|string Array except when max nesting level is reached then a string "[...]" */ protected function formatArray(array $array, int $nestingLevel = 0) @@ -91,7 +91,7 @@ protected function formatArray(array $array, int $nestingLevel = 0) } /** - * @param mixed $value + * @param mixed $value * @return mixed[]|string */ protected function formatObject($value, int $nestingLevel) diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 29288543f..9363b6c47 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -122,7 +122,7 @@ public function setJsonPrettyPrint(bool $enable): self } /** - * @param mixed $data + * @param mixed $data * @return scalar|array */ protected function normalize($data, int $depth = 0) diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index c8889b5b1..f209ae5d5 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -34,7 +34,7 @@ public function format(array $record): array } /** - * @param mixed $value + * @param mixed $value * @return string|int|bool|null */ protected function normalizeValue($value) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 6245def42..4177046fb 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -213,7 +213,7 @@ private static function handleCustomStyles(string $style, string $string): strin } /** - * @param mixed[] $dict + * @param mixed[] $dict * @return mixed[] */ private static function dump(string $title, array $dict): array diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 9973fc3bb..ec3bf2d16 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -84,7 +84,7 @@ protected function write(array $record): void } /** - * @param mixed[] $record + * @param mixed[] $record * @return mixed[] */ protected function filterEmptyFields(array $record): array diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 26f2187c4..170bccf69 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -47,8 +47,8 @@ class ElasticaHandler extends AbstractProcessingHandler protected $options = []; /** - * @param Client $client Elastica Client object - * @param mixed[] $options Handler configuration + * @param Client $client Elastica Client object + * @param mixed[] $options Handler configuration */ public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 44787dbe1..0995100c5 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -54,8 +54,8 @@ class ElasticsearchHandler extends AbstractProcessingHandler protected $options = []; /** - * @param Client $client Elasticsearch Client object - * @param mixed[] $options Handler configuration + * @param Client $client Elasticsearch Client object + * @param mixed[] $options Handler configuration */ public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 5b75b0002..2b8d1a88c 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -31,8 +31,8 @@ class ErrorLogHandler extends AbstractProcessingHandler 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 + * @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, $level = Logger::DEBUG, bool $bubble = true, bool $expandNewlines = false) { diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index f57677c86..e37180ca5 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -63,8 +63,9 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Base header creation function used by init headers & record headers * - * @param array $meta Wildfire Plugin, Protocol & Structure Indexes - * @param string $message Log message + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * * @return array Complete header string ready for the client as key and message as value */ protected function createHeader(array $meta, string $message): array diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 502f8c3cc..18ed8cee3 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -33,8 +33,8 @@ class IFTTTHandler extends AbstractProcessingHandler private $secretKey; /** - * @param string $eventName The name of the IFTTT Maker event that should be triggered - * @param string $secretKey A valid IFTTT secret key + * @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, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 27ab9dc0f..6d13db375 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -44,7 +44,7 @@ class LogglyHandler extends AbstractProcessingHandler protected $tag = []; /** - * @param string $token API token supplied by Loggly + * @param string $token API token supplied by Loggly * * @throws MissingExtensionException If the curl extension is missing */ diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 6f2f965b9..0989184af 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -66,9 +66,9 @@ class NativeMailerHandler extends MailHandler /** * @param string|string[] $to The receiver of the mail - * @param string $subject The subject of the mail - * @param string $from The sender of the mail - * @param int $maxColumnWidth The maximum column width that the message lines will have + * @param string $subject The subject of the mail + * @param string $from The sender of the mail + * @param int $maxColumnWidth The maximum column width that the message lines will have */ public function __construct($to, string $subject, string $from, $level = Logger::ERROR, bool $bubble = true, int $maxColumnWidth = 70) { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 16edf1010..6e209b190 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -86,6 +86,7 @@ public function __construct(array $options = [], ?Connector $connector = null, $ /** * @param array $options + * * @return array */ private function initOptions(array $options): array diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index a74876170..3adec7a4d 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -37,7 +37,7 @@ public function pushProcessor(callable $callback): HandlerInterface; * * @psalm-return ProcessorInterface|callable(Record): Record $callback * - * @throws \LogicException In case the processor stack is empty + * @throws \LogicException In case the processor stack is empty * @return callable|ProcessorInterface */ public function popProcessor(): callable; diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 45218b305..f9fede8ee 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -34,8 +34,8 @@ class RedisPubSubHandler extends AbstractProcessingHandler private $channelKey; /** - * @param \Predis\Client|\Redis $redis The redis instance - * @param string $key The channel key to publish records to + * @param \Predis\Client|\Redis $redis The redis instance + * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 53f2e760d..e2c849c1f 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -316,6 +316,7 @@ public function setFormatter(?FormatterInterface $formatter = null): self * Generates attachment field * * @param string|mixed[] $value + * * @return array{title: string, value: string, short: false} */ private function generateAttachmentField(string $title, $value): array @@ -335,6 +336,7 @@ private function generateAttachmentField(string $title, $value): array * Generates a collection of attachment fields from array * * @param mixed[] $data + * * @return array */ private function generateAttachmentFields(array $data): array @@ -351,6 +353,7 @@ private function generateAttachmentFields(array $data): array * Get a copy of record with fields excluded according to $this->excludeFields * * @phpstan-param FormattedRecord $record + * * @return mixed[] */ private function removeExcludedFields(array $record): array diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index d1821ca73..e6b7f77b5 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -79,7 +79,7 @@ public function close(): void } /** - * @param string|string[] $message + * @param string|string[] $message * @return string[] */ private function splitMessageIntoLines($message): array diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 78774ce8a..51fb73966 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -38,7 +38,7 @@ class TelegramBotHandler extends AbstractProcessingHandler private const AVAILABLE_PARSE_MODES = [ 'HTML', 'MarkdownV2', - 'Markdown' // legacy mode without underline and strikethrough, use MarkdownV2 instead + 'Markdown', // legacy mode without underline and strikethrough, use MarkdownV2 instead ]; /** @@ -104,18 +104,21 @@ public function setParseMode(string $parseMode = null): self } $this->parseMode = $parseMode; + return $this; } public function disableWebPagePreview(bool $disableWebPagePreview = null): self { $this->disableWebPagePreview = $disableWebPagePreview; + return $this; } public function disableNotification(bool $disableNotification = null): self { $this->disableNotification = $disableNotification; + return $this; } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 03b51cd66..e2e3905f4 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -172,7 +172,7 @@ public function hasRecordThatMatches(string $regex, $level): bool } /** - * @param string|int $level Logging level value or name + * @param string|int $level Logging level value or name * @return bool * * @psalm-param callable(Record, int): mixed $predicate @@ -205,8 +205,8 @@ protected function write(array $record): void } /** - * @param string $method - * @param mixed[] $args + * @param string $method + * @param mixed[] $args * @return bool */ public function __call($method, $args) diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 155e81575..64d251d70 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -93,7 +93,7 @@ public function addExtraField(string $extraName, string $serverName): self } /** - * @param mixed[] $extra + * @param mixed[] $extra * @return mixed[] */ private function appendExtraFields(array $extra): array diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index b1fafc019..d730eea3a 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -41,10 +41,10 @@ public function __construct(LoggerInterface $logger) } /** - * @param int|string $level Level or level name - * @param bool $callPrevious - * @param bool $restartSyscalls - * @param bool|null $async + * @param int|string $level Level or level name + * @param bool $callPrevious + * @param bool $restartSyscalls + * @param bool|null $async * @return $this * * @phpstan-param Level|LevelName|LogLevel::* $level diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index d42ca2a55..dc280fea1 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -56,7 +56,7 @@ public function testFormat() // Document parameters $this->assertEquals('my_index', $doc->getIndex()); - if(method_exists($doc, 'getType')) { + if (method_exists($doc, 'getType')) { $this->assertEquals('doc_type', $doc->getType()); } diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index b08bce2ed..7fb9808e9 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -263,7 +263,6 @@ public function testHandleIntegrationNewESVersion() $client->request("/{$this->options['index']}", Request::DELETE); } - /** * Return last created document id from ES response * @param Response $response Elastica Response object @@ -279,15 +278,15 @@ protected function getCreatedDocId(Response $response) /** * Retrieve document by id from Elasticsearch - * @param Client $client Elastica client - * @param string $index + * @param Client $client Elastica client + * @param string $index * @param ?string $type - * @param string $documentId + * @param string $documentId * @return array */ protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) { - if($type === null) { + if ($type === null) { $path = "/{$index}/_doc/{$documentId}"; } else { $path = "/{$index}/{$type}/{$documentId}"; diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index 0a9a0bea7..82be0d6f4 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -13,7 +13,6 @@ use MongoDB\Driver\Manager; use Monolog\Test\TestCase; -use Monolog\Formatter\NormalizerFormatter; class MongoDBHandlerTest extends TestCase { diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 55a96b837..6cb3c7d96 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -41,8 +41,7 @@ private function createHandler( string $parseMode = 'Markdown', bool $disableWebPagePreview = false, bool $disableNotification = true - ): void - { + ): void { $constructorArgs = [$apiKey, $channel, Logger::DEBUG, true, $parseMode, $disableWebPagePreview, $disableNotification]; $this->handler = $this->getMockBuilder(TelegramBotHandler::class) From 8b5278d8e181c2839f99e3eca48da9c2bf05e91e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 4 Jul 2021 14:03:55 +0200 Subject: [PATCH 339/498] Bump phpstan to level 8 --- phpstan.neon.dist | 13 ++++++- src/Monolog/Formatter/ElasticaFormatter.php | 2 + .../Formatter/GelfMessageFormatter.php | 39 +++++++++++-------- src/Monolog/Formatter/LineFormatter.php | 3 ++ src/Monolog/Formatter/LogstashFormatter.php | 2 +- src/Monolog/Formatter/MongoDBFormatter.php | 12 ++++-- src/Monolog/Formatter/NormalizerFormatter.php | 4 +- src/Monolog/Formatter/ScalarFormatter.php | 11 +++--- src/Monolog/Formatter/WildfireFormatter.php | 3 +- .../Handler/AbstractProcessingHandler.php | 2 + src/Monolog/Handler/AmqpHandler.php | 1 + src/Monolog/Handler/BrowserConsoleHandler.php | 8 +++- src/Monolog/Handler/BufferHandler.php | 1 + src/Monolog/Handler/ChromePHPHandler.php | 6 ++- src/Monolog/Handler/CubeHandler.php | 17 +++++--- src/Monolog/Handler/DeduplicationHandler.php | 7 +++- src/Monolog/Handler/ErrorLogHandler.php | 3 ++ src/Monolog/Handler/FallbackGroupHandler.php | 11 ++++++ src/Monolog/Handler/FilterHandler.php | 3 ++ .../ChannelLevelActivationStrategy.php | 7 +++- .../ErrorLevelActivationStrategy.php | 8 +++- src/Monolog/Handler/FingersCrossedHandler.php | 7 +++- src/Monolog/Handler/FirePHPHandler.php | 6 +++ src/Monolog/Handler/FleepHookHandler.php | 2 - src/Monolog/Handler/FlowdockHandler.php | 3 -- src/Monolog/Handler/GelfHandler.php | 4 +- src/Monolog/Handler/GroupHandler.php | 12 ++++-- src/Monolog/Handler/InsightOpsHandler.php | 2 - src/Monolog/Handler/LogEntriesHandler.php | 2 - src/Monolog/Handler/LogmaticHandler.php | 2 - src/Monolog/Handler/MailHandler.php | 6 ++- src/Monolog/Handler/ProcessHandler.php | 2 +- src/Monolog/Handler/PushoverHandler.php | 17 +++++--- src/Monolog/Handler/RollbarHandler.php | 1 + src/Monolog/Handler/RotatingFileHandler.php | 13 ++++--- src/Monolog/Handler/SamplingHandler.php | 5 ++- src/Monolog/Handler/Slack/SlackRecord.php | 10 ++++- src/Monolog/Handler/SocketHandler.php | 24 ++++++++++-- src/Monolog/Handler/StreamHandler.php | 31 +++++++++------ src/Monolog/Handler/SyslogHandler.php | 2 - src/Monolog/Handler/SyslogUdpHandler.php | 8 +++- src/Monolog/Handler/TelegramBotHandler.php | 7 ++++ src/Monolog/Handler/TestHandler.php | 9 ++++- .../Handler/WhatFailureGroupHandler.php | 8 +++- src/Monolog/Processor/GitProcessor.php | 6 +++ .../Processor/IntrospectionProcessor.php | 6 +++ src/Monolog/Utils.php | 5 +++ 47 files changed, 262 insertions(+), 101 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 04ba0f33d..6ef80e8bc 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 6 + level: 8 treatPhpDocTypesAsCertain: false reportUnmatchedIgnoredErrors: false @@ -19,7 +19,16 @@ parameters: paths: - src/Monolog/Handler/LogglyHandler.php + # blocked until we only support php8+ + - '#Parameter \#1 \$socket of function (socket_close|socket_sendto|socket_send) expects Socket, resource\|Socket(\|null)? given\.#' + - '#Parameter \#1 \$handle of function (curl_exec|curl_close|curl_error|curl_errno|curl_setopt) expects CurlHandle, CurlHandle\|resource(\|null)? given\.#' + # blocked by https://github.com/phpstan/phpstan/issues/5091 - '#has unknown class Monolog\\Handler\\Record#' - - '#::processRecord#' + - '#::processRecord\(\) should return array#' + - '#::processRecord\(\) has invalid type#' + - '#::processRecord\(\) return type has no value type#' + - '#::processRecord\(\) has parameter \$record with no value type#' + - '#::popProcessor\(\) should return callable#' + - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#' - '#is incompatible with native type array.#' diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 9504d89c8..3939c1c50 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -65,6 +65,7 @@ public function getIndex(): string */ public function getType(): string { + /** @phpstan-ignore-next-line */ return $this->type; } @@ -78,6 +79,7 @@ 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); diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 3ca84c33b..a563a1ea0 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -20,6 +20,8 @@ * @see http://docs.graylog.org/en/latest/pages/gelf.html * * @author Matt Lehner + * + * @phpstan-import-type Level from \Monolog\Logger */ class GelfMessageFormatter extends NormalizerFormatter { @@ -49,6 +51,8 @@ class GelfMessageFormatter extends NormalizerFormatter * Translates Monolog log levels to Graylog2 log priorities. * * @var array + * + * @phpstan-var array */ private $logLevels = [ Logger::DEBUG => 7, @@ -65,7 +69,7 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n { parent::__construct('U.u'); - $this->systemName = (is_null($systemName) || $systemName === '') ? gethostname() : $systemName; + $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName; $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix; $this->contextPrefix = $contextPrefix; @@ -73,15 +77,18 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record): Message { + $context = $extra = []; if (isset($record['context'])) { - $record['context'] = parent::format($record['context']); + /** @var mixed[] $context */ + $context = parent::normalize($record['context']); } if (isset($record['extra'])) { - $record['extra'] = parent::format($record['extra']); + /** @var mixed[] $extra */ + $extra = parent::normalize($record['extra']); } if (!isset($record['datetime'], $record['message'], $record['level'])) { @@ -105,31 +112,31 @@ public function format(array $record): Message if (isset($record['channel'])) { $message->setFacility($record['channel']); } - if (isset($record['extra']['line'])) { - $message->setLine($record['extra']['line']); - unset($record['extra']['line']); + if (isset($extra['line'])) { + $message->setLine($extra['line']); + unset($extra['line']); } - if (isset($record['extra']['file'])) { - $message->setFile($record['extra']['file']); - unset($record['extra']['file']); + if (isset($extra['file'])) { + $message->setFile($extra['file']); + unset($extra['file']); } - foreach ($record['extra'] as $key => $val) { + foreach ($extra as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->extraPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + $message->setAdditional($this->extraPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength)); continue; } $message->setAdditional($this->extraPrefix . $key, $val); } - foreach ($record['context'] as $key => $val) { + foreach ($context as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->contextPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + $message->setAdditional($this->contextPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength)); continue; } @@ -137,8 +144,8 @@ public function format(array $record): Message } /** @phpstan-ignore-next-line */ - if (null === $message->getFile() && isset($record['context']['exception']['file'])) { - if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { + 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]); } diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index fa87cf359..f3eeb2323 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -110,6 +110,9 @@ public function format(array $record): string // remove leftover %extra.xxx% and %context.xxx% if any if (false !== strpos($output, '%')) { $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output); + if (null === $output) { + throw new \RuntimeException('Failed to run preg_replace: ' . preg_last_error() . ' / ' . preg_last_error_msg()); + } } return $output; diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index 563d97dbb..c33715917 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -52,7 +52,7 @@ public function __construct(string $applicationName, ?string $systemName = null, // logstash requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\TH:i:s.uP'); - $this->systemName = $systemName === null ? gethostname() : $systemName; + $this->systemName = $systemName === null ? (string) gethostname() : $systemName; $this->applicationName = $applicationName; $this->extraKey = $extraKey; $this->contextKey = $contextKey; diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index adf2ce1a5..202d30eb9 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -37,23 +37,26 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri $this->maxNestingLevel = max($maxNestingLevel, 0); $this->exceptionTraceAsString = $exceptionTraceAsString; - $this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare(phpversion('mongodb'), '1.1.9', '<='); + $this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare((string) phpversion('mongodb'), '1.1.9', '<='); } /** * {@inheritDoc} * - * @return scalar[] + * @return mixed[] */ public function format(array $record): array { - return $this->formatArray($record); + /** @var mixed[] $res */ + $res = $this->formatArray($record); + + return $res; } /** * {@inheritDoc} * - * @return array + * @return array */ public function formatBatch(array $records): array { @@ -152,6 +155,7 @@ private function legacyGetMongoDbDateTime(\DateTimeInterface $value): UTCDateTim ? (int) $milliseconds : (string) $milliseconds; + // @phpstan-ignore-next-line return new UTCDateTime($milliseconds); } } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 9363b6c47..1572b4c94 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -47,6 +47,8 @@ public function __construct(?string $dateFormat = null) /** * {@inheritdoc} + * + * @param mixed[] $record */ public function format(array $record) { @@ -123,7 +125,7 @@ public function setJsonPrettyPrint(bool $enable): self /** * @param mixed $data - * @return scalar|array + * @return null|scalar|array */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index f209ae5d5..5439ac6e1 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -22,20 +22,21 @@ class ScalarFormatter extends NormalizerFormatter /** * {@inheritdoc} * - * @phpstan-return scalar[] $record + * @phpstan-return array $record */ public function format(array $record): array { + $result = []; foreach ($record as $key => $value) { - $record[$key] = $this->normalizeValue($value); + $result[$key] = $this->normalizeValue($value); } - return $record; + return $result; } /** - * @param mixed $value - * @return string|int|bool|null + * @param mixed $value + * @return scalar|null */ protected function normalizeValue($value) { diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 5ee94d71f..71c99578e 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -69,6 +69,7 @@ public function format(array $record): string unset($record['extra']['line']); } + /** @var mixed[] $record */ $record = $this->normalize($record); $message = ['message' => $record['message']]; $handleError = false; @@ -125,7 +126,7 @@ public function formatBatch(array $records) /** * {@inheritdoc} * - * @return scalar|array|object + * @return null|scalar|array|object */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index eaff86ac7..fa17dcd83 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -21,6 +21,7 @@ * * @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 @@ -38,6 +39,7 @@ public function handle(array $record): bool } if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index ea7f5d3f6..e30d784dd 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -94,6 +94,7 @@ public function handleBatch(array $records): void continue; } + /** @var Record $record */ $record = $this->processRecord($record); $data = $this->getFormatter()->format($record); diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 4177046fb..4c938426d 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -197,7 +197,7 @@ private static function handleCustomStyles(string $style, string $string): strin static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; static $labels = []; - return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) { + $style = preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) { if (trim($m[1]) === 'autolabel') { // Format the string as a label with consistent auto assigned background color if (!isset($labels[$string])) { @@ -210,6 +210,12 @@ private static function handleCustomStyles(string $style, string $string): strin return $m[1]; }, $style); + + if (null === $style) { + throw new \RuntimeException('Failed to run preg_replace_callback: ' . preg_last_error() . ' / ' . preg_last_error_msg()); + } + + return $style; } /** diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index e4b46a97f..e8dd594a3 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -80,6 +80,7 @@ public function handle(array $record): bool } if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 27214665e..125b26586 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -22,6 +22,8 @@ * This also works out of the box with Firefox 43+ * * @author Christophe Coevoet + * + * @phpstan-import-type Record from \Monolog\Logger */ class ChromePHPHandler extends AbstractProcessingHandler { @@ -87,7 +89,9 @@ public function handleBatch(array $records): void if ($record['level'] < $this->level) { continue; } - $messages[] = $this->processRecord($record); + /** @var Record $message */ + $message = $this->processRecord($record); + $messages[] = $message; } if (!empty($messages)) { diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index d40ac4354..e95af66b6 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -46,7 +46,7 @@ public function __construct(string $url, $level = Logger::DEBUG, bool $bubble = { $urlInfo = parse_url($url); - if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { + if ($urlInfo === false || !isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); } @@ -76,11 +76,12 @@ protected function connectUdp(): void throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); } - $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); - if (!$this->udpConnection) { + $udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); + if (false === $udpConnection) { throw new \LogicException('Unable to create a socket'); } + $this->udpConnection = $udpConnection; if (!socket_connect($this->udpConnection, $this->host, $this->port)) { throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); } @@ -98,12 +99,12 @@ protected function connectHttp(): void throw new MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler'); } - $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); - - if (!$this->httpConnection) { + $httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); + if (false === $httpConnection) { throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); } + $this->httpConnection = $httpConnection; curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); } @@ -150,6 +151,10 @@ private function writeHttp(string $data): void $this->connectHttp(); } + if (null === $this->httpConnection) { + throw new \LogicException('No connection could be established'); + } + curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index be27c03ae..9b85ae7ed 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Simple handler wrapper that deduplicates log records across multiple requests @@ -34,6 +35,8 @@ * @author Jordi Boggiano * * @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 { @@ -43,7 +46,7 @@ class DeduplicationHandler extends BufferHandler protected $deduplicationStore; /** - * @var int + * @var Level */ protected $deduplicationLevel; @@ -63,6 +66,8 @@ class DeduplicationHandler extends BufferHandler * @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 Level|LevelName|LogLevel::* $deduplicationLevel */ public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true) { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 2b8d1a88c..b5f4ef1f3 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -79,6 +79,9 @@ protected function write(array $record): void } $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); + if ($lines === false) { + throw new \RuntimeException('Failed to preg_split formatted string: '.preg_last_error().' / '.preg_last_error_msg()); + } foreach ($lines as $line) { error_log($line, $this->messageType); } diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index 9c92fa2d3..0d84369c1 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -13,6 +13,15 @@ use Throwable; +/** + * Forwards records to at most one handler + * + * 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 { /** @@ -21,6 +30,7 @@ class FallbackGroupHandler extends GroupHandler public function handle(array $record): bool { if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -45,6 +55,7 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } + /** @var Record[] $records */ $records = $processed; } diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index cad7637df..40a5efb4b 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -64,6 +64,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList + * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) { @@ -89,6 +90,7 @@ public function getAcceptedLevels(): array * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array * * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList + * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self { @@ -124,6 +126,7 @@ public function handle(array $record): bool } if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 599d76c6b..7b9abb582 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -12,6 +12,7 @@ namespace Monolog\Handler\FingersCrossed; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Channel and Error level based monolog activation strategy. Allows to trigger activation @@ -35,11 +36,12 @@ * * @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 { /** - * @var int + * @var Level */ private $defaultActionLevel; @@ -52,7 +54,8 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any * @param array $channelToActionLevel An array that maps channel names to action levels. * - * @phpstan-param array $channelToActionLevel + * @phpstan-param array $channelToActionLevel + * @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel */ public function __construct($defaultActionLevel, array $channelToActionLevel = []) { diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 71601e401..5ec88eab6 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -12,21 +12,27 @@ namespace Monolog\Handler\FingersCrossed; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Error level based activation strategy. * * @author Johannes M. Schmitt + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { /** - * @var int + * @var Level */ private $actionLevel; /** * @param int|string $actionLevel Level or name or value + * + * @phpstan-param Level|LevelName|LogLevel::* $actionLevel */ public function __construct($actionLevel) { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 45801ec7d..266d4d594 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -16,6 +16,7 @@ use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; +use Psr\Log\LogLevel; /** * Buffers all records until a certain level is reached @@ -73,6 +74,9 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * @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 Level|LevelName|LogLevel::* $passthruLevel + * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy */ public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null) { @@ -127,6 +131,7 @@ public function activate(): void public function handle(array $record): bool { if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } @@ -152,7 +157,7 @@ public function close(): void { $this->flushBuffer(); - $this->handler->close(); + $this->getHandler()->close(); } public function reset() diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index e37180ca5..ad6c56980 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -67,11 +67,15 @@ class FirePHPHandler extends AbstractProcessingHandler * @param string $message Log message * * @return array Complete header string ready for the client as key and message as value + * + * @phpstan-return non-empty-array */ protected function createHeader(array $meta, string $message): array { $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta)); + // See https://github.com/phpstan/phpstan/issues/5219 + // @phpstan-ignore-next-line return [$header => $message]; } @@ -80,6 +84,8 @@ protected function createHeader(array $meta, string $message): array * * @return array * + * @phpstan-return non-empty-array + * * @see createHeader() * * @phpstan-param FormattedRecord $record diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 815844072..34cda19a5 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -43,8 +43,6 @@ class FleepHookHandler extends SocketHandler * see https://fleep.io/integrations/webhooks/ * * @param string $token Webhook token - * @param string|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 * @throws MissingExtensionException */ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index c12fe334f..d843b109c 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -37,9 +37,6 @@ class FlowdockHandler extends SocketHandler protected $apiToken; /** - * @param string|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 - * * @throws MissingExtensionException if OpenSSL is missing */ public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 5a4c8ac92..64d9da804 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -25,12 +25,12 @@ class GelfHandler extends AbstractProcessingHandler { /** - * @var PublisherInterface|null the publisher object that sends the message to the server + * @var PublisherInterface the publisher object that sends the message to the server */ protected $publisher; /** - * @param PublisherInterface $publisher a publisher object + * @param PublisherInterface $publisher a gelf publisher object */ public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) { diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 7265d87a3..3c9dc4b3b 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -18,6 +18,8 @@ * Forwards records to multiple handlers * * @author Lenar Lõhmus + * + * @phpstan-import-type Record from \Monolog\Logger */ class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { @@ -45,7 +47,7 @@ public function __construct(array $handlers, bool $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -59,11 +61,12 @@ public function isHandling(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } @@ -75,7 +78,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -84,6 +87,7 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } + /** @var Record[] $records */ $records = $processed; } @@ -113,7 +117,7 @@ public function close(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index 5ddc66bd1..fc34e8153 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -30,8 +30,6 @@ class InsightOpsHandler extends SocketHandler * @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|int $level The minimum logging level to trigger this handler - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 66de5f800..28f38b445 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -26,8 +26,6 @@ class LogEntriesHandler extends SocketHandler /** * @param string $token Log token supplied by LogEntries * @param bool $useSSL Whether or not SSL encryption should be used. - * @param string|int $level The minimum logging level to trigger this handler - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. * @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 diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 209af161f..7e0c4c586 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -40,8 +40,6 @@ class LogmaticHandler extends SocketHandler * @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 int|string $level The minimum logging level to trigger this handler. - * @param bool $bubble Whether or not messages that are handled should bubble up the stack. * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index a0148a587..2feadb17a 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -34,7 +34,9 @@ public function handleBatch(array $records): void if ($record['level'] < $this->level) { continue; } - $messages[] = $this->processRecord($record); + /** @var Record $message */ + $message = $this->processRecord($record); + $messages[] = $message; } if (!empty($messages)) { @@ -61,7 +63,7 @@ protected function write(array $record): void } /** - * @phpstan-param Record[] $records + * @phpstan-param non-empty-array $records * @phpstan-return Record */ protected function getHighestRecord(array $records): array diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index d057efae8..193da7245 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -162,7 +162,7 @@ protected function selectErrorStream() */ protected function readProcessErrors(): string { - return stream_get_contents($this->pipes[2]); + return (string) stream_get_contents($this->pipes[2]); } /** diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 12cc101cd..255af5c06 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Psr\Log\LogLevel; /** * Sends notifications through the pushover api to mobile phones @@ -21,6 +22,8 @@ * @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 { @@ -28,7 +31,7 @@ class PushoverHandler extends SocketHandler private $token; /** @var array */ private $users; - /** @var ?string */ + /** @var string */ private $title; /** @var string|int|null */ private $user = null; @@ -80,8 +83,6 @@ class PushoverHandler extends SocketHandler * @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 string|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 * @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 @@ -93,7 +94,9 @@ class PushoverHandler extends SocketHandler * @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 $users + * @phpstan-param string|array $users + * @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel + * @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel */ public function __construct( string $token, @@ -112,7 +115,7 @@ public function __construct( $this->token = $token; $this->users = (array) $users; - $this->title = $title ?: gethostname(); + $this->title = $title ?: (string) gethostname(); $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel); $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel); $this->retry = $retry; @@ -195,6 +198,8 @@ protected function write(array $record): void /** * @param int|string $value + * + * @phpstan-param Level|LevelName|LogLevel::* $value */ public function setHighPriorityLevel($value): self { @@ -205,6 +210,8 @@ public function setHighPriorityLevel($value): self /** * @param int|string $value + * + * @phpstan-param Level|LevelName|LogLevel::* $value */ public function setEmergencyLevel($value): self { diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 2d94da422..aaec12625 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -97,6 +97,7 @@ protected function write(array $record): void $toLog = $record['message']; } + // @phpstan-ignore-next-line $this->rollbarLogger->log($context['level'], $toLog, $context); $this->hasRecords = true; diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 949fd1b80..dbb008d24 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -46,8 +46,6 @@ class RotatingFileHandler extends StreamHandler /** * @param string $filename * @param int $maxFiles The maximal amount of files to keep (0 means unlimited) - * @param string|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 * @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 */ @@ -116,7 +114,7 @@ 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 = !file_exists($this->url); + $this->mustRotate = null === $this->url || !file_exists($this->url); } if ($this->nextRotation <= $record['datetime']) { @@ -142,6 +140,11 @@ protected function rotate(): void } $logFiles = glob($this->getGlobPattern()); + if (false === $logFiles) { + // failed to glob + return; + } + if ($this->maxFiles >= count($logFiles)) { // no files to remove return; @@ -176,7 +179,7 @@ protected function getTimedFilename(): string $fileInfo['dirname'] . '/' . $this->filenameFormat ); - if (!empty($fileInfo['extension'])) { + if (isset($fileInfo['extension'])) { $timedFilename .= '.'.$fileInfo['extension']; } @@ -191,7 +194,7 @@ protected function getGlobPattern(): string [$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'], $fileInfo['dirname'] . '/' . $this->filenameFormat ); - if (!empty($fileInfo['extension'])) { + if (isset($fileInfo['extension'])) { $glob .= '.'.$fileInfo['extension']; } diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index d76f1d351..a7ba86396 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -36,7 +36,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter /** * @var HandlerInterface|callable - * @phpstan-var HandlerInterface|callable(Record, HandlerInterface): HandlerInterface + * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface */ protected $handler; @@ -46,7 +46,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter protected $factor; /** - * @psalm-param HandlerInterface|callable(Record, HandlerInterface): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler * * @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) @@ -71,6 +71,7 @@ public function handle(array $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index e2c849c1f..13c3a1021 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -25,6 +25,7 @@ * @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 { @@ -121,7 +122,7 @@ public function __construct( * is expecting. * * @phpstan-param FormattedRecord $record - * @phpstan-return string[] + * @phpstan-return mixed[] */ public function getSlackData(array $record): array { @@ -137,6 +138,7 @@ public function getSlackData(array $record): array } if ($this->formatter && !$this->useAttachment) { + /** @phpstan-ignore-next-line */ $message = $this->formatter->format($record); } else { $message = $record['message']; @@ -221,6 +223,7 @@ public function getAttachmentColor(int $level): string */ public function stringify(array $fields): string { + /** @var Record $fields */ $normalized = $this->normalizerFormatter->format($fields); $hasSecondDimension = count(array_filter($normalized, 'is_array')); @@ -341,8 +344,11 @@ private function generateAttachmentField(string $title, $value): array */ private function generateAttachmentFields(array $data): array { + /** @var Record $data */ + $normalized = $this->normalizerFormatter->format($data); + $fields = array(); - foreach ($this->normalizerFormatter->format($data) as $key => $value) { + foreach ($normalized as $key => $value) { $fields[] = $this->generateAttachmentField((string) $key, $value); } diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index e35cac92d..c98249e8b 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -216,7 +216,7 @@ public function isConnected(): bool /** * Wrapper to allow mocking * - * @return resource|bool + * @return resource|false */ protected function pfsockopen() { @@ -226,7 +226,7 @@ protected function pfsockopen() /** * Wrapper to allow mocking * - * @return resource|bool + * @return resource|false */ protected function fsockopen() { @@ -245,6 +245,10 @@ protected function streamSetTimeout() $seconds = floor($this->timeout); $microseconds = round(($this->timeout - $seconds) * 1e6); + if (!is_resource($this->resource)) { + throw new \LogicException('streamSetTimeout called but $this->resource is not a resource'); + } + return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds); } @@ -257,6 +261,10 @@ protected function streamSetTimeout() */ protected function streamSetChunkSize() { + if (!is_resource($this->resource)) { + throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource'); + } + return stream_set_chunk_size($this->resource, $this->chunkSize); } @@ -267,6 +275,10 @@ protected function streamSetChunkSize() */ protected function fwrite(string $data) { + if (!is_resource($this->resource)) { + throw new \LogicException('fwrite called but $this->resource is not a resource'); + } + return @fwrite($this->resource, $data); } @@ -277,6 +289,10 @@ protected function fwrite(string $data) */ protected function streamGetMetadata() { + if (!is_resource($this->resource)) { + throw new \LogicException('streamGetMetadata called but $this->resource is not a resource'); + } + return stream_get_meta_data($this->resource); } @@ -325,7 +341,7 @@ private function createSocketResource(): void } else { $resource = $this->fsockopen(); } - if (!$resource) { + if (is_bool($resource)) { throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); } $this->resource = $resource; @@ -361,7 +377,7 @@ private function writeToSocket(string $data): void } $sent += $chunk; $socketInfo = $this->streamGetMetadata(); - if ($socketInfo['timed_out']) { + if (is_array($socketInfo) && $socketInfo['timed_out']) { throw new \RuntimeException("Write timed-out"); } diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 51eb02688..0f46f6315 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -101,34 +101,41 @@ public function getUrl(): ?string protected function write(array $record): void { if (!is_resource($this->stream)) { - if (null === $this->url || '' === $this->url) { + $url = $this->url; + if (null === $url || '' === $url) { throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); } - $this->createDir(); + $this->createDir($url); $this->errorMessage = null; set_error_handler([$this, 'customErrorHandler']); - $this->stream = fopen($this->url, 'a'); + $stream = fopen($url, 'a'); if ($this->filePermission !== null) { - @chmod($this->url, $this->filePermission); + @chmod($url, $this->filePermission); } restore_error_handler(); - if (!is_resource($this->stream)) { + if (!is_resource($stream)) { $this->stream = null; - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url)); } - stream_set_chunk_size($this->stream, self::MAX_CHUNK_SIZE); + stream_set_chunk_size($stream, self::MAX_CHUNK_SIZE); + $this->stream = $stream; + } + + $stream = $this->stream; + if (!is_resource($stream)) { + throw new \LogicException('No stream was opened yet'); } if ($this->useLocking) { // ignoring errors here, there's not much we can do about them - flock($this->stream, LOCK_EX); + flock($stream, LOCK_EX); } - $this->streamWrite($this->stream, $record); + $this->streamWrite($stream, $record); if ($this->useLocking) { - flock($this->stream, LOCK_UN); + flock($stream, LOCK_UN); } } @@ -165,14 +172,14 @@ private function getDirFromStream(string $stream): ?string return null; } - private function createDir(): void + private function createDir(string $url): void { // Do not try to create dir if it has already been tried. if ($this->dirCreated) { return; } - $dir = $this->getDirFromStream($this->url); + $dir = $this->getDirFromStream($url); if (null !== $dir && !is_dir($dir)) { $this->errorMessage = null; set_error_handler([$this, 'customErrorHandler']); diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 12636e533..c857d62de 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -36,8 +36,6 @@ class SyslogHandler extends AbstractSyslogHandler /** * @param string $ident * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant - * @param string|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 * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ public function __construct(string $ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index e6b7f77b5..ec404acfe 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -45,7 +45,6 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @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 string|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 * @param string $ident Program name or tag for each log message. * @param int $rfc RFC to format the message for. @@ -88,7 +87,12 @@ private function splitMessageIntoLines($message): array $message = implode("\n", $message); } - return preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); + $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); + if (false === $lines) { + throw new \RuntimeException('Could not preg_split: '.preg_last_error().' / '.preg_last_error_msg()); + } + + return $lines; } /** diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 51fb73966..db608ab87 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -27,6 +27,8 @@ * @link https://core.telegram.org/bots/api * * @author Mazur Alexandr + * + * @phpstan-import-type Record from \Monolog\Logger */ class TelegramBotHandler extends AbstractProcessingHandler { @@ -127,6 +129,7 @@ public function disableNotification(bool $disableNotification = null): self */ public function handleBatch(array $records): void { + /** @var Record[] $messages */ $messages = []; foreach ($records as $record) { @@ -135,6 +138,7 @@ public function handleBatch(array $records): void } if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } @@ -174,6 +178,9 @@ protected function send(string $message): void ])); $result = Curl\Util::execute($ch); + if (!is_string($result)) { + throw new RuntimeException('Telegram API error. Description: No response'); + } $result = json_decode($result, true); if ($result['ok'] === false) { diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index e2e3905f4..384f6e905 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -118,6 +118,8 @@ public function setSkipReset(bool $skipReset) /** * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecords($level): bool { @@ -151,6 +153,8 @@ public function hasRecord($record, $level): bool /** * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatContains(string $message, $level): bool { @@ -214,10 +218,11 @@ 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('Monolog\Logger::' . strtoupper($matches[2])); - if (method_exists($this, $genericMethod)) { + $callback = [$this, $genericMethod]; + if (is_callable($callback)) { $args[] = $level; - return call_user_func_array([$this, $genericMethod], $args); + return call_user_func_array($callback, $args); } } diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 16c3cbbb5..2dd136720 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -16,15 +16,18 @@ * and continuing through to give every handler a chance to succeed. * * @author Craig D'Amelio + * + * @phpstan-import-type Record from \Monolog\Logger */ class WhatFailureGroupHandler extends GroupHandler { /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { if ($this->processors) { + /** @var Record $record */ $record = $this->processRecord($record); } @@ -40,7 +43,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -49,6 +52,7 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } + /** @var Record[] $records */ $records = $processed; } diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 337ef2268..8166bdca2 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -12,12 +12,16 @@ namespace Monolog\Processor; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Injects Git branch and Git commit SHA in all records * * @author Nick Otter * @author Jordi Boggiano + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class GitProcessor implements ProcessorInterface { @@ -28,6 +32,8 @@ class GitProcessor implements ProcessorInterface /** * @param string|int $level The minimum logging level at which this Processor will be triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG) { diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 5a3e93c9a..0823501b9 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -12,6 +12,7 @@ namespace Monolog\Processor; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Injects line/file:class/function where the log message came from @@ -23,6 +24,9 @@ * triggered the FingersCrossedHandler. * * @author Jordi Boggiano + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class IntrospectionProcessor implements ProcessorInterface { @@ -41,6 +45,8 @@ class IntrospectionProcessor implements ProcessorInterface /** * @param string|int $level The minimum logging level at which this Processor will be triggered * @param string[] $skipClassesPartials + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 798681987..b2d0ad583 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -138,6 +138,8 @@ public static function handleJsonError(int $code, $data, ?int $encodeFlags = nul * @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): void { @@ -186,6 +188,9 @@ function ($m) { }, $data ); + if (!is_string($data)) { + throw new \RuntimeException('Failed to preg_replace_callback: '.preg_last_error().' / '.preg_last_error_msg()); + } $data = str_replace( ['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'], ['€', 'Å ', 'Å¡', 'Ž', 'ž', 'Å’', 'Å“', 'Ÿ'], From b2ad71de59709f5904cca7670ba19c4c62ffde90 Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Thu, 1 Jul 2021 16:26:46 +0200 Subject: [PATCH 340/498] JsonFormatter::normalize() : respect date format from Formatter --- src/Monolog/Formatter/JsonFormatter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 16421e225..611cf9492 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -173,6 +173,10 @@ protected function normalize($data, int $depth = 0) return $normalized; } + if ($data instanceof \DateTimeInterface) { + return $this->formatDate($data); + } + if ($data instanceof Throwable) { return $this->normalizeException($data, $depth); } From 4b9fdf77caf9100e4adaf10ef45531cbb8d187b1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Jul 2021 13:08:21 +0200 Subject: [PATCH 341/498] Fix json formatter to call parent constructor --- src/Monolog/Formatter/JsonFormatter.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 611cf9492..08c4fcbd3 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -44,6 +44,8 @@ public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $append $this->batchMode = $batchMode; $this->appendNewline = $appendNewline; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; + + parent::__construct(); } /** From a6eef7298c5e7cd22350fd3f8085911c03df2b0a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Jul 2021 13:24:06 +0200 Subject: [PATCH 342/498] Last phpstan fixes --- composer.json | 2 +- phpstan.neon.dist | 11 +++++++---- src/Monolog/Formatter/NormalizerFormatter.php | 3 +++ src/Monolog/Handler/FirePHPHandler.php | 2 -- src/Monolog/Logger.php | 1 - 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 27d433377..7ed2e3d37 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90 <7.0.1", "swiftmailer/swiftmailer": "^5.3|^6.0", - "phpstan/phpstan": "^0.12.59" + "phpstan/phpstan": "^0.12.91" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6ef80e8bc..961f7ce47 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,18 +10,21 @@ parameters: ignoreErrors: - '#zend_monitor_|ZEND_MONITOR_#' - - '#^Cannot call method ltrim\(\) on int\|false.$#' - '#MongoDB\\(Client|Collection)#' + # Invalid type info on Redis multi + - '#^Cannot call method ltrim\(\) on int\|false.$#' + + # Cannot resolve this cleanly as different normalizers return different types but it is safe - message: '#Return type \(string\) of method Monolog\\Formatter\\LineFormatter::normalizeException\(\) should be compatible with return type \(array\) of method Monolog\\Formatter\\NormalizerFormatter::normalizeException\(\)#' paths: - src/Monolog/Formatter/LineFormatter.php - - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' - paths: - - src/Monolog/Handler/LogglyHandler.php # blocked until we only support php8+ - '#Parameter \#1 \$socket of function (socket_close|socket_sendto|socket_send) expects Socket, resource\|Socket(\|null)? given\.#' - '#Parameter \#1 \$handle of function (curl_exec|curl_close|curl_error|curl_errno|curl_setopt) expects CurlHandle, CurlHandle\|resource(\|null)? given\.#' + - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' + paths: + - src/Monolog/Handler/LogglyHandler.php # blocked by https://github.com/phpstan/phpstan/issues/5091 - '#has unknown class Monolog\\Handler\\Record#' diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 1572b4c94..1c87dfb68 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -172,11 +172,14 @@ protected function normalize($data, int $depth = 0) } if ($data instanceof \JsonSerializable) { + /** @var null|scalar|array $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 $value */ $value = json_decode($this->toJson($data, true), true); } diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index ad6c56980..72718de63 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -74,8 +74,6 @@ protected function createHeader(array $meta, string $message): array { $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta)); - // See https://github.com/phpstan/phpstan/issues/5219 - // @phpstan-ignore-next-line return [$header => $message]; } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 0b7cb4483..37086e7e7 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -436,7 +436,6 @@ public static function toMonologLevel($level): int throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } - /** @phpstan-ignore-next-line */ return $level; } From df991fd88693ab703aa403413d83e15f688dae33 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 5 Jul 2021 13:34:13 +0200 Subject: [PATCH 343/498] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eef18d993..4f38665c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### 2.3.0 (2021-07-05) + + * Added a ton of PHPStan type annotations as well as type aliases on Monolog\Logger for Record, Level and LevelName that you can import (#1557) + * Added ability to customize date format when using JsonFormatter (#1561) + * Fixed FilterHandler not calling reset on its internal handler when reset() is called on it (#1531) + * Fixed SyslogUdpHandler not setting the timezone correctly on DateTimeImmutable instances (#1540) + * Fixed StreamHandler thread safety - chunk size set to 2GB now to avoid interlacing when doing concurrent writes (#1553) + ### 2.2.0 (2020-12-14) * Added JSON_PARTIAL_OUTPUT_ON_ERROR to default json encoding flags, to avoid dropping entire context data or even records due to an invalid subset of it somewhere From 19542ed8efd4b9cf94eb1c697d46e98448046753 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 8 Jul 2021 15:22:49 +0200 Subject: [PATCH 344/498] Normalize @inheritDoc tags, refs #1557 --- src/Monolog/Formatter/ChromePHPFormatter.php | 4 ++-- src/Monolog/Formatter/ElasticaFormatter.php | 2 +- src/Monolog/Formatter/ElasticsearchFormatter.php | 2 +- src/Monolog/Formatter/FlowdockFormatter.php | 4 ++-- src/Monolog/Formatter/JsonFormatter.php | 4 ++-- src/Monolog/Formatter/LineFormatter.php | 2 +- src/Monolog/Formatter/LogstashFormatter.php | 2 +- src/Monolog/Formatter/NormalizerFormatter.php | 4 ++-- src/Monolog/Formatter/ScalarFormatter.php | 2 +- src/Monolog/Formatter/WildfireFormatter.php | 6 +++--- src/Monolog/Handler/AbstractHandler.php | 2 +- .../Handler/AbstractProcessingHandler.php | 2 +- src/Monolog/Handler/AbstractSyslogHandler.php | 2 +- src/Monolog/Handler/BufferHandler.php | 8 ++++---- src/Monolog/Handler/ChromePHPHandler.php | 2 +- src/Monolog/Handler/CubeHandler.php | 2 +- src/Monolog/Handler/DynamoDbHandler.php | 4 ++-- src/Monolog/Handler/ElasticaHandler.php | 4 ++-- src/Monolog/Handler/ElasticsearchHandler.php | 4 ++-- src/Monolog/Handler/ErrorLogHandler.php | 2 +- src/Monolog/Handler/FallbackGroupHandler.php | 4 ++-- src/Monolog/Handler/FilterHandler.php | 10 +++++----- src/Monolog/Handler/FingersCrossedHandler.php | 10 +++++----- src/Monolog/Handler/FleepHookHandler.php | 2 +- src/Monolog/Handler/FlowdockHandler.php | 6 +++--- src/Monolog/Handler/FormattableHandlerTrait.php | 4 ++-- src/Monolog/Handler/GelfHandler.php | 2 +- src/Monolog/Handler/Handler.php | 4 ++-- src/Monolog/Handler/HandlerWrapper.php | 16 ++++++++-------- src/Monolog/Handler/IFTTTHandler.php | 2 +- src/Monolog/Handler/InsightOpsHandler.php | 2 +- src/Monolog/Handler/LogEntriesHandler.php | 2 +- src/Monolog/Handler/LogmaticHandler.php | 4 ++-- src/Monolog/Handler/MailHandler.php | 4 ++-- src/Monolog/Handler/MandrillHandler.php | 2 +- src/Monolog/Handler/NativeMailerHandler.php | 2 +- src/Monolog/Handler/NoopHandler.php | 4 ++-- src/Monolog/Handler/NullHandler.php | 4 ++-- src/Monolog/Handler/OverflowHandler.php | 6 +++--- src/Monolog/Handler/ProcessHandler.php | 2 +- src/Monolog/Handler/ProcessableHandlerTrait.php | 4 ++-- src/Monolog/Handler/RollbarHandler.php | 6 +++--- src/Monolog/Handler/RotatingFileHandler.php | 6 +++--- src/Monolog/Handler/SamplingHandler.php | 4 ++-- src/Monolog/Handler/SendGridHandler.php | 2 +- src/Monolog/Handler/SlackHandler.php | 4 ++-- src/Monolog/Handler/SlackWebhookHandler.php | 2 +- src/Monolog/Handler/SqsHandler.php | 2 +- src/Monolog/Handler/StreamHandler.php | 4 ++-- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- src/Monolog/Handler/SyslogHandler.php | 4 ++-- src/Monolog/Handler/TelegramBotHandler.php | 2 +- src/Monolog/Handler/TestHandler.php | 2 +- src/Monolog/Handler/ZendMonitorHandler.php | 4 ++-- tests/Monolog/Handler/ExceptionTestHandler.php | 2 +- 55 files changed, 103 insertions(+), 103 deletions(-) diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 424282abd..aa1884b9c 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -37,7 +37,7 @@ class ChromePHPFormatter implements FormatterInterface ]; /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record) { @@ -68,7 +68,7 @@ public function format(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function formatBatch(array $records) { diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 3939c1c50..6c8a9ab5e 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -46,7 +46,7 @@ public function __construct(string $index, ?string $type) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record) { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 5442cb793..b792b819c 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -44,7 +44,7 @@ public function __construct(string $index, string $type) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record) { diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index f7f2e81a7..41b56b3c0 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -35,7 +35,7 @@ public function __construct(string $source, string $sourceEmail) } /** - * {@inheritdoc} + * {@inheritDoc} * * @return mixed[] */ @@ -71,7 +71,7 @@ public function format(array $record): array } /** - * {@inheritdoc} + * {@inheritDoc} * * @return mixed[][] */ diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 08c4fcbd3..46592ba96 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -69,7 +69,7 @@ public function isAppendingNewlines(): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record): string { @@ -94,7 +94,7 @@ public function format(array $record): string } /** - * {@inheritdoc} + * {@inheritDoc} */ public function formatBatch(array $records): string { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index f3eeb2323..1cc9f539c 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -67,7 +67,7 @@ public function ignoreEmptyContextAndExtra(bool $ignore = true): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record): string { diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index c33715917..f8de0d333 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -59,7 +59,7 @@ public function __construct(string $applicationName, ?string $systemName = null, } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record): string { diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 1c87dfb68..01f75a42c 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -46,7 +46,7 @@ public function __construct(?string $dateFormat = null) } /** - * {@inheritdoc} + * {@inheritDoc} * * @param mixed[] $record */ @@ -56,7 +56,7 @@ public function format(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function formatBatch(array $records) { diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index 5439ac6e1..187bc550d 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -20,7 +20,7 @@ class ScalarFormatter extends NormalizerFormatter { /** - * {@inheritdoc} + * {@inheritDoc} * * @phpstan-return array $record */ diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 71c99578e..6539b3473 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -52,7 +52,7 @@ public function __construct(?string $dateFormat = null) } /** - * {@inheritdoc} + * {@inheritDoc} * * @return string */ @@ -114,7 +114,7 @@ public function format(array $record): string } /** - * {@inheritdoc} + * {@inheritDoc} * * @phpstan-return never */ @@ -124,7 +124,7 @@ public function formatBatch(array $records) } /** - * {@inheritdoc} + * {@inheritDoc} * * @return null|scalar|array|object */ diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 1f4679513..a5cdaa71f 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -46,7 +46,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index fa17dcd83..77e533fca 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -30,7 +30,7 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc use FormattableHandlerTrait; /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 673561abf..5e5ad1c1f 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -97,7 +97,7 @@ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, bool $ } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index e8dd594a3..fcce5d630 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -56,7 +56,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $le } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { @@ -108,7 +108,7 @@ public function __destruct() } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -140,7 +140,7 @@ public function reset() } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -154,7 +154,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 125b26586..d1a98b8fe 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -75,7 +75,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index e95af66b6..fc8f58f1a 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -110,7 +110,7 @@ protected function connectHttp(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index ec3bf2d16..21840bf60 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -65,7 +65,7 @@ public function __construct(DynamoDbClient $client, string $table, $level = Logg } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { @@ -95,7 +95,7 @@ protected function filterEmptyFields(array $record): array } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 170bccf69..fc92ca42d 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -73,7 +73,7 @@ protected function write(array $record): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -101,7 +101,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 0995100c5..b9d323d83 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -80,7 +80,7 @@ protected function write(array $record): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -110,7 +110,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index b5f4ef1f3..d14797467 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -68,7 +68,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index 0d84369c1..d4e234ce0 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -25,7 +25,7 @@ class FallbackGroupHandler extends GroupHandler { /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { @@ -46,7 +46,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 40a5efb4b..81d227b47 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -109,7 +109,7 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -117,7 +117,7 @@ public function isHandling(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { @@ -136,7 +136,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -174,7 +174,7 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -189,7 +189,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 266d4d594..0627b4451 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -105,7 +105,7 @@ public function __construct($handler, $activationStrategy = null, int $bufferSiz } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -126,7 +126,7 @@ public function activate(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { @@ -151,7 +151,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -223,7 +223,7 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -238,7 +238,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 34cda19a5..6194283a8 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -79,7 +79,7 @@ public function write(array $record): void } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index d843b109c..a632c8623 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -50,7 +50,7 @@ public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubb } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -70,7 +70,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { @@ -80,7 +80,7 @@ protected function write(array $record): void } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 3dbf0f656..b60bdce0e 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -27,7 +27,7 @@ trait FormattableHandlerTrait protected $formatter; /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -37,7 +37,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 64d9da804..4ff26c4cd 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -40,7 +40,7 @@ public function __construct(PublisherInterface $publisher, $level = Logger::DEBU } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/Handler.php b/src/Monolog/Handler/Handler.php index 9f43fe10b..afef2fd74 100644 --- a/src/Monolog/Handler/Handler.php +++ b/src/Monolog/Handler/Handler.php @@ -19,7 +19,7 @@ abstract class Handler implements HandlerInterface { /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -29,7 +29,7 @@ public function handleBatch(array $records): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index 842c941c1..d4351b9f9 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -44,7 +44,7 @@ public function __construct(HandlerInterface $handler) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -52,7 +52,7 @@ public function isHandling(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { @@ -60,7 +60,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -68,7 +68,7 @@ public function handleBatch(array $records): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -76,7 +76,7 @@ public function close(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function pushProcessor(callable $callback): HandlerInterface { @@ -90,7 +90,7 @@ public function pushProcessor(callable $callback): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function popProcessor(): callable { @@ -102,7 +102,7 @@ public function popProcessor(): callable } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -116,7 +116,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 18ed8cee3..f43ef267c 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -45,7 +45,7 @@ public function __construct(string $eventName, string $secretKey, $level = Logge } /** - * {@inheritdoc} + * {@inheritDoc} */ public function write(array $record): void { diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index fc34e8153..c62dc24d9 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -48,7 +48,7 @@ public function __construct(string $token, string $region = 'us', bool $useSSL = } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 28f38b445..a0739cf04 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -42,7 +42,7 @@ public function __construct(string $token, bool $useSSL = true, $level = Logger: } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 7e0c4c586..e7666eca4 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -60,7 +60,7 @@ public function __construct(string $token, string $hostname = '', string $appnam } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { @@ -68,7 +68,7 @@ protected function generateDataStream(array $record): string } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 2feadb17a..97f343202 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -24,7 +24,7 @@ abstract class MailHandler extends AbstractProcessingHandler { /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { @@ -55,7 +55,7 @@ public function handleBatch(array $records): void abstract protected function send(string $content, array $records): void; /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index f49dc1c4c..3003500ec 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -48,7 +48,7 @@ public function __construct(string $apiKey, $message, $level = Logger::ERROR, bo } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 0989184af..0c0a3bdb1 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -109,7 +109,7 @@ public function addParameter($parameters): self } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/NoopHandler.php b/src/Monolog/Handler/NoopHandler.php index 8ee2b4c69..1ddf0beb9 100644 --- a/src/Monolog/Handler/NoopHandler.php +++ b/src/Monolog/Handler/NoopHandler.php @@ -23,7 +23,7 @@ class NoopHandler extends Handler { /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -31,7 +31,7 @@ public function isHandling(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 482e7f682..e75ee0c6e 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -43,7 +43,7 @@ public function __construct($level = Logger::DEBUG) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function isHandling(array $record): bool { @@ -51,7 +51,7 @@ public function isHandling(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 77bd618a5..22068c9a3 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -85,7 +85,7 @@ public function __construct( * 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(array $record): bool { @@ -122,7 +122,7 @@ public function handle(array $record): bool } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -136,7 +136,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 193da7245..8a8cf1be6 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -176,7 +176,7 @@ protected function writeProcessInput(string $string): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index f3cdd2a34..9ef6e301c 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -30,7 +30,7 @@ trait ProcessableHandlerTrait protected $processors = []; /** - * {@inheritdoc} + * {@inheritDoc} */ public function pushProcessor(callable $callback): HandlerInterface { @@ -40,7 +40,7 @@ public function pushProcessor(callable $callback): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function popProcessor(): callable { diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index aaec12625..adcc9395a 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -71,7 +71,7 @@ public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { @@ -112,7 +112,7 @@ public function flush(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -120,7 +120,7 @@ public function close(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function reset() { diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index dbb008d24..2b7c48030 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -61,7 +61,7 @@ public function __construct(string $filename, int $maxFiles = 0, $level = Logger } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -73,7 +73,7 @@ public function close(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ public function reset() { @@ -108,7 +108,7 @@ public function setFilenameFormat(string $filenameFormat, string $dateFormat): s } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index a7ba86396..c128a32d1 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -103,7 +103,7 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -118,7 +118,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 02ccc4fec..4ec64290b 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -68,7 +68,7 @@ public function __construct(string $apiUser, string $apiKey, string $from, $to, } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 13ad8b714..46d69a6d2 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -91,7 +91,7 @@ public function getToken(): string } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function generateDataStream(array $record): string { @@ -143,7 +143,7 @@ private function buildHeader(string $content): string } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 1c934774c..d6a3733e6 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -84,7 +84,7 @@ public function getWebhookUrl(): string } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 2d531458b..dc1dcb427 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -41,7 +41,7 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Log } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 0f46f6315..bc1f198d5 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -64,7 +64,7 @@ public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -96,7 +96,7 @@ public function getUrl(): ?string } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index e0e182dbb..b3fedea5d 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -46,7 +46,7 @@ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ER } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index c857d62de..4951f66a9 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -47,7 +47,7 @@ public function __construct(string $ident, $facility = LOG_USER, $level = Logger } /** - * {@inheritdoc} + * {@inheritDoc} */ public function close(): void { @@ -55,7 +55,7 @@ public function close(): void } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index db608ab87..013cfdd80 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -125,7 +125,7 @@ public function disableNotification(bool $disableNotification = null): self } /** - * {@inheritdoc} + * {@inheritDoc} */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 384f6e905..0986da270 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -200,7 +200,7 @@ public function hasRecordThatPasses(callable $predicate, $level) } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 7c9577cac..ddd46d8c5 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -57,7 +57,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ protected function write(array $record): void { @@ -84,7 +84,7 @@ protected function writeZendMonitorCustomEvent(string $type, string $message, ar } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getDefaultFormatter(): FormatterInterface { diff --git a/tests/Monolog/Handler/ExceptionTestHandler.php b/tests/Monolog/Handler/ExceptionTestHandler.php index f5a682ef4..f5df55e4e 100644 --- a/tests/Monolog/Handler/ExceptionTestHandler.php +++ b/tests/Monolog/Handler/ExceptionTestHandler.php @@ -16,7 +16,7 @@ class ExceptionTestHandler extends TestHandler { /** - * {@inheritdoc} + * {@inheritDoc} */ public function handle(array $record): bool { From 42384f29bad61dcaa62c6ed591c3761ed01f1c22 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 12 Jul 2021 14:48:59 +0200 Subject: [PATCH 345/498] Ignore config file --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 02e43648e..52e9cb437 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ /.* export-ignore /phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore +/_config.yml export-ignore /UPGRADE.md From 63e195046ce040b4d30660c7d5f677af03684cf1 Mon Sep 17 00:00:00 2001 From: Fabien Villepinte Date: Wed, 14 Jul 2021 12:57:59 +0200 Subject: [PATCH 346/498] Fix Utils::getClass() with PHP8 (#1563) --- src/Monolog/Utils.php | 10 +++++++++- tests/Monolog/UtilsTest.php | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index b2d0ad583..2fd901ad7 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -19,7 +19,15 @@ public static function getClass(object $object): string { $class = \get_class($object); - return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; + if (false === ($pos = \strpos($class, "@anonymous\0"))) { + return $class; + } + + if (false === ($parent = \get_parent_class($class))) { + return \substr($class, 0, $pos + 10); + } + + return $parent . '@anonymous'; } public static function substr(string $string, int $start, ?int $length = null): string diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 68a62b14c..3d66b960a 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -13,6 +13,25 @@ class UtilsTest extends \PHPUnit_Framework_TestCase { + /** + * @param string $expected + * @param object $object + * @dataProvider provideObjects + */ + public function testGetClass($expected, $object) + { + $this->assertSame($expected, Utils::getClass($object)); + } + + public function provideObjects() + { + return [ + ['stdClass', new \stdClass()], + ['class@anonymous', new class {}], + ['stdClass@anonymous', new class extends \stdClass {}], + ]; + } + /** * @param string $expected * @param string $input From 9738e495f288eec0b187e310b7cdbbb285777dbe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 14 Jul 2021 13:56:39 +0200 Subject: [PATCH 347/498] Update changelog for 2.3.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f38665c9..bd440ac91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### 2.3.1 (2021-07-14) + + * Fixed Utils::getClass handling of anonymous classes not being fully compatible with PHP 8 (#1563) + * Fixed some `@inheritDoc` annotations having the wrong case + ### 2.3.0 (2021-07-05) * Added a ton of PHPStan type annotations as well as type aliases on Monolog\Logger for Record, Level and LevelName that you can import (#1557) From d08c09d95509a49b410d7e6835793b78cbb79d3c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 23 Jul 2021 09:11:20 +0200 Subject: [PATCH 348/498] Fix phpstan error --- src/Monolog/Handler/SyslogUdpHandler.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index ec404acfe..0b68922ac 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -110,26 +110,25 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $date $hostname = '-'; } - if ($this->rfc === self::RFC3164 && ($datetime instanceof \DateTimeImmutable || $datetime instanceof \DateTime)) { + if ($this->rfc === self::RFC3164) { + // see https://github.com/phpstan/phpstan/issues/5348 + // @phpstan-ignore-next-line $dateNew = $datetime->setTimezone(new \DateTimeZone('UTC')); $date = $dateNew->format($this->dateFormats[$this->rfc]); - } - else { - $date = $datetime->format($this->dateFormats[$this->rfc]); - } - if ($this->rfc === self::RFC3164) { return "<$priority>" . $date . " " . $hostname . " " . $this->ident . "[" . $pid . "]: "; - } else { - return "<$priority>1 " . - $date . " " . - $hostname . " " . - $this->ident . " " . - $pid . " - - "; } + + $date = $datetime->format($this->dateFormats[$this->rfc]); + + return "<$priority>1 " . + $date . " " . + $hostname . " " . + $this->ident . " " . + $pid . " - - "; } /** From 82ab6a5f4f9ad081856eee4c9458efed5ecd7156 Mon Sep 17 00:00:00 2001 From: Juan Morales Date: Fri, 23 Jul 2021 09:16:39 +0200 Subject: [PATCH 349/498] Fixes php8 non-backward compatible changes (#1568) * Utils method added to resolve PCRE error messages properly --- src/Monolog/Formatter/LineFormatter.php | 3 +- src/Monolog/Handler/BrowserConsoleHandler.php | 3 +- src/Monolog/Handler/ErrorLogHandler.php | 4 ++- src/Monolog/Handler/SyslogUdpHandler.php | 4 ++- src/Monolog/Utils.php | 22 ++++++++++++- tests/Monolog/UtilsTest.php | 32 +++++++++++++++++++ 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 1cc9f539c..6ed817aba 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -111,7 +111,8 @@ public function format(array $record): string if (false !== strpos($output, '%')) { $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output); if (null === $output) { - throw new \RuntimeException('Failed to run preg_replace: ' . preg_last_error() . ' / ' . preg_last_error_msg()); + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); } } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 4c938426d..8d908b266 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -212,7 +212,8 @@ private static function handleCustomStyles(string $style, string $string): strin }, $style); if (null === $style) { - throw new \RuntimeException('Failed to run preg_replace_callback: ' . preg_last_error() . ' / ' . preg_last_error_msg()); + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); } return $style; diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index d14797467..f2e22036b 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\Utils; /** * Stores to PHP error_log() handler. @@ -80,7 +81,8 @@ protected function write(array $record): void $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); if ($lines === false) { - throw new \RuntimeException('Failed to preg_split formatted string: '.preg_last_error().' / '.preg_last_error_msg()); + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to preg_split formatted string: ' . $pcreErrorCode . ' / '. Utils::pcreLastErrorMessage($pcreErrorCode)); } foreach ($lines as $line) { error_log($line, $this->messageType); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 0b68922ac..abc6d44db 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -14,6 +14,7 @@ use DateTimeInterface; use Monolog\Logger; use Monolog\Handler\SyslogUdp\UdpSocket; +use Monolog\Utils; /** * A Handler for logging to a remote syslogd server. @@ -89,7 +90,8 @@ private function splitMessageIntoLines($message): array $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); if (false === $lines) { - throw new \RuntimeException('Could not preg_split: '.preg_last_error().' / '.preg_last_error_msg()); + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Could not preg_split: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); } return $lines; diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 2fd901ad7..8812f007d 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -140,6 +140,25 @@ public static function handleJsonError(int $code, $data, ?int $encodeFlags = nul return $json; } + /** + * @internal + */ + public static function pcreLastErrorMessage(int $code): string + { + if (PHP_VERSION_ID >= 80000) { + return preg_last_error_msg(); + } + + $constants = (get_defined_constants(true))['pcre']; + $constants = array_filter($constants, function ($key) { + return substr($key, -6) == '_ERROR'; + }, ARRAY_FILTER_USE_KEY); + + $constants = array_flip($constants); + + return $constants[$code] ?? 'UNDEFINED_ERROR'; + } + /** * Throws an exception according to a given code with a customized message * @@ -197,7 +216,8 @@ function ($m) { $data ); if (!is_string($data)) { - throw new \RuntimeException('Failed to preg_replace_callback: '.preg_last_error().' / '.preg_last_error_msg()); + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode)); } $data = str_replace( ['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'], diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 3d66b960a..bc2164671 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -109,4 +109,36 @@ public function providesDetectAndCleanUtf8() 'object' => [$obj, $obj], ]; } + + /** + * @dataProvider providesPcreLastErrorMessage + * @param int $code + * @param string $msg + */ + public function testPcreLastErrorMessage($code, $msg) + { + if (PHP_VERSION_ID >= 80000) { + $this->assertSame('No error', Utils::pcreLastErrorMessage($code)); + return; + } + + $this->assertEquals($msg, Utils::pcreLastErrorMessage($code)); + } + + /** + * @return array[] + */ + public function providesPcreLastErrorMessage() + { + return [ + [0, 'PREG_NO_ERROR'], + [1, 'PREG_INTERNAL_ERROR'], + [2, 'PREG_BACKTRACK_LIMIT_ERROR'], + [3, 'PREG_RECURSION_LIMIT_ERROR'], + [4, 'PREG_BAD_UTF8_ERROR'], + [5, 'PREG_BAD_UTF8_OFFSET_ERROR'], + [6, 'PREG_JIT_STACKLIMIT_ERROR'], + [-1, 'UNDEFINED_ERROR'], + ]; + } } From 71312564759a7db5b789296369c1a264efc43aad Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 23 Jul 2021 09:42:52 +0200 Subject: [PATCH 350/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd440ac91..f3f46977b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 2.3.2 (2021-07-23) + + * Fixed compatibility with PHP 7.2 - 7.4 when experiencing PCRE errors (#1568) + ### 2.3.1 (2021-07-14) * Fixed Utils::getClass handling of anonymous classes not being fully compatible with PHP 8 (#1563) From 71cf94a36183d7d2ae04cea095bfb4e3a94ce30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Jul 2021 19:22:53 +0200 Subject: [PATCH 351/498] add check for required extension --- src/Monolog/Handler/SyslogUdpHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index abc6d44db..deaa19f80 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -49,11 +49,16 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @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, $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'); + } + parent::__construct($facility, $level, $bubble); $this->ident = $ident; From d76d691acfc82e09c37cf47b5e24e335bf2c2b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Jul 2021 19:50:08 +0200 Subject: [PATCH 352/498] add checks for required curl extension --- src/Monolog/Handler/IFTTTHandler.php | 4 ++++ src/Monolog/Handler/SendGridHandler.php | 4 ++++ src/Monolog/Handler/SlackWebhookHandler.php | 4 ++++ src/Monolog/Handler/TelegramBotHandler.php | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index f43ef267c..000ccea40 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -38,6 +38,10 @@ class IFTTTHandler extends AbstractProcessingHandler */ 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'); + } + $this->eventName = $eventName; $this->secretKey = $secretKey; diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 4ec64290b..1280ee703 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -59,6 +59,10 @@ class SendGridHandler extends MailHandler */ 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'); + } + parent::__construct($level, $bubble); $this->apiUser = $apiUser; $this->apiKey = $apiKey; diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index d6a3733e6..8ae3c7882 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -58,6 +58,10 @@ public function __construct( bool $bubble = true, array $excludeFields = array() ) { + if (!extension_loaded('curl')) { + throw new MissingExtensionException('The curl extension is needed to use the SlackWebhookHandler'); + } + parent::__construct($level, $bubble); $this->webhookUrl = $webhookUrl; diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 013cfdd80..9ea057371 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -90,6 +90,10 @@ public function __construct( bool $disableWebPagePreview = null, bool $disableNotification = null ) { + if (!extension_loaded('curl')) { + throw new MissingExtensionException('The curl extension is needed to use the TelegramBotHandler'); + } + parent::__construct($level, $bubble); $this->apiKey = $apiKey; From 1ad394f62fb87a950ecb86b8a266dbf49a5460f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Jul 2021 19:55:11 +0200 Subject: [PATCH 353/498] mention some more extensions in composer.json --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7ed2e3d37..95053e1d7 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,10 @@ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "rollbar/rollbar": "Allow sending log messages to Rollbar", "php-console/php-console": "Allow sending log messages to Google Chrome", - "ext-mbstring": "Allow to work properly with unicode symbols" + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-openssl": "Required to send log messages using SSL" }, "autoload": { "psr-4": {"Monolog\\": "src/Monolog"} From 173a59ffe0c4125387055e7f5d542c941f6448a2 Mon Sep 17 00:00:00 2001 From: Pier-Luc Lafleur Date: Fri, 6 Aug 2021 09:40:16 -0400 Subject: [PATCH 354/498] Update 01-usage.md Removing mention of monolog-cascade monolog-cascade doesn't support monolog ^2.0 or php8 --- doc/01-usage.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index fa37614ee..50e5ad13a 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -109,10 +109,6 @@ Note that the FirePHPHandler is called first as it is added on top of the stack. This allows you to temporarily add a logger with bubbling disabled if you want to override other configured loggers. -> If you use Monolog standalone and are looking for an easy way to -> configure many handlers, the [theorchard/monolog-cascade](https://github.com/theorchard/monolog-cascade) -> can help you build complex logging configs via PHP arrays, yaml or json configs. - ## Adding extra data in the records Monolog provides two different ways to add extra information along the simple From f2156cdd55f960432c332d4da1cd53c7fccf075f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 17 Aug 2021 14:13:55 +0200 Subject: [PATCH 355/498] Tweak some type annotations --- src/Monolog/Handler/FilterHandler.php | 4 ++-- src/Monolog/Logger.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 81d227b47..718f17ef1 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -44,7 +44,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * Minimum level for logs that are passed to handler * * @var int[] - * @phpstan-var Level[] + * @phpstan-var array */ protected $acceptedLevels; @@ -78,7 +78,7 @@ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel } /** - * @phpstan-return Level[] + * @phpstan-return array */ public function getAcceptedLevels(): array { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 37086e7e7..abc52029a 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -382,6 +382,7 @@ public function reset(): void * Gets all supported logging levels. * * @return array Assoc array with human-readable level names => level codes. + * @phpstan-return array */ public static function getLevels(): array { From 57e3fe3173e83bceecf9b25fac31d60ec57b15f3 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Wed, 14 Jul 2021 23:25:49 +0200 Subject: [PATCH 356/498] Allow psr/log 2.0 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 7ed2e3d37..5ac50eec3 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ ], "require": { "php": ">=7.2", - "psr/log": "^1.0.1" + "psr/log": "^1.0.1 || ^2.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -53,7 +53,7 @@ "psr-4": {"Monolog\\": "tests/Monolog"} }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0" }, "extra": { "branch-alias": { From 203bb1b6f567f1fc266e381c6e955326afddf5c3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 13 Sep 2021 12:13:06 +0200 Subject: [PATCH 357/498] Fix CI to allow psr/log v2 --- .github/workflows/continuous-integration.yml | 16 ++- composer.json | 3 +- phpstan.neon.dist | 3 + tests/Monolog/Handler/RollbarHandlerTest.php | 2 + tests/Monolog/PsrLogCompatTest.php | 130 ++++++++++++++++++- 5 files changed, 144 insertions(+), 10 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 9852d7805..19806498c 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -58,18 +58,24 @@ jobs: - name: Add require for mongodb/mongodb to make tests runnable run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' - # This does not affect runtime, only tests were fixed in psr/log 1.1.2 so it's - # ok to require this only when running tests - - name: Bump required version of psr/log for tests purposes to fix the --prefer-lowest builds - run: 'composer require ${{ env.COMPOSER_FLAGS }} psr/log:^1.1.2 --no-update' - - name: "Handle lowest dependencies update" if: "contains(matrix.dependencies, 'lowest')" run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" + - name: "Ensure psr/log v2 is installed" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" + run: composer require -W psr/log:^2 + - name: "Install latest dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} - name: "Run tests" run: "composer exec phpunit -- --verbose" + + - name: "Run tests with rollbar" + run: | + composer require psr/log:'^1.1|^2' --no-update + composer require rollbar/rollbar:^1.3 --no-update + composer update -W ${{ env.COMPOSER_FLAGS }} + composer exec phpunit -- --verbose --filter Rollbar diff --git a/composer.json b/composer.json index 5ac50eec3..99e791a83 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,7 @@ "phpspec/prophecy": "^1.6.1", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", - "rollbar/rollbar": "^1.3", - "ruflin/elastica": ">=0.90 <7.0.1", + "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0", "phpstan/phpstan": "^0.12.91" }, diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 961f7ce47..275089a06 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -35,3 +35,6 @@ parameters: - '#::popProcessor\(\) should return callable#' - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#' - '#is incompatible with native type array.#' + + # can be removed when https://github.com/rollbar/rollbar-php/pull/536 will be merged + - '#Rollbar\\RollbarLogger#' diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 40442105c..0aa7cbff0 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -22,6 +22,8 @@ * @see https://rollbar.com/docs/notifier/rollbar-php/ * * @coversDefaultClass Monolog\Handler\RollbarHandler + * + * @requires function \Rollbar\RollbarLogger::__construct */ class RollbarHandlerTest extends TestCase { diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index a4bbcd0cb..eaeb3552c 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -11,16 +11,21 @@ namespace Monolog; +use DateTimeZone; use Monolog\Handler\TestHandler; use Monolog\Formatter\LineFormatter; use Monolog\Processor\PsrLogMessageProcessor; +use PHPUnit\Framework\TestCase; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; use Psr\Log\Test\LoggerInterfaceTest; -class PsrLogCompatTest extends LoggerInterfaceTest +class PsrLogCompatTest extends TestCase { private $handler; - public function getLogger() + public function getLogger(): LoggerInterface { $logger = new Logger('foo'); $logger->pushHandler($handler = new TestHandler); @@ -32,7 +37,7 @@ public function getLogger() return $logger; } - public function getLogs() + public function getLogs(): array { $convert = function ($record) { $lower = function ($match) { @@ -44,4 +49,123 @@ public function getLogs() return array_map($convert, $this->handler->getRecords()); } + + public function testImplements() + { + $this->assertInstanceOf(LoggerInterface::class, $this->getLogger()); + } + + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + + $expected = array( + "$level message of level $level with context: Bob", + "$level message of level $level with context: Bob", + ); + $this->assertEquals($expected, $this->getLogs()); + } + + public function provideLevelsAndMessages() + { + return array( + LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), + LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), + LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), + LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), + LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), + LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), + LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), + LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), + ); + } + + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + + $this->expectException(InvalidArgumentException::class); + $logger->log('invalid level', 'Foo'); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testObjectCastToString() + { + $string = uniqid('DUMMY'); + $dummy = $this->createStringable($string); + $dummy->expects($this->once()) + ->method('__toString'); + + $this->getLogger()->warning($dummy); + + $expected = array("warning $string"); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextCanContainAnything() + { + $closed = fopen('php://memory', 'r'); + fclose($closed); + + $context = array( + 'bool' => true, + 'null' => null, + 'string' => 'Foo', + 'int' => 0, + 'float' => 0.5, + 'nested' => array('with object' => $this->createStringable()), + 'object' => new \DateTime('now', new DateTimeZone('Europe/London')), + 'resource' => fopen('php://memory', 'r'), + 'closed' => $closed, + ); + + $this->getLogger()->warning('Crazy context data', $context); + + $expected = array('warning Crazy context data'); + $this->assertEquals($expected, $this->getLogs()); + } + + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $logger = $this->getLogger(); + $logger->warning('Random message', array('exception' => 'oops')); + $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + + $expected = array( + 'warning Random message', + 'critical Uncaught Exception!' + ); + $this->assertEquals($expected, $this->getLogs()); + } + + /** + * Creates a mock of a `Stringable`. + * + * @param string $string The string that must be represented by the stringable. + * @return \PHPUnit_Framework_MockObject_MockObject A mock of an object that has a `__toString()` method. + */ + protected function createStringable($string = '') + { + $mock = $this->getMockBuilder('Stringable') + ->setMethods(array('__toString')) + ->getMock(); + + $mock->method('__toString') + ->will($this->returnValue($string)); + + return $mock; + } } From 0b22036ab67fa7752e53e8bb18891894e31137d1 Mon Sep 17 00:00:00 2001 From: jcm Date: Fri, 30 Jul 2021 09:06:22 +0200 Subject: [PATCH 358/498] Add method in Utils to convert memory values from php_ini into bytes, and use lower amount of chunk size based on memory limit --- src/Monolog/Handler/StreamHandler.php | 37 ++++++++- src/Monolog/Utils.php | 48 ++++++++++++ tests/Monolog/Handler/StreamHandlerTest.php | 87 +++++++++++++++++++++ tests/Monolog/UtilsTest.php | 43 ++++++++++ 4 files changed, 211 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index bc1f198d5..8d1189289 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -25,8 +25,12 @@ */ class StreamHandler extends AbstractProcessingHandler { - protected const MAX_CHUNK_SIZE = 2147483647; - + /** @const int */ + const SAFE_MEMORY_OFFSET = 1024; + /** @const int */ + const MAX_CHUNK_SIZE = 2147483647; + /** @var int */ + protected $streamChunkSize = self::MAX_CHUNK_SIZE; /** @var resource|null */ protected $stream; /** @var ?string */ @@ -50,9 +54,26 @@ class StreamHandler extends AbstractProcessingHandler public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); + + if ($phpMemoryLimit = ini_get('memory_limit')) { + if (($memoryInByes = Utils::memoryIniValueToBytes($phpMemoryLimit))) { + $memoryUsage = memory_get_usage(true); + if (($memoryInByes - $memoryUsage) < $this->streamChunkSize) { + $this->streamChunkSize = $memoryInByes - $memoryUsage - self::SAFE_MEMORY_OFFSET; + } + } + } + if (is_resource($stream)) { $this->stream = $stream; - stream_set_chunk_size($this->stream, self::MAX_CHUNK_SIZE); + + try { + stream_set_chunk_size($this->stream, $this->streamChunkSize); + } catch (\Exception $exception) { + throw new \RuntimeException('Impossible to set the stream chunk size.' + .PHP_EOL.'Error: '.$exception->getMessage() + .PHP_EOL.'Trace: '.$exception->getTraceAsString()); + } } elseif (is_string($stream)) { $this->url = Utils::canonicalizePath($stream); } else { @@ -95,6 +116,14 @@ public function getUrl(): ?string return $this->url; } + /** + * @return int + */ + public function getStreamChunkSize() : int + { + return $this->streamChunkSize; + } + /** * {@inheritDoc} */ @@ -118,7 +147,7 @@ protected function write(array $record): void throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url)); } - stream_set_chunk_size($stream, self::MAX_CHUNK_SIZE); + stream_set_chunk_size($stream, $this->streamChunkSize); $this->stream = $stream; } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 8812f007d..28a7f334a 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -226,4 +226,52 @@ function ($m) { ); } } + + /** + * Converts a string with a valid 'memory_limit' format, to bytes. + * Reference: Function code from https://www.php.net/manual/en/function.ini-get.php + * @param string|int $val + * @return int|false Returns an integer representing bytes. Returns FALSE in case of error. + */ + public static function memoryIniValueToBytes($val) + { + if (!is_string($val) && !is_integer($val)) { + return false; + } + + $val = trim((string)$val); + + if (empty($val)) { + return false; + } + + $valLen = strlen($val); + $last = strtolower($val[$valLen - 1]); + + if (preg_match('/[a-zA-Z]/', $last)) { + if ($valLen == 1) { + return false; + } + + $val = substr($val, 0, -1); + } + + if (!is_numeric($val) || $val < 0) { + return false; + } + + //Lets be explicit here + $val = (int)($val); + + switch ($last) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + + return $val; + } } diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 8e0d111f0..8a9ae1846 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Handler\StreamHandler; use Monolog\Test\TestCase; use Monolog\Logger; @@ -220,4 +221,90 @@ public function provideNonExistingAndNotCreatablePath() ], ]; } + + public function provideMemoryValues() + { + return [ + ['1M', true], + ['10M', true], + ['1024M', true], + ['1G', true], + ['2000M', true], + ['2050M', true], + ['2048M', true], + ['3G', false], + ['2560M', false], + ]; + } + + /** + * @dataProvider provideMemoryValues + * @return void + */ + public function testPreventOOMError($phpMemory, $chunkSizeDecreased) + { + $memoryLimit = ini_set('memory_limit', $phpMemory); + + if ($memoryLimit === false) { + /* + * We could not set a memory limit that would trigger the error. + * There is no need to continue with this test. + */ + + $this->assertTrue(true); + return; + } + + $stream = tmpfile(); + + if ($stream === false) { + /* + * We could create a temp file to be use as a stream. + * There is no need to continue with this test. + */ + $this->assertTrue(true); + return; + } + + $exceptionRaised = false; + + try { + $handler = new StreamHandler($stream); + stream_get_contents($stream, 1024); + } catch (\RuntimeException $exception) { + /* + * At this point, stream_set_chunk_size() failed in the constructor. + * Probably because not enough memory. + * The rest of th test depends on the success pf stream_set_chunk_size(), that is why + * if exception is raised (which is true at this point), the rest of assertions will not be executed. + */ + $exceptionRaised = true; + } + + ini_set('memory_limit', $memoryLimit); + $this->assertEquals($memoryLimit, ini_get('memory_limit')); + + if (!$exceptionRaised) { + $this->assertEquals($chunkSizeDecreased, $handler->getStreamChunkSize() < StreamHandler::MAX_CHUNK_SIZE); + } + } + + /** + * @return void + */ + public function testSimpleOOMPrevention() + { + $previousValue = ini_set('memory_limit', '2048M'); + + if ($previousValue === false) { + $this->assertTrue(true); + return; + } + + $stream = tmpfile(); + new StreamHandler($stream); + stream_get_contents($stream); + ini_set('memory_limit', $previousValue); + $this->assertTrue(true); + } } diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index bc2164671..95d11fa5b 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -141,4 +141,47 @@ public function providesPcreLastErrorMessage() [-1, 'UNDEFINED_ERROR'], ]; } + + public function provideMemoryIniValuesToConvertToBytes() + { + return [ + ['1', 1], + ['2', 2], + ['2.5', 2], + ['2.9', 2], + ['1B', 1], + ['1X', 1], + ['1K', 1024], + ['1G', 1073741824], + ['', false], + [null, false], + ['A', false], + ['AA', false], + ['B', false], + ['BB', false], + ['G', false], + ['GG', false], + ['-1', false], + ['-123', false], + ['-1A', false], + ['-1B', false], + ['-123G', false], + ['-B', false], + ['-A', false], + ['-', false], + [true, false], + [false, false], + ]; + } + + /** + * @dataProvider provideMemoryIniValuesToConvertToBytes + * @param mixed $input + * @param int|false $expected + */ + public function testMemoryIniValueToBytes($input, $expected) + { + $result = Utils::memoryIniValueToBytes($input); + $this->assertEquals($expected, $result); + } } From 70fe0928675d1f1080a9d6496f549baf5ae482a9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 14 Sep 2021 13:44:02 +0200 Subject: [PATCH 359/498] Simplify memoryIniValueToBytes, tweak code to use less memory overall --- src/Monolog/Handler/StreamHandler.php | 28 ++++----- src/Monolog/Utils.php | 34 ++++------- tests/Monolog/Handler/StreamHandlerTest.php | 63 +++++++-------------- tests/Monolog/UtilsTest.php | 24 ++++---- 4 files changed, 53 insertions(+), 96 deletions(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 8d1189289..ec2519c11 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -26,9 +26,7 @@ class StreamHandler extends AbstractProcessingHandler { /** @const int */ - const SAFE_MEMORY_OFFSET = 1024; - /** @const int */ - const MAX_CHUNK_SIZE = 2147483647; + protected const MAX_CHUNK_SIZE = 100 * 1024 * 1024; /** @var int */ protected $streamChunkSize = self::MAX_CHUNK_SIZE; /** @var resource|null */ @@ -55,25 +53,21 @@ public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true { parent::__construct($level, $bubble); - if ($phpMemoryLimit = ini_get('memory_limit')) { - if (($memoryInByes = Utils::memoryIniValueToBytes($phpMemoryLimit))) { - $memoryUsage = memory_get_usage(true); - if (($memoryInByes - $memoryUsage) < $this->streamChunkSize) { - $this->streamChunkSize = $memoryInByes - $memoryUsage - self::SAFE_MEMORY_OFFSET; - } + if (($phpMemoryLimit = Utils::expandIniShorthandBytes(ini_get('memory_limit'))) !== false) { + if ($phpMemoryLimit > 0) { + // use max 10% of allowed memory for the chunk size + $this->streamChunkSize = max((int) ($phpMemoryLimit / 10), 10*1024); } + // else memory is unlimited, keep the buffer to the default 100MB + } else { + // no memory limit information, use a conservative 10MB + $this->streamChunkSize = 10*10*1024; } if (is_resource($stream)) { $this->stream = $stream; - try { - stream_set_chunk_size($this->stream, $this->streamChunkSize); - } catch (\Exception $exception) { - throw new \RuntimeException('Impossible to set the stream chunk size.' - .PHP_EOL.'Error: '.$exception->getMessage() - .PHP_EOL.'Trace: '.$exception->getTraceAsString()); - } + stream_set_chunk_size($this->stream, $this->streamChunkSize); } elseif (is_string($stream)) { $this->url = Utils::canonicalizePath($stream); } else { @@ -119,7 +113,7 @@ public function getUrl(): ?string /** * @return int */ - public function getStreamChunkSize() : int + public function getStreamChunkSize(): int { return $this->streamChunkSize; } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 28a7f334a..d3e7ad096 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -229,41 +229,27 @@ function ($m) { /** * Converts a string with a valid 'memory_limit' format, to bytes. - * Reference: Function code from https://www.php.net/manual/en/function.ini-get.php - * @param string|int $val + * + * @param string|false $val * @return int|false Returns an integer representing bytes. Returns FALSE in case of error. */ - public static function memoryIniValueToBytes($val) + public static function expandIniShorthandBytes($val) { - if (!is_string($val) && !is_integer($val)) { + if (!is_string($val)) { return false; } - $val = trim((string)$val); - - if (empty($val)) { - return false; + // support -1 + if ((int) $val < 0) { + return (int) $val; } - $valLen = strlen($val); - $last = strtolower($val[$valLen - 1]); - - if (preg_match('/[a-zA-Z]/', $last)) { - if ($valLen == 1) { - return false; - } - - $val = substr($val, 0, -1); - } - - if (!is_numeric($val) || $val < 0) { + if (!preg_match('/^\s*(?\d+)(?:\.\d+)?\s*(?[gmk]?)\s*$/i', $val, $match)) { return false; } - //Lets be explicit here - $val = (int)($val); - - switch ($last) { + $val = (int) $match['val']; + switch (strtolower($match['unit'] ?? '')) { case 'g': $val *= 1024; case 'm': diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 8a9ae1846..275aa9553 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -225,15 +225,15 @@ public function provideNonExistingAndNotCreatablePath() public function provideMemoryValues() { return [ - ['1M', true], - ['10M', true], - ['1024M', true], - ['1G', true], - ['2000M', true], - ['2050M', true], - ['2048M', true], - ['3G', false], - ['2560M', false], + ['1M', (int) (1024*1024/10)], + ['10M', (int) (1024*1024)], + ['1024M', (int) (1024*1024*1024/10)], + ['1G', (int) (1024*1024*1024/10)], + ['2000M', (int) (2000*1024*1024/10)], + ['2050M', (int) (2050*1024*1024/10)], + ['2048M', (int) (2048*1024*1024/10)], + ['3G', (int) (3*1024*1024*1024/10)], + ['2560M', (int) (2560*1024*1024/10)], ]; } @@ -241,52 +241,28 @@ public function provideMemoryValues() * @dataProvider provideMemoryValues * @return void */ - public function testPreventOOMError($phpMemory, $chunkSizeDecreased) + public function testPreventOOMError($phpMemory, $expectedChunkSize) { - $memoryLimit = ini_set('memory_limit', $phpMemory); + $previousValue = ini_set('memory_limit', $phpMemory); - if ($memoryLimit === false) { - /* - * We could not set a memory limit that would trigger the error. - * There is no need to continue with this test. - */ - - $this->assertTrue(true); - return; + if ($previousValue === false) { + $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } $stream = tmpfile(); if ($stream === false) { - /* - * We could create a temp file to be use as a stream. - * There is no need to continue with this test. - */ - $this->assertTrue(true); - return; + $this->markTestSkipped('We could not create a temp file to be use as a stream.'); } $exceptionRaised = false; - try { - $handler = new StreamHandler($stream); - stream_get_contents($stream, 1024); - } catch (\RuntimeException $exception) { - /* - * At this point, stream_set_chunk_size() failed in the constructor. - * Probably because not enough memory. - * The rest of th test depends on the success pf stream_set_chunk_size(), that is why - * if exception is raised (which is true at this point), the rest of assertions will not be executed. - */ - $exceptionRaised = true; - } + $handler = new StreamHandler($stream); + stream_get_contents($stream, 1024); - ini_set('memory_limit', $memoryLimit); - $this->assertEquals($memoryLimit, ini_get('memory_limit')); + ini_set('memory_limit', $previousValue); - if (!$exceptionRaised) { - $this->assertEquals($chunkSizeDecreased, $handler->getStreamChunkSize() < StreamHandler::MAX_CHUNK_SIZE); - } + $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); } /** @@ -297,8 +273,7 @@ public function testSimpleOOMPrevention() $previousValue = ini_set('memory_limit', '2048M'); if ($previousValue === false) { - $this->assertTrue(true); - return; + $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } $stream = tmpfile(); diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 95d11fa5b..aced3baf3 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -142,16 +142,18 @@ public function providesPcreLastErrorMessage() ]; } - public function provideMemoryIniValuesToConvertToBytes() + public function provideIniValuesToConvertToBytes() { return [ ['1', 1], ['2', 2], ['2.5', 2], ['2.9', 2], - ['1B', 1], - ['1X', 1], + ['1B', false], + ['1X', false], ['1K', 1024], + ['1 K', 1024], + [' 5 M ', 5*1024*1024], ['1G', 1073741824], ['', false], [null, false], @@ -161,11 +163,11 @@ public function provideMemoryIniValuesToConvertToBytes() ['BB', false], ['G', false], ['GG', false], - ['-1', false], - ['-123', false], - ['-1A', false], - ['-1B', false], - ['-123G', false], + ['-1', -1], + ['-123', -123], + ['-1A', -1], + ['-1B', -1], + ['-123G', -123], ['-B', false], ['-A', false], ['-', false], @@ -175,13 +177,13 @@ public function provideMemoryIniValuesToConvertToBytes() } /** - * @dataProvider provideMemoryIniValuesToConvertToBytes + * @dataProvider provideIniValuesToConvertToBytes * @param mixed $input * @param int|false $expected */ - public function testMemoryIniValueToBytes($input, $expected) + public function testExpandIniShorthandBytes($input, $expected) { - $result = Utils::memoryIniValueToBytes($input); + $result = Utils::expandIniShorthandBytes($input); $this->assertEquals($expected, $result); } } From 4b47204f781e77c64765711f800da0a9bc7bf9fb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 14 Sep 2021 15:07:52 +0200 Subject: [PATCH 360/498] Fix SocketHandler::getChunkSize return type, fixes #1570, closes #1576 --- src/Monolog/Handler/SocketHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index c98249e8b..a829f0578 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -36,7 +36,7 @@ class SocketHandler extends AbstractProcessingHandler private $writingTimeout = 10.0; /** @var ?int */ private $lastSentBytes = null; - /** @var int */ + /** @var ?int */ private $chunkSize = null; /** @var bool */ private $persistent = false; @@ -197,7 +197,7 @@ public function getWritingTimeout(): float /** * Get current chunk size */ - public function getChunkSize(): int + public function getChunkSize(): ?int { return $this->chunkSize; } From 493d7475e6a1fcfb2cd5c76049d9247b44a893de Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 14 Sep 2021 15:30:26 +0200 Subject: [PATCH 361/498] Fix type error --- src/Monolog/Handler/SocketHandler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index a829f0578..4e1410ab8 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -265,6 +265,10 @@ protected function streamSetChunkSize() throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource'); } + if (null === $this->chunkSize) { + throw new \LogicException('streamSetChunkSize called but $this->chunkSize is not set'); + } + return stream_set_chunk_size($this->resource, $this->chunkSize); } From 98730fb77fb2d6e1fb141ea123c4b2b33cf4e3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Barto=C5=A1?= Date: Tue, 14 Sep 2021 15:32:21 +0200 Subject: [PATCH 362/498] Add Nette integration to the README (#1585) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a46feeb3..e7104af7b 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. - [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog. - [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog. -- [Nette Framework](http://nette.org/en/) can be used with Monolog via [contributte/monolog](https://github.com/contributte/monolog) extension. +- [Nette Framework](http://nette.org/en/) is usable with Monolog via the [contributte/monolog](https://github.com/contributte/monolog) or [orisai/nette-monolog](https://github.com/orisai/nette-monolog) extensions. - [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog. - [FuelPHP](http://fuelphp.com/) comes out of the box with Monolog. - [Equip Framework](https://github.com/equip/framework) comes out of the box with Monolog. From 3962ebfe206ac7ce6c754c79e2fee0c64bf1818d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 14 Sep 2021 20:38:30 +0200 Subject: [PATCH 363/498] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f46977b..34aa44c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 2.3.3 (2021-09-14) + + * Fixed memory usage when using StreamHandler and calling stream_get_contents on the resource you passed to it (#1578, #1577) + * Fixed support for psr/log 2.x (#1587) + * Fixed some type annotations + ### 2.3.2 (2021-07-23) * Fixed compatibility with PHP 7.2 - 7.4 when experiencing PCRE errors (#1568) From 0f7935954820a0ebc4baf3f68beec844b760685f Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 15 Sep 2021 13:13:55 +0200 Subject: [PATCH 364/498] Allow psr/log 3 (#1589) Signed-off-by: Alexander M. Turek --- .github/workflows/continuous-integration.yml | 17 +++++------------ composer.json | 5 +++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 19806498c..5cb0839c2 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -51,10 +51,6 @@ jobs: key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - - name: Remove elasticsearch/elasticsearch on PHP 8 - if: "startsWith(matrix.php-version, '8.')" - run: 'composer remove elasticsearch/elasticsearch --dev --no-update' - - name: Add require for mongodb/mongodb to make tests runnable run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' @@ -62,10 +58,6 @@ jobs: if: "contains(matrix.dependencies, 'lowest')" run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" - - name: "Ensure psr/log v2 is installed" - if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" - run: composer require -W psr/log:^2 - - name: "Install latest dependencies" run: | composer update ${{ env.COMPOSER_FLAGS }} @@ -73,9 +65,10 @@ jobs: - name: "Run tests" run: "composer exec phpunit -- --verbose" - - name: "Run tests with rollbar" + - name: "Run tests with psr/log 3" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" run: | - composer require psr/log:'^1.1|^2' --no-update - composer require rollbar/rollbar:^1.3 --no-update + composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update psr/log:^3 composer update -W ${{ env.COMPOSER_FLAGS }} - composer exec phpunit -- --verbose --filter Rollbar + composer exec phpunit -- --verbose diff --git a/composer.json b/composer.json index 605f8d139..5372e4856 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ ], "require": { "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0" + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -27,6 +27,7 @@ "phpspec/prophecy": "^1.6.1", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", + "rollbar/rollbar": "^1.3", "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0", "phpstan/phpstan": "^0.12.91" @@ -55,7 +56,7 @@ "psr-4": {"Monolog\\": "tests/Monolog"} }, "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "extra": { "branch-alias": { From 18eb14b78a3e88fe6374708a522d9af65edaa74a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 15 Sep 2021 13:20:03 +0200 Subject: [PATCH 365/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34aa44c34..92d030324 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 2.3.4 (2021-09-15) + + * Fixed support for psr/log 3.x (#1589) + ### 2.3.3 (2021-09-14) * Fixed memory usage when using StreamHandler and calling stream_get_contents on the resource you passed to it (#1578, #1577) From 437e7a1c50044b92773b361af77620efb76fff59 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 15 Sep 2021 13:27:21 +0200 Subject: [PATCH 366/498] Adjust phpdoc to match the psr/log 3 interface, refs #1589 --- src/Monolog/Logger.php | 43 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index abc52029a..9fbf20527 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -17,6 +17,7 @@ use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; use Throwable; +use Stringable; /** * Monolog log channel @@ -482,14 +483,18 @@ public function getExceptionHandler(): ?callable * * This method allows for compatibility with common interfaces. * - * @param int|string $level The log level - * @param string $message The log message - * @param mixed[] $context The log context + * @param mixed $level The log level + * @param string|Stringable $message The log message + * @param mixed[] $context The log context * * @phpstan-param Level|LevelName|LogLevel::* $level */ public function log($level, $message, array $context = []): void { + if (!is_int($level) && !is_string($level)) { + throw new \InvalidArgumentException('$level is expected to be a string or int'); + } + $level = static::toMonologLevel($level); $this->addRecord($level, (string) $message, $context); @@ -500,8 +505,8 @@ public function log($level, $message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function debug($message, array $context = []): void { @@ -513,8 +518,8 @@ public function debug($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function info($message, array $context = []): void { @@ -526,8 +531,8 @@ public function info($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function notice($message, array $context = []): void { @@ -539,8 +544,8 @@ public function notice($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function warning($message, array $context = []): void { @@ -552,8 +557,8 @@ public function warning($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function error($message, array $context = []): void { @@ -565,8 +570,8 @@ public function error($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function critical($message, array $context = []): void { @@ -578,8 +583,8 @@ public function critical($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function alert($message, array $context = []): void { @@ -591,8 +596,8 @@ public function alert($message, array $context = []): void * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param mixed[] $context The log context + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ public function emergency($message, array $context = []): void { From 07a509ac766146cdad641c327e2b65d0307e1a85 Mon Sep 17 00:00:00 2001 From: Shawn Iwinski Date: Fri, 1 Oct 2021 16:25:14 -0400 Subject: [PATCH 367/498] Allow php-amqplib/php-amqplib v3 (#1595) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5372e4856..ccc4f6ed7 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "elasticsearch/elasticsearch": "^7", "mongodb/mongodb": "^1.8", "graylog2/gelf-php": "^1.4.2", - "php-amqplib/php-amqplib": "~2.4", + "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", "phpunit/phpunit": "^8.5", From f563e3159e494c5d9ebf7cfa4ec5c81b8b99675a Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 1 Oct 2021 22:46:08 +0200 Subject: [PATCH 368/498] Fix the composer.json (#1598) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ccc4f6ed7..020d278e9 100644 --- a/composer.json +++ b/composer.json @@ -68,8 +68,8 @@ "phpstan": "vendor/bin/phpstan analyse" }, "config": { + "lock": false, "sort-packages": true, "platform-check": false - }, - "lock": false + } } From 895066e60258abd955a95f4a325a8d2cc55317a8 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 1 Oct 2021 22:46:08 +0200 Subject: [PATCH 369/498] Fix the composer.json (#1598) --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d2deab7b8..aecc40f39 100644 --- a/composer.json +++ b/composer.json @@ -54,5 +54,7 @@ "test": "vendor/bin/phpunit", "phpstan": "vendor/bin/phpstan analyse" }, - "lock": false + "config": { + "lock": false + } } From 9d1fed4affc44c39ef8e62f98c220151b76a5453 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 1 Oct 2021 23:03:11 +0200 Subject: [PATCH 370/498] Fix insane-memory-limit handling in StreamHandler, fixes #1592 --- src/Monolog/Handler/StreamHandler.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index ec2519c11..2531d41b9 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -26,9 +26,11 @@ class StreamHandler extends AbstractProcessingHandler { /** @const int */ - protected const MAX_CHUNK_SIZE = 100 * 1024 * 1024; + protected const MAX_CHUNK_SIZE = 2147483647; + /** @const int 10MB */ + protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; /** @var int */ - protected $streamChunkSize = self::MAX_CHUNK_SIZE; + protected $streamChunkSize; /** @var resource|null */ protected $stream; /** @var ?string */ @@ -55,13 +57,15 @@ public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true if (($phpMemoryLimit = Utils::expandIniShorthandBytes(ini_get('memory_limit'))) !== false) { if ($phpMemoryLimit > 0) { - // use max 10% of allowed memory for the chunk size - $this->streamChunkSize = max((int) ($phpMemoryLimit / 10), 10*1024); + // use max 10% of allowed memory for the chunk size, and at least 100KB + $this->streamChunkSize = min(static::MAX_CHUNK_SIZE, max((int) ($phpMemoryLimit / 10), 100 * 1024)); + } else { + // memory is unlimited, set to the default 10MB + $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; } - // else memory is unlimited, keep the buffer to the default 100MB } else { - // no memory limit information, use a conservative 10MB - $this->streamChunkSize = 10*10*1024; + // no memory limit information, set to the default 10MB + $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; } if (is_resource($stream)) { From fd4380d6fc37626e2f799f29d91195040137eba9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 1 Oct 2021 23:08:31 +0200 Subject: [PATCH 371/498] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d030324..121380fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 2.3.5 (2021-10-01) + + * Fixed regression in StreamHandler since 2.3.3 on systems with the memory_limit set to >=20GB (#1592) + ### 2.3.4 (2021-09-15) * Fixed support for psr/log 3.x (#1589) From d1c28292689764504cbaab2beec8ddd0a54bcc1c Mon Sep 17 00:00:00 2001 From: Juan Morales Date: Sat, 2 Oct 2021 22:05:18 +0200 Subject: [PATCH 372/498] Documentation. Enrich documentation on "Customizing log format". (#1575) Co-authored-by: jcm --- doc/01-usage.md | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index 50e5ad13a..2eae04181 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -190,31 +190,48 @@ $securityLogger = $logger->withName('security'); ## Customizing the log format In Monolog it's easy to customize the format of the logs written into files, -sockets, mails, databases and other handlers. Most of the handlers use the +sockets, mails, databases and other handlers; by the use of "Formatters". +As mentioned before, a *Formatter* is attached to a *Handler*, and as a general convention, most of the handlers use the ```php $record['formatted'] ``` +field in the log record to store its formatted value. Again, this field depends on the implemenation of the *Handler* but is a good idea to **stick into the good practices and conventions of the project**. -value to be automatically put into the log device. This value depends on the -formatter settings. You can choose between predefined formatter classes or -write your own (e.g. a multiline text file for human-readable output). +You can choose between predefined formatter classes or write your own (e.g. a multiline text file for human-readable output). -To configure a predefined formatter class, just set it as the handler's field: +> Note: +> +> A very useful formatter to look at, is the `LineFormatter`. +> +> This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. +> +> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be render as part of th final result. + +In the following example, we demonstrate how to: +1. Create a `LineFormatter` instance and set a custom output format template. +2. Create a new *Handler*. +3. Attach the *Formatter* to the *Handler*. +4. Create a new *Logger* object. +5. Attach the *Handler* to the *Logger* object. ```php %level_name% > %message% %context% %extra%\n"; + // finally, create a formatter $formatter = new LineFormatter($output, $dateFormat); // Create a handler $stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG); $stream->setFormatter($formatter); + // bind it to a logger object $securityLogger = new Logger('security'); $securityLogger->pushHandler($stream); From 4a11cadb275fa3af3c1e631c01d2a30bd6544b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20B=C3=B6sing?= <2189546+boesing@users.noreply.github.com> Date: Wed, 13 Oct 2021 22:29:04 +0200 Subject: [PATCH 373/498] Add constructor injection for `SocketHandler` and its children (#1600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: add constructor injection for `SocketHandler` and its children Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com> * docs: add parameter documentation to `SocketHandler#__construct` Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com> --- src/Monolog/Handler/FleepHookHandler.php | 23 ++++++++++-- src/Monolog/Handler/FlowdockHandler.php | 23 ++++++++++-- src/Monolog/Handler/InsightOpsHandler.php | 25 +++++++++++-- src/Monolog/Handler/LogEntriesHandler.php | 25 +++++++++++-- src/Monolog/Handler/LogmaticHandler.php | 26 ++++++++++++-- src/Monolog/Handler/PushoverHandler.php | 18 ++++++++-- src/Monolog/Handler/SlackHandler.php | 18 ++++++++-- src/Monolog/Handler/SocketHandler.php | 43 ++++++++++++++++++----- 8 files changed, 174 insertions(+), 27 deletions(-) diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 6194283a8..85c95b9d7 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -45,8 +45,16 @@ class FleepHookHandler extends SocketHandler * @param string $token Webhook token * @throws MissingExtensionException */ - public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) - { + public function __construct( + string $token, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler'); } @@ -54,7 +62,16 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble $this->token = $token; $connectionString = 'ssl://' . static::FLEEP_HOST . ':443'; - parent::__construct($connectionString, $level, $bubble); + parent::__construct( + $connectionString, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); } /** diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index a632c8623..b837bdb66 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -39,13 +39,30 @@ class FlowdockHandler extends SocketHandler /** * @throws MissingExtensionException if OpenSSL is missing */ - public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubble = true) - { + public function __construct( + string $apiToken, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); } - parent::__construct('ssl://api.flowdock.com:443', $level, $bubble); + parent::__construct( + 'ssl://api.flowdock.com:443', + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->apiToken = $apiToken; } diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index c62dc24d9..71f64a267 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -33,8 +33,18 @@ class InsightOpsHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct(string $token, string $region = 'us', bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) - { + public function __construct( + string $token, + string $region = 'us', + bool $useSSL = true, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler'); } @@ -43,7 +53,16 @@ public function __construct(string $token, string $region = 'us', bool $useSSL = ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443' : $region . '.data.logs.insight.rapid7.com:80'; - parent::__construct($endpoint, $level, $bubble); + parent::__construct( + $endpoint, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->logToken = $token; } diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index a0739cf04..25fcd1594 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -30,14 +30,33 @@ class LogEntriesHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct(string $token, bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true, string $host = 'data.logentries.com') - { + public function __construct( + string $token, + bool $useSSL = true, + $level = Logger::DEBUG, + bool $bubble = true, + string $host = 'data.logentries.com', + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); } $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80'; - parent::__construct($endpoint, $level, $bubble); + parent::__construct( + $endpoint, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->logToken = $token; } diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index e7666eca4..859a46906 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -43,8 +43,19 @@ class LogmaticHandler extends SocketHandler * * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing */ - public function __construct(string $token, string $hostname = '', string $appname = '', bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) - { + public function __construct( + string $token, + string $hostname = '', + string $appname = '', + bool $useSSL = true, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if ($useSSL && !extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use SSL encrypted connection for LogmaticHandler'); } @@ -52,7 +63,16 @@ public function __construct(string $token, string $hostname = '', string $appnam $endpoint = $useSSL ? 'ssl://api.logmatic.io:10515' : 'api.logmatic.io:10514'; $endpoint .= '/v1/'; - parent::__construct($endpoint, $level, $bubble); + parent::__construct( + $endpoint, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->logToken = $token; $this->hostname = $hostname; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 255af5c06..fed2303d7 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -108,10 +108,24 @@ public function __construct( $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, int $retry = 30, - int $expire = 25200 + int $expire = 25200, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null ) { $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; - parent::__construct($connectionString, $level, $bubble); + parent::__construct( + $connectionString, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->token = $token; $this->users = (array) $users; diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 46d69a6d2..a648513e0 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -59,13 +59,27 @@ public function __construct( bool $bubble = true, bool $useShortAttachment = false, bool $includeContextAndExtra = false, - array $excludeFields = array() + array $excludeFields = array(), + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); } - parent::__construct('ssl://slack.com:443', $level, $bubble); + parent::__construct( + 'ssl://slack.com:443', + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->slackRecord = new SlackRecord( $channel, diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 4e1410ab8..21701afa2 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -31,15 +31,15 @@ class SocketHandler extends AbstractProcessingHandler /** @var resource|null */ private $resource; /** @var float */ - private $timeout = 0.0; + private $timeout; /** @var float */ - private $writingTimeout = 10.0; + private $writingTimeout; /** @var ?int */ private $lastSentBytes = null; /** @var ?int */ - private $chunkSize = null; + private $chunkSize; /** @var bool */ - private $persistent = false; + private $persistent; /** @var ?int */ private $errno = null; /** @var ?string */ @@ -48,13 +48,40 @@ class SocketHandler extends AbstractProcessingHandler private $lastWritingAt = null; /** - * @param string $connectionString Socket connection string + * @param string $connectionString Socket connection string + * @param bool $persistent Flag to enable/disable persistent connections + * @param float $timeout Socket timeout to wait until the request is being aborted + * @param float $writingTimeout Socket timeout to wait until the request should've been sent/written + * @param float|null $connectionTimeout Socket connect timeout to wait until the connection should've been + * 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. */ - public function __construct(string $connectionString, $level = Logger::DEBUG, bool $bubble = true) - { + public function __construct( + string $connectionString, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { parent::__construct($level, $bubble); $this->connectionString = $connectionString; - $this->connectionTimeout = (float) ini_get('default_socket_timeout'); + + if ($connectionTimeout !== null) { + $this->validateTimeout($connectionTimeout); + } + + $this->connectionTimeout = $connectionTimeout ?? (float) ini_get('default_socket_timeout'); + $this->persistent = $persistent; + $this->validateTimeout($timeout); + $this->timeout = $timeout; + $this->validateTimeout($writingTimeout); + $this->writingTimeout = $writingTimeout; + $this->chunkSize = $chunkSize; } /** From df8f91bfefb331c0077eb30d845f82d3347a06aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Mon, 18 Oct 2021 13:37:56 +0200 Subject: [PATCH 374/498] Fix old class name (#1604) --- doc/02-handlers-formatters-processors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index c4db5d08c..342eac7b9 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -150,7 +150,7 @@ - [_ChromePHPFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ChromePHPFormatter.php): Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler. - [_GelfMessageFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/GelfMessageFormatter.php): Used to format log records into Gelf message instances, only useful for the GelfHandler. - [_LogstashFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogstashFormatter.php): Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest). -- [_ElasticaFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ElasticaFormatter.php): Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler. +- [_ElasticaFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ElasticaFormatter.php): Used to format log records into an Elastica\Document object, only useful for the ElasticaHandler. - [_LogglyFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogglyFormatter.php): Used to format log records into Loggly messages, only useful for the LogglyHandler. - [_FlowdockFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. - [_MongoDBFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. From f19a2ae873d42f4494f3fb29de9dadb91a3f7601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20J=2E=20Garc=C3=ADa=20Lagar?= Date: Mon, 18 Oct 2021 23:44:22 +0200 Subject: [PATCH 375/498] Add missed classes (#1605) --- doc/02-handlers-formatters-processors.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 342eac7b9..181805faa 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -82,6 +82,7 @@ [Mongo](http://pecl.php.net/package/mongo) extension connection. - [_CouchDBHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/CouchDBHandler.php): Logs records to a CouchDB server. - [_DoctrineCouchDBHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/DoctrineCouchDBHandler.php): Logs records to a CouchDB server via the Doctrine CouchDB ODM. +- [_ElasticaHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ElasticaHandler.php): Logs records to an Elasticsearch server using [ruflin/elastica](https://elastica.io/). - [_ElasticsearchHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ElasticsearchHandler.php): Logs records to an Elasticsearch server. - [_DynamoDbHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/DynamoDbHandler.php): Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php). @@ -151,6 +152,7 @@ - [_GelfMessageFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/GelfMessageFormatter.php): Used to format log records into Gelf message instances, only useful for the GelfHandler. - [_LogstashFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogstashFormatter.php): Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/latest). - [_ElasticaFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ElasticaFormatter.php): Used to format log records into an Elastica\Document object, only useful for the ElasticaHandler. +- [_ElasticsearchFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/ElasticsearchFormatter.php): Used to add index and type keys to log records, only useful for the ElasticsearchHandler. - [_LogglyFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogglyFormatter.php): Used to format log records into Loggly messages, only useful for the LogglyHandler. - [_FlowdockFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FlowdockFormatter.php): Used to format log records into Flowdock messages, only useful for the FlowdockHandler. - [_MongoDBFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. From fb2c324c17941ffe805aa7c953895af96840d0c9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 15 Nov 2021 09:08:41 +0100 Subject: [PATCH 376/498] Update scripts to latest Composer syntax --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 020d278e9..c671df1ec 100644 --- a/composer.json +++ b/composer.json @@ -64,8 +64,8 @@ } }, "scripts": { - "test": "vendor/bin/phpunit", - "phpstan": "vendor/bin/phpstan analyse" + "test": "@php vendor/bin/phpunit", + "phpstan": "@php vendor/bin/phpstan analyse" }, "config": { "lock": false, From 4b34c2893fd0e71177955adbf6b3834f0dfb8f4d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 6 Mar 2022 13:08:08 +0100 Subject: [PATCH 377/498] Avoid linting file which is problematic on php 7.2 --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9e20a03ea..cd260475a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,4 +29,4 @@ jobs: php-version: "${{ matrix.php-version }}" - name: "Lint PHP files" - run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" + run: "find src/ -type f -name '*.php' -not -name AsMonologProcessor.php -print0 | xargs -0 -L1 -P4 -- php -l -f" From 8c58abad9ef83481aabed8394ff8d391a2a9409a Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Sun, 6 Mar 2022 13:08:33 +0100 Subject: [PATCH 378/498] Add AsMonologProcessor attribute (#1637) --- src/Monolog/Attribute/AsMonologProcessor.php | 36 +++++++++++++++++++ .../Attribute/AsMonologProcessorTest.php | 33 +++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/Monolog/Attribute/AsMonologProcessor.php create mode 100644 tests/Monolog/Attribute/AsMonologProcessorTest.php diff --git a/src/Monolog/Attribute/AsMonologProcessor.php b/src/Monolog/Attribute/AsMonologProcessor.php new file mode 100644 index 000000000..b52d07761 --- /dev/null +++ b/src/Monolog/Attribute/AsMonologProcessor.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +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 +{ + /** + * @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 ?string $channel = null, + public ?string $handler = null, + public ?string $method = null, + ) { + } +} \ No newline at end of file diff --git a/tests/Monolog/Attribute/AsMonologProcessorTest.php b/tests/Monolog/Attribute/AsMonologProcessorTest.php new file mode 100644 index 000000000..fe93d2801 --- /dev/null +++ b/tests/Monolog/Attribute/AsMonologProcessorTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Attribute; + +use PHPUnit\Framework\TestCase; + +/** + * @requires PHP 8.0 + */ +final class AsMonologProcessorTest extends TestCase +{ + public function test(): void + { + $asMonologProcessor = new AsMonologProcessor('channel', 'handler', 'method'); + $this->assertSame('channel', $asMonologProcessor->channel); + $this->assertSame('handler', $asMonologProcessor->handler); + $this->assertSame('method', $asMonologProcessor->method); + + $asMonologProcessor = new AsMonologProcessor(null, null, null); + $this->assertNull($asMonologProcessor->channel); + $this->assertNull($asMonologProcessor->handler); + $this->assertNull($asMonologProcessor->method); + } +} \ No newline at end of file From 030c25c4d239de98172bdb0e23cbeb1e564a5e36 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Sun, 6 Mar 2022 13:09:40 +0100 Subject: [PATCH 379/498] Addition of a new framework (#1610) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e7104af7b..61d39cf89 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. - [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. - [SilverStripe 4](https://www.silverstripe.org/) comes out of the box with Monolog. +- [Magento](https://magento.com/) comes out of the box with Monolog. ### Author From 5129feea3e35cc3243e80c8a2e33872af6e3eb62 Mon Sep 17 00:00:00 2001 From: Alex Jose Date: Sun, 6 Mar 2022 17:57:57 +0530 Subject: [PATCH 380/498] Added user_agent to the WebProcessor (#1613) --- src/Monolog/Processor/WebProcessor.php | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 64d251d70..51850e17f 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -36,11 +36,12 @@ class WebProcessor implements ProcessorInterface 'http_method' => 'REQUEST_METHOD', 'server' => 'SERVER_NAME', 'referrer' => 'HTTP_REFERER', + 'user_agent' => 'HTTP_USER_AGENT', ]; /** * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer + * @param array|array|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($serverData = null, array $extraFields = null) { @@ -52,20 +53,23 @@ public function __construct($serverData = null, array $extraFields = null) throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); } + $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer']; if (isset($this->serverData['UNIQUE_ID'])) { $this->extraFields['unique_id'] = 'UNIQUE_ID'; + $defaultEnabled[] = 'unique_id'; } - if (null !== $extraFields) { - if (isset($extraFields[0])) { - foreach (array_keys($this->extraFields) as $fieldName) { - if (!in_array($fieldName, $extraFields)) { - unset($this->extraFields[$fieldName]); - } + if (null === $extraFields) { + $extraFields = $defaultEnabled; + } + if (isset($extraFields[0])) { + foreach (array_keys($this->extraFields) as $fieldName) { + if (!in_array($fieldName, $extraFields)) { + unset($this->extraFields[$fieldName]); } - } else { - $this->extraFields = $extraFields; } + } else { + $this->extraFields = $extraFields; } } From 4a32baade5d11a840cfe4adb099157351cff8855 Mon Sep 17 00:00:00 2001 From: Aimeos Date: Sun, 6 Mar 2022 13:36:15 +0100 Subject: [PATCH 381/498] Added Aimeos as Monolog supporter to framework integration section (#1622) Co-authored-by: Jordi Boggiano --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 61d39cf89..b89e0390e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. - [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. - [SilverStripe 4](https://www.silverstripe.org/) comes out of the box with Monolog. +- [Aimeos ecommerce framework](https://aimeos.org/) is usable with Monolog via the [ai-monolog](https://github.com/aimeos/ai-monolog) extension. - [Magento](https://magento.com/) comes out of the box with Monolog. ### Author From c295434c248d9642b48b8e8be5519912e6591092 Mon Sep 17 00:00:00 2001 From: Lusso Luca Date: Sun, 6 Mar 2022 13:37:10 +0100 Subject: [PATCH 382/498] Add Drupal integration to the README (#1639) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b89e0390e..bfcae0c00 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. - [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. - [SilverStripe 4](https://www.silverstripe.org/) comes out of the box with Monolog. +- [Drupal](https://www.drupal.org/) is usable with Monolog via the [monolog](https://www.drupal.org/project/monolog) module. - [Aimeos ecommerce framework](https://aimeos.org/) is usable with Monolog via the [ai-monolog](https://github.com/aimeos/ai-monolog) extension. - [Magento](https://magento.com/) comes out of the box with Monolog. From c0ae5884370312fc58231d5ca200e30fdd45236e Mon Sep 17 00:00:00 2001 From: gnito-org <70450336+gnito-org@users.noreply.github.com> Date: Sun, 6 Mar 2022 10:12:11 -0400 Subject: [PATCH 383/498] Fix minor spelling & grammar issues in docs (#1623) --- doc/01-usage.md | 10 +++++----- doc/02-handlers-formatters-processors.md | 10 +++++----- doc/message-structure.md | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index 2eae04181..e23d87693 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -127,7 +127,7 @@ $logger->info('Adding a new user', ['username' => 'Seldaek']); Simple handlers (like the StreamHandler for instance) will simply format the array to a string but richer handlers can take advantage of the context -(FirePHP is able to display arrays in pretty way for instance). +(FirePHP is able to display arrays in a pretty way for instance). ### Using processors @@ -196,7 +196,7 @@ As mentioned before, a *Formatter* is attached to a *Handler*, and as a general ```php $record['formatted'] ``` -field in the log record to store its formatted value. Again, this field depends on the implemenation of the *Handler* but is a good idea to **stick into the good practices and conventions of the project**. +field in the log record to store its formatted value. Again, this field depends on the implementation of the *Handler* but is a good idea to **stick into the good practices and conventions of the project**. You can choose between predefined formatter classes or write your own (e.g. a multiline text file for human-readable output). @@ -205,8 +205,8 @@ You can choose between predefined formatter classes or write your own (e.g. a mu > A very useful formatter to look at, is the `LineFormatter`. > > This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. -> -> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be render as part of th final result. +> +> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be render as part of the final result. In the following example, we demonstrate how to: 1. Create a `LineFormatter` instance and set a custom output format template. @@ -222,7 +222,7 @@ In the following example, we demonstrate how to: $dateFormat = "Y n j, g:i a"; // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" -// we now change the default output format according our needs. +// we now change the default output format according to our needs. $output = "%datetime% > %level_name% > %message% %context% %extra%\n"; // finally, create a formatter diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 181805faa..d999c146a 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -16,7 +16,7 @@ ### Log to files and syslog - [_StreamHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/StreamHandler.php): Logs records into any PHP stream, use this for log files. -- [_RotatingFileHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RotatingFileHandler.php): Logs records to a file and creates one logfile per day. +- [_RotatingFileHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RotatingFileHandler.php): Logs records to a file and creates one log file per day. It will also delete files older than `$maxFiles`. You should use [logrotate](https://linux.die.net/man/8/logrotate) for high profile setups though, this is just meant as a quick and dirty solution. @@ -111,10 +111,10 @@ where a remote tcp connection may have died but you do not want your entire application to crash and may wish to continue to log to other handlers. - [_FallbackGroupHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FallbackGroupHandler.php): This handler extends the _GroupHandler_ ignoring - exceptions raised by each child handler, until one has handled without throwing. - This allows you to ignore issues where a remote tcp connection may have died - but you do not want your entire application to crash and may wish to continue - to attempt log to other handlers, until one does not throw. + exceptions raised by each child handler, until one has handled without throwing. + This allows you to ignore issues where a remote tcp connection may have died + but you do not want your entire application to crash and may wish to continue + to attempt logging to other handlers, until one does not throw an exception. - [_BufferHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/BufferHandler.php): This handler will buffer all the log records it receives until `close()` is called at which point it will call `handleBatch()` on the handler it wraps with all the log messages at once. This is very useful to diff --git a/doc/message-structure.md b/doc/message-structure.md index 571df4190..985e0faa5 100644 --- a/doc/message-structure.md +++ b/doc/message-structure.md @@ -15,4 +15,4 @@ extra | array | A placeholder array where processors ca At first glance `context` and `extra` look very similar, and they are in the sense that they both carry arbitrary data that is related to the log message somehow. The main difference is that `context` can be supplied in user land (it is the 3rd parameter to `Logger::addRecord()`) whereas `extra` is internal only and can be filled by processors. -The reason processors write to `extra` and not to `context` is to prevent overriding any user provided data in `context`. +The reason processors write to `extra` and not to `context` is to prevent overriding any user-provided data in `context`. From 16cc886c02048869a5e2eb7c17db9ab4ea5e168d Mon Sep 17 00:00:00 2001 From: Koen Kivits Date: Mon, 7 Mar 2022 14:11:30 +0100 Subject: [PATCH 384/498] Fix ErrorHandler::handleError $context signature (#1614) The context can be null, eg. for internal PHP errors. --- src/Monolog/ErrorHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index e7d244bba..16794be65 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -210,7 +210,7 @@ private function handleException(\Throwable $e): void * * @param mixed[] $context */ - public function handleError(int $code, string $message, string $file = '', int $line = 0, array $context = []): bool + public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []): bool { if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { return false; From 168bb6e53da3b4838b16048e61e02547b9ca2d14 Mon Sep 17 00:00:00 2001 From: smiley Date: Mon, 7 Mar 2022 14:24:20 +0100 Subject: [PATCH 385/498] return self on several setter/builder methods for more consistent behaviour (#1609) --- src/Monolog/Formatter/JsonFormatter.php | 6 ++++-- src/Monolog/Formatter/LineFormatter.php | 12 +++++++++--- src/Monolog/Formatter/NormalizerFormatter.php | 8 ++++++-- src/Monolog/Logger.php | 4 +++- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 46592ba96..6b1a10e52 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -109,11 +109,13 @@ public function formatBatch(array $records): string } /** - * @return void + * @return self */ - public function includeStacktraces(bool $include = true) + public function includeStacktraces(bool $include = true): self { $this->includeStacktraces = $include; + + return $this; } /** diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 6ed817aba..55272a5b7 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -48,22 +48,28 @@ public function __construct(?string $format = null, ?string $dateFormat = null, parent::__construct($dateFormat); } - public function includeStacktraces(bool $include = true): void + public function includeStacktraces(bool $include = true): self { $this->includeStacktraces = $include; if ($this->includeStacktraces) { $this->allowInlineLineBreaks = true; } + + return $this; } - public function allowInlineLineBreaks(bool $allow = true): void + public function allowInlineLineBreaks(bool $allow = true): self { $this->allowInlineLineBreaks = $allow; + + return $this; } - public function ignoreEmptyContextAndExtra(bool $ignore = true): void + public function ignoreEmptyContextAndExtra(bool $ignore = true): self { $this->ignoreEmptyContextAndExtra = $ignore; + + return $this; } /** diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 01f75a42c..0c6227150 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -267,13 +267,17 @@ protected function formatDate(\DateTimeInterface $date) return $date->format($this->dateFormat); } - public function addJsonEncodeOption(int $option): void + public function addJsonEncodeOption(int $option): self { $this->jsonEncodeOptions |= $option; + + return $this; } - public function removeJsonEncodeOption(int $option): void + public function removeJsonEncodeOption(int $option): self { $this->jsonEncodeOptions &= ~$option; + + return $this; } } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 9fbf20527..90b6c7fad 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -272,9 +272,11 @@ public function getProcessors(): array * * @param bool $micro True to use microtime() to create timestamps */ - public function useMicrosecondTimestamps(bool $micro): void + public function useMicrosecondTimestamps(bool $micro): self { $this->microsecondTimestamps = $micro; + + return $this; } /** From 832660ec683234112a28fbcac721d07ab578618f Mon Sep 17 00:00:00 2001 From: Eugene Ivanov <93479789+evgeek@users.noreply.github.com> Date: Mon, 7 Mar 2022 16:37:10 +0300 Subject: [PATCH 386/498] Handling the maximum length of a Telegram message (#1616) * Handling the maximum length of a Telegram message The maximum allowed length of a Telegram message - 4096 symbols (https://core.telegram.org/bots/api#message, 'text' field). Longer messages are not delivered. Therefore, I implemented splitting too long message into several (with a 1 second delay between sending according to the documentation - https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this) as the default behavior. An additional option that you can enable by truncateLongMessage is to leave one message, but truncate it to the maximum length allowed. * Changed handling of long messages (default - truncation, delay - optional) * PSR-12 code formatting --- src/Monolog/Handler/TelegramBotHandler.php | 93 ++++++++++++++++++++-- 1 file changed, 86 insertions(+), 7 deletions(-) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 9ea057371..e8c818fe0 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -43,6 +43,11 @@ class TelegramBotHandler extends AbstractProcessingHandler 'Markdown', // legacy mode without underline and strikethrough, use MarkdownV2 instead ]; + /** + * The maximum number of characters allowed in a message according to the Telegram api documentation + */ + private const MAX_MESSAGE_LENGTH = 4096; + /** * Telegram bot access token provided by BotFather. * Create telegram bot with https://telegram.me/BotFather and use access token from it. @@ -78,18 +83,37 @@ class TelegramBotHandler extends AbstractProcessingHandler private $disableNotification; /** - * @param string $apiKey Telegram bot access token provided by BotFather + * 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 $splitLongMessages; + + /** + * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). + * @var bool + */ + 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 + * @throws MissingExtensionException */ public function __construct( string $apiKey, string $channel, - $level = Logger::DEBUG, - bool $bubble = true, + $level = Logger::DEBUG, + bool $bubble = true, string $parseMode = null, - bool $disableWebPagePreview = null, - bool $disableNotification = 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'); } @@ -101,6 +125,8 @@ public function __construct( $this->setParseMode($parseMode); $this->disableWebPagePreview($disableWebPagePreview); $this->disableNotification($disableNotification); + $this->splitLongMessages($splitLongMessages); + $this->delayBetweenMessages($delayBetweenMessages); } public function setParseMode(string $parseMode = null): self @@ -128,6 +154,31 @@ public function disableNotification(bool $disableNotification = null): self return $this; } + /** + * 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 + { + $this->splitLongMessages = $splitLongMessages; + + return $this; + } + + /** + * 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 + { + $this->delayBetweenMessages = $delayBetweenMessages; + + return $this; + } + /** * {@inheritDoc} */ @@ -150,7 +201,7 @@ public function handleBatch(array $records): void } if (!empty($messages)) { - $this->send((string) $this->getFormatter()->formatBatch($messages)); + $this->send((string)$this->getFormatter()->formatBatch($messages)); } } @@ -167,6 +218,19 @@ protected function write(array $record): void * @param string $message */ protected function send(string $message): void + { + $messages = $this->handleMessageLength($message); + + foreach ($messages as $key => $msg) { + if ($this->delayBetweenMessages && $key > 0) { + sleep(1); + } + + $this->sendCurl($msg); + } + } + + protected function sendCurl(string $message): void { $ch = curl_init(); $url = self::BOT_API . $this->apiKey . '/SendMessage'; @@ -191,4 +255,19 @@ protected function send(string $message): void throw new RuntimeException('Telegram API error. Description: ' . $result['description']); } } + + /** + * Handle a message that is too long: truncates or splits into several + * @param string $message + * @return string[] + */ + private function handleMessageLength(string $message): array + { + $truncatedMarker = ' (...truncated)'; + if (!$this->splitLongMessages && strlen($message) > self::MAX_MESSAGE_LENGTH) { + return [substr($message, 0, self::MAX_MESSAGE_LENGTH - strlen($truncatedMarker)) . $truncatedMarker]; + } + + return str_split($message, self::MAX_MESSAGE_LENGTH); + } } From baf2d9d4a7b7e33523646cba531352032b52c0c8 Mon Sep 17 00:00:00 2001 From: Anatoly Pashin Date: Mon, 7 Mar 2022 23:50:57 +1000 Subject: [PATCH 387/498] Check whether graylog2/gelf-php is installed in GelfMessageFormatter constructor (#1624) --- src/Monolog/Formatter/GelfMessageFormatter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index a563a1ea0..a1a79372d 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -67,6 +67,10 @@ class GelfMessageFormatter extends NormalizerFormatter public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null) { + if (!class_exists(Message::class)) { + throw new \RuntimeException('Composer package graylog2/gelf-php is required to use Monolog\'s GelfMessageFormatter'); + } + parent::__construct('U.u'); $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName; From f9a8e87563f4b4011d2e948f1c299137a6e5dfca Mon Sep 17 00:00:00 2001 From: Bei Xiao Date: Sun, 13 Mar 2022 21:29:18 +0200 Subject: [PATCH 388/498] SlackWebhookHandler: use footer for username & footer_icon for userIcon (#1617) * Use footer for username & footer_icon for userIcon * Update test case for SlackWebhookHandler --- src/Monolog/Handler/Slack/SlackRecord.php | 14 +++--- .../Handler/SlackWebhookHandlerTest.php | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 13c3a1021..71a410946 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -146,12 +146,14 @@ public function getSlackData(array $record): array if ($this->useAttachment) { $attachment = array( - 'fallback' => $message, - 'text' => $message, - 'color' => $this->getAttachmentColor($record['level']), - 'fields' => array(), - 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp(), + '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) { diff --git a/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/tests/Monolog/Handler/SlackWebhookHandlerTest.php index 8ce721086..36990ebfd 100644 --- a/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ b/tests/Monolog/Handler/SlackWebhookHandlerTest.php @@ -51,6 +51,8 @@ public function testConstructorMinimal() 'title' => 'Message', 'mrkdwn_in' => array('fields'), 'ts' => $record['datetime']->getTimestamp(), + 'footer' => null, + 'footer_icon' => null, ), ), ), $slackRecord->getSlackData($record)); @@ -84,6 +86,53 @@ public function testConstructorFull() ), $slackRecord->getSlackData($this->getRecord())); } + /** + * @covers ::__construct + * @covers ::getSlackRecord + */ + public function testConstructorFullWithAttachment() + { + $handler = new SlackWebhookHandler( + self::WEBHOOK_URL, + 'test-channel-with-attachment', + 'test-username-with-attachment', + true, + 'https://www.example.com/example.png', + false, + false, + Logger::DEBUG, + false + ); + + $record = $this->getRecord(); + $slackRecord = $handler->getSlackRecord(); + $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); + $this->assertEquals(array( + 'username' => 'test-username-with-attachment', + 'channel' => 'test-channel-with-attachment', + 'attachments' => array( + array( + 'fallback' => 'test', + 'text' => 'test', + 'color' => SlackRecord::COLOR_WARNING, + 'fields' => array( + array( + 'title' => 'Level', + 'value' => Logger::getLevelName(Logger::WARNING), + 'short' => false, + ), + ), + 'mrkdwn_in' => array('fields'), + 'ts' => $record['datetime']->getTimestamp(), + 'footer' => 'test-username-with-attachment', + 'footer_icon' => 'https://www.example.com/example.png', + 'title' => 'Message', + ), + ), + 'icon_url' => 'https://www.example.com/example.png', + ), $slackRecord->getSlackData($record)); + } + /** * @covers ::getFormatter */ From 6f233d2e2fc38378670db62640f630fdd7c8321f Mon Sep 17 00:00:00 2001 From: Yurun Date: Mon, 14 Mar 2022 03:31:19 +0800 Subject: [PATCH 389/498] Remove unused variable (#1628) --- src/Monolog/Logger.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 90b6c7fad..1f4ef7f1a 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -291,7 +291,6 @@ public function useMicrosecondTimestamps(bool $micro): self */ public function addRecord(int $level, string $message, array $context = []): bool { - $offset = 0; $record = null; foreach ($this->handlers as $handler) { From 56899afff929b7b1348b640ef81152e3118fcbd8 Mon Sep 17 00:00:00 2001 From: Bruno Baguette Date: Sun, 13 Mar 2022 21:01:11 +0100 Subject: [PATCH 390/498] Typo fixes + fix of a broken (404 error) link (#1619) --- doc/01-usage.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index e23d87693..52deef6d4 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -44,7 +44,7 @@ incoming records so that they can be used by the handlers to output useful information. Custom severity levels are not available. Only the eight -[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice, +[RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424) levels (debug, info, notice, warning, error, critical, alert, emergency) are present for basic filtering purposes, but for sorting and other use cases that would require flexibility, you should add Processors to the Logger that can add extra @@ -52,7 +52,7 @@ information (tags, user ip, ..) to the records before they are handled. ## Log Levels -Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424). +Monolog supports the logging levels described by [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424). - **DEBUG** (100): Detailed debug information. @@ -205,8 +205,8 @@ You can choose between predefined formatter classes or write your own (e.g. a mu > A very useful formatter to look at, is the `LineFormatter`. > > This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. -> -> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be render as part of the final result. +> +> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'", in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be rendered as part of the final result. In the following example, we demonstrate how to: 1. Create a `LineFormatter` instance and set a custom output format template. From b39a394c0596522e1bcd91b39cbc4df58a487363 Mon Sep 17 00:00:00 2001 From: Gemma Lynn Date: Sun, 13 Mar 2022 21:04:53 +0100 Subject: [PATCH 391/498] Store native BSON types as-is in the MongoDB formatter (#1620) --- src/Monolog/Formatter/MongoDBFormatter.php | 3 +- .../Formatter/MongoDBFormatterTest.php | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 202d30eb9..fca69a899 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use MongoDB\BSON\Type; use MongoDB\BSON\UTCDateTime; use Monolog\Utils; @@ -85,7 +86,7 @@ protected function formatArray(array $array, int $nestingLevel = 0) $array[$name] = $this->formatException($value, $nestingLevel + 1); } elseif (is_array($value)) { $array[$name] = $this->formatArray($value, $nestingLevel + 1); - } elseif (is_object($value)) { + } elseif (is_object($value) && !$value instanceof Type) { $array[$name] = $this->formatObject($value, $nestingLevel + 1); } } diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 6a2dd04e5..67f0657ef 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -11,6 +11,9 @@ namespace Monolog\Formatter; +use MongoDB\BSON\ObjectId; +use MongoDB\BSON\Regex; +use MongoDB\BSON\UTCDateTime; use Monolog\Logger; /** @@ -259,4 +262,31 @@ public function testFormatDepthException() $this->assertEquals(987, $formattedRecord['context']['nest2']['code']); $this->assertEquals('[...]', $formattedRecord['context']['nest2']['trace']); } + + public function testBsonTypes() + { + $record = [ + 'message' => 'some log message', + 'context' => [ + 'objectid' => new ObjectId(), + 'nest' => [ + 'timestamp' => new UTCDateTime(), + 'regex' => new Regex('pattern'), + ], + ], + 'level' => Logger::WARNING, + 'level_name' => Logger::getLevelName(Logger::WARNING), + 'channel' => 'test', + 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + 'extra' => [], + ]; + + $formatter = new MongoDBFormatter(); + $formattedRecord = $formatter->format($record); + + $this->assertInstanceOf(ObjectId::class, $formattedRecord['context']['objectid']); + $this->assertInstanceOf(UTCDateTime::class, $formattedRecord['context']['nest']['timestamp']); + $this->assertInstanceOf(Regex::class, $formattedRecord['context']['nest']['regex']); + + } } From 1c8f39a94d3101c54d77de692e002f134b9645fa Mon Sep 17 00:00:00 2001 From: Yup Date: Sun, 13 Mar 2022 22:19:51 +0200 Subject: [PATCH 392/498] Allow easier extend of BrowserConsoleHandler.php (#1593) Co-authored-by: Jordi Boggiano --- src/Monolog/Handler/BrowserConsoleHandler.php | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 8d908b266..fa383f1c2 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -11,10 +11,17 @@ namespace Monolog\Handler; -use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; use Monolog\Utils; +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 * @@ -29,6 +36,10 @@ class BrowserConsoleHandler extends AbstractProcessingHandler /** @var FormattedRecord[] */ protected static $records = []; + protected const FORMAT_HTML = 'html'; + protected const FORMAT_JS = 'js'; + protected const FORMAT_UNKNOWN = 'unknown'; + /** * {@inheritDoc} * @@ -65,14 +76,14 @@ protected function write(array $record): void public static function send(): void { $format = static::getResponseFormat(); - if ($format === 'unknown') { + if ($format === self::FORMAT_UNKNOWN) { return; } if (count(static::$records)) { - if ($format === 'html') { + if ($format === self::FORMAT_HTML) { static::writeOutput(''); - } elseif ($format === 'js') { + } elseif ($format === self::FORMAT_JS) { static::writeOutput(static::generateScript()); } static::resetStatic(); @@ -125,25 +136,37 @@ protected static function writeOutput(string $str): void * If Content-Type is anything else -> unknown * * @return string One of 'js', 'html' or 'unknown' + * @phpstan-return self::FORMAT_* */ protected static function getResponseFormat(): string { // Check content type foreach (headers_list() as $header) { if (stripos($header, 'content-type:') === 0) { - // This handler only works with HTML and javascript outputs - // text/javascript is obsolete in favour of application/javascript, but still used - if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) { - return 'js'; - } - if (stripos($header, 'text/html') === false) { - return 'unknown'; - } - break; + return static::getResponseFormatFromContentType($header); } } - return 'html'; + return self::FORMAT_HTML; + } + + /** + * @return string One of 'js', 'html' or 'unknown' + * @phpstan-return self::FORMAT_* + */ + protected static function getResponseFormatFromContentType(string $contentType): string + { + // This handler only works with HTML and javascript outputs + // text/javascript is obsolete in favour of application/javascript, but still used + if (stripos($contentType, 'application/javascript') !== false || stripos($contentType, 'text/javascript') !== false) { + return self::FORMAT_JS; + } + + if (stripos($contentType, 'text/html') !== false) { + return self::FORMAT_HTML; + } + + return self::FORMAT_UNKNOWN; } private static function generateScript(): string From 67100e7952cae23b51289fe9ef416d1e63d052f5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 13 Mar 2022 21:44:42 +0100 Subject: [PATCH 393/498] Update changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 121380fd7..3332ed9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +### 2.4.0 (2022-xx-xx) + + * Added `persistent`, `timeout`, `writingTimeout`, `connectionTimeout`, `chunkSize` constructor params to SocketHandler and derivatives (#1600) + * Added `AsMonologProcessor` PHP attribute which can help autowiring / autoconfiguration of processors if frameworks / integrations decide to make use of it. This is useless when used purely with Monolog (#1637) + * Added support for keeping native BSON types as is in MongoDBFormatter (#1620) + * Added support for a `user_agent` key in WebProcessor, disabled by default but you can use it by configuring the $extraFields you want (#1613) + * Added support for username/userIcon in SlackWebhookHandler (#1617) + * Added extension points to BrowserConsoleHandler (#1593) + * Fixed error handler signature to accept a null $context which happens with internal PHP errors (#1614) + * Fixed a few setter methods not returning `self` (#1609) + * Fixed handling of records going over the max Telegram message length (#1616) + ### 2.3.5 (2021-10-01) * Fixed regression in StreamHandler since 2.3.3 on systems with the memory_limit set to >=20GB (#1592) From 93369fd88f9cfce1c4c53ac0a09670cf32f4b86d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 12:40:24 +0100 Subject: [PATCH 394/498] Add LogRecord interface for forward compatibility --- src/Monolog/LogRecord.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/Monolog/LogRecord.php diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php new file mode 100644 index 000000000..81fccb405 --- /dev/null +++ b/src/Monolog/LogRecord.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use ArrayAccess; + +/** + * 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 + * @template-implements \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> + * @phpstan-import-type Record from Logger + */ +interface LogRecord implements \ArrayAccess +{ + /** + * @phpstan-return Record + */ + public function toArray(): array; +} From f764bbdc0c0f310a6646b6a137c5c7dfbf799f6b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 12:48:00 +0100 Subject: [PATCH 395/498] Add includeStacktraces constructor parameter to LineFormatter & JsonFormatter, fixes #1603 --- src/Monolog/Formatter/JsonFormatter.php | 3 ++- src/Monolog/Formatter/LineFormatter.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 6b1a10e52..42735a6b4 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -39,11 +39,12 @@ class JsonFormatter extends NormalizerFormatter /** * @param self::BATCH_MODE_* $batchMode */ - public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false) + public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = false) { $this->batchMode = $batchMode; $this->appendNewline = $appendNewline; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; + $this->includeStacktraces = $includeStacktraces; parent::__construct(); } diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 55272a5b7..a855c5259 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -40,11 +40,12 @@ class LineFormatter extends NormalizerFormatter * @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) + public function __construct(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = false, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = false) { $this->format = $format === null ? static::SIMPLE_FORMAT : $format; $this->allowInlineLineBreaks = $allowInlineLineBreaks; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; + $this->includeStacktraces($includeStacktraces); parent::__construct($dateFormat); } From 4b22d380d045d078060f9ad30612478f838decdd Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:00:50 +0100 Subject: [PATCH 396/498] Expand rollbar supported versions --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c671df1ec..b151c6549 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "phpspec/prophecy": "^1.6.1", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", - "rollbar/rollbar": "^1.3", + "rollbar/rollbar": "^1.3 || ^2 || ^3", "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0", "phpstan/phpstan": "^0.12.91" From e289293a7c172e066c9fabbcd8da8f0d2c7abf91 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:03:53 +0100 Subject: [PATCH 397/498] PHPStan fixes --- phpstan.neon.dist | 3 --- src/Monolog/LogRecord.php | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 275089a06..961f7ce47 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -35,6 +35,3 @@ parameters: - '#::popProcessor\(\) should return callable#' - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#' - '#is incompatible with native type array.#' - - # can be removed when https://github.com/rollbar/rollbar-php/pull/536 will be merged - - '#Rollbar\\RollbarLogger#' diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php index 81fccb405..702807d71 100644 --- a/src/Monolog/LogRecord.php +++ b/src/Monolog/LogRecord.php @@ -22,10 +22,10 @@ * Do not rely on this interface for other purposes, and do not implement it. * * @author Jordi Boggiano - * @template-implements \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> + * @template-extends \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> * @phpstan-import-type Record from Logger */ -interface LogRecord implements \ArrayAccess +interface LogRecord extends \ArrayAccess { /** * @phpstan-return Record From c02d86ffb2fe351c3bc6e33417807b4ac55067ec Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:34:54 +0100 Subject: [PATCH 398/498] Include record message/context/extra data when throwing an exception because the log cannot be opened, fixes #1630 --- src/Monolog/Handler/SqsHandler.php | 2 +- src/Monolog/Handler/StreamHandler.php | 6 +++--- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- src/Monolog/Handler/SyslogHandler.php | 2 +- src/Monolog/Handler/TelegramBotHandler.php | 7 ++++--- src/Monolog/Utils.php | 21 +++++++++++++++++++++ tests/Monolog/Handler/StreamHandlerTest.php | 9 ++++++++- 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index dc1dcb427..dcf282b45 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -46,7 +46,7 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Log protected function write(array $record): void { if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) { - throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string'); + throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string' . Utils::getRecordMessageForException($record)); } $messageBody = $record['formatted']; diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 2531d41b9..e6c795699 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -130,7 +130,7 @@ protected function write(array $record): void if (!is_resource($this->stream)) { $url = $this->url; if (null === $url || '' === $url) { - throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); + throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().' . Utils::getRecordMessageForException($record)); } $this->createDir($url); $this->errorMessage = null; @@ -143,7 +143,7 @@ protected function write(array $record): void if (!is_resource($stream)) { $this->stream = null; - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url)); + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url) . Utils::getRecordMessageForException($record)); } stream_set_chunk_size($stream, $this->streamChunkSize); $this->stream = $stream; @@ -151,7 +151,7 @@ protected function write(array $record): void $stream = $this->stream; if (!is_resource($stream)) { - throw new \LogicException('No stream was opened yet'); + throw new \LogicException('No stream was opened yet' . Utils::getRecordMessageForException($record)); } if ($this->useLocking) { diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index b3fedea5d..7d6b7b683 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -83,7 +83,7 @@ protected function buildMessage(string $content, array $records): Swift_Message } if (!$message instanceof Swift_Message) { - throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it'); + throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . Utils::getRecordMessageForException($record)); } if ($records) { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 4951f66a9..0acf6c2ee 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -60,7 +60,7 @@ public function close(): 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.'"'); + throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"' . Utils::getRecordMessageForException($record)); } syslog($this->logLevels[$record['level']], (string) $record['formatted']); } diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index e8c818fe0..0f935808c 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -13,6 +13,7 @@ use RuntimeException; use Monolog\Logger; +use Monolog\Utils; /** * Handler send logs to Telegram using Telegram Bot API. @@ -247,12 +248,12 @@ protected function sendCurl(string $message): void $result = Curl\Util::execute($ch); if (!is_string($result)) { - throw new RuntimeException('Telegram API error. Description: No response'); + throw new RuntimeException('Telegram API error. Description: No response' . Utils::getRecordMessageForException($record)); } $result = json_decode($result, true); if ($result['ok'] === false) { - throw new RuntimeException('Telegram API error. Description: ' . $result['description']); + throw new RuntimeException('Telegram API error. Description: ' . $result['description'] . Utils::getRecordMessageForException($record)); } } @@ -265,7 +266,7 @@ private function handleMessageLength(string $message): array { $truncatedMarker = ' (...truncated)'; if (!$this->splitLongMessages && strlen($message) > self::MAX_MESSAGE_LENGTH) { - return [substr($message, 0, self::MAX_MESSAGE_LENGTH - strlen($truncatedMarker)) . $truncatedMarker]; + return [Utils::substr($message, 0, self::MAX_MESSAGE_LENGTH - strlen($truncatedMarker)) . $truncatedMarker]; } return str_split($message, self::MAX_MESSAGE_LENGTH); diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index d3e7ad096..726c98191 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -260,4 +260,25 @@ public static function expandIniShorthandBytes($val) return $val; } + + /** + * @param array $record + */ + public static function getRecordMessageForException(array $record): string + { + $context = ''; + $extra = ''; + try { + if ($record['context']) { + $context = "\nContext: " . json_encode($record['context']); + } + 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; + } } diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 275aa9553..2b2f6a674 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -145,9 +145,16 @@ public function testWriteInvalidArgument($invalidArgument) public function testWriteInvalidResource() { $this->expectException(\UnexpectedValueException::class); + $this->expectExceptionMessage('The stream or file "bogus://url" could not be opened in append mode: Failed to open stream: No such file or directory +The exception occurred while attempting to log: test +Context: {"foo":"bar"} +Extra: [1,2,3]'); $handler = new StreamHandler('bogus://url'); - $handler->handle($this->getRecord()); + $record = $this->getRecord(); + $record['context'] = ['foo' => 'bar']; + $record['extra'] = [1, 2, 3]; + $handler->handle($record); } /** From b886d70a359ce7725b5a753fe0542d4cd0233800 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:35:56 +0100 Subject: [PATCH 399/498] Fixes --- src/Monolog/Handler/SwiftMailerHandler.php | 1 + src/Monolog/Handler/SyslogHandler.php | 1 + src/Monolog/Handler/TelegramBotHandler.php | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 7d6b7b683..f8c39f835 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Swift_Message; diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 0acf6c2ee..1d543b7ec 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Logs to syslog service. diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 0f935808c..8912eba51 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -248,12 +248,12 @@ protected function sendCurl(string $message): void $result = Curl\Util::execute($ch); if (!is_string($result)) { - throw new RuntimeException('Telegram API error. Description: No response' . Utils::getRecordMessageForException($record)); + throw new RuntimeException('Telegram API error. Description: No response'); } $result = json_decode($result, true); if ($result['ok'] === false) { - throw new RuntimeException('Telegram API error. Description: ' . $result['description'] . Utils::getRecordMessageForException($record)); + throw new RuntimeException('Telegram API error. Description: ' . $result['description']); } } From f1f2e3e37c71cffe54e7b31aa4d10b09a329def7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:39:42 +0100 Subject: [PATCH 400/498] Fix fix --- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index f8c39f835..640cc803b 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -84,7 +84,7 @@ protected function buildMessage(string $content, array $records): Swift_Message } if (!$message instanceof Swift_Message) { - throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . Utils::getRecordMessageForException($record)); + throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . Utils::getRecordMessageForException(reset($records))); } if ($records) { From 330b80ceb7d42693627bf608fecfbdeddf6af9af Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:41:10 +0100 Subject: [PATCH 401/498] One day I will learn --- src/Monolog/Handler/SwiftMailerHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 640cc803b..be7e2a587 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -84,7 +84,8 @@ protected function buildMessage(string $content, array $records): Swift_Message } if (!$message instanceof Swift_Message) { - throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . Utils::getRecordMessageForException(reset($records))); + $record = reset($records); + throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); } if ($records) { From d7fd7450628561ba697b7097d86db72662f54aef Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:44:37 +0100 Subject: [PATCH 402/498] Update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3332ed9a0..50d34c171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,14 @@ -### 2.4.0 (2022-xx-xx) +### 2.4.0 (2022-03-14) + * Added `[Monolog\LogRecord](src/Monolog/LogRecord.php)` interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes + * Added `includeStacktraces` constructor params to LineFormatter & JsonFormatter (#1603) * Added `persistent`, `timeout`, `writingTimeout`, `connectionTimeout`, `chunkSize` constructor params to SocketHandler and derivatives (#1600) * Added `AsMonologProcessor` PHP attribute which can help autowiring / autoconfiguration of processors if frameworks / integrations decide to make use of it. This is useless when used purely with Monolog (#1637) * Added support for keeping native BSON types as is in MongoDBFormatter (#1620) * Added support for a `user_agent` key in WebProcessor, disabled by default but you can use it by configuring the $extraFields you want (#1613) * Added support for username/userIcon in SlackWebhookHandler (#1617) * Added extension points to BrowserConsoleHandler (#1593) + * Added record message/context/extra info to exceptions thrown when a StreamHandler cannot open its stream to avoid completely losing the data logged (#1630) * Fixed error handler signature to accept a null $context which happens with internal PHP errors (#1614) * Fixed a few setter methods not returning `self` (#1609) * Fixed handling of records going over the max Telegram message length (#1616) From affa44f7c8b19bc0486c26223bb30c29298785d5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:45:46 +0100 Subject: [PATCH 403/498] Fix formatting issue --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d34c171..1dcc7a149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### 2.4.0 (2022-03-14) - * Added `[Monolog\LogRecord](src/Monolog/LogRecord.php)` interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes + * Added [`Monolog\LogRecord`](src/Monolog/LogRecord.php) interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes * Added `includeStacktraces` constructor params to LineFormatter & JsonFormatter (#1603) * Added `persistent`, `timeout`, `writingTimeout`, `connectionTimeout`, `chunkSize` constructor params to SocketHandler and derivatives (#1600) * Added `AsMonologProcessor` PHP attribute which can help autowiring / autoconfiguration of processors if frameworks / integrations decide to make use of it. This is useless when used purely with Monolog (#1637) From cb3675ee15cc0157c1694b8cac1af7ad436b31c7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 13:51:26 +0100 Subject: [PATCH 404/498] Try fixing ci --- tests/Monolog/Handler/StreamHandlerTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 2b2f6a674..127a36e23 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -145,10 +145,7 @@ public function testWriteInvalidArgument($invalidArgument) public function testWriteInvalidResource() { $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessage('The stream or file "bogus://url" could not be opened in append mode: Failed to open stream: No such file or directory -The exception occurred while attempting to log: test -Context: {"foo":"bar"} -Extra: [1,2,3]'); + $this->expectExceptionMessage('The stream or file "bogus://url" could not be opened in append mode: Failed to open stream: No such file or directory'."\n".'The exception occurred while attempting to log: test'."\n".'Context: {"foo":"bar"}'."\n".'Extra: [1,2,3]'); $handler = new StreamHandler('bogus://url'); $record = $this->getRecord(); From 0a023ffb2322d9a2c87d5c1eb209d0c62415be65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Vu=C5=A1ak?= Date: Fri, 18 Mar 2022 09:47:05 +0100 Subject: [PATCH 405/498] Calculate exception message according to PHP version (#1644) --- tests/Monolog/Handler/StreamHandlerTest.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 127a36e23..43a520bcd 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -145,7 +145,25 @@ public function testWriteInvalidArgument($invalidArgument) public function testWriteInvalidResource() { $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessage('The stream or file "bogus://url" could not be opened in append mode: Failed to open stream: No such file or directory'."\n".'The exception occurred while attempting to log: test'."\n".'Context: {"foo":"bar"}'."\n".'Extra: [1,2,3]'); + $php7xMessage = <<expectExceptionMessage(($majorVersion >= 8) ? $php8xMessage : $php7xMessage); $handler = new StreamHandler('bogus://url'); $record = $this->getRecord(); From f0e0dbaa5254cbcda95916db6014d00c8f307203 Mon Sep 17 00:00:00 2001 From: jszczypk Date: Fri, 18 Mar 2022 10:31:44 +0100 Subject: [PATCH 406/498] added information about call type from debug_backtrace (#1612) $record['extra']['callType'] will contain current call type: "->" or "::" depending if it was normal or static method call. Gives possibility to nicely format messages "{$record['extra']['class']}{$record['extra']['callType']}{$record['extra']['function']} ..." --- src/Monolog/Processor/IntrospectionProcessor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 0823501b9..4dc1cdf84 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -101,6 +101,7 @@ public function __invoke(array $record): array 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null, 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null, 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, + 'callType' => isset($trace[$i]['type']) ? $trace[$]['type'] : null, 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, ] ); From 77b71e0baf6370f65f5d21c1df078edbd053a87b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 18 Mar 2022 10:43:11 +0100 Subject: [PATCH 407/498] Fix syntax --- src/Monolog/Processor/IntrospectionProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 4dc1cdf84..a32e76b21 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -101,7 +101,7 @@ public function __invoke(array $record): array 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null, 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null, 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, - 'callType' => isset($trace[$i]['type']) ? $trace[$]['type'] : null, + 'callType' => isset($trace[$i]['type']) ? $trace[$i]['type'] : null, 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, ] ); From f2f66cd480df5f165391ff9b6332700d467b25ac Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 18 Mar 2022 10:48:03 +0100 Subject: [PATCH 408/498] Fix tests --- tests/Monolog/Processor/IntrospectionProcessorTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Monolog/Processor/IntrospectionProcessorTest.php b/tests/Monolog/Processor/IntrospectionProcessorTest.php index 5dabbc51a..b19175af1 100644 --- a/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ b/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -92,6 +92,7 @@ public function testLevelEqual() 'line' => null, 'class' => 'PHPUnit\Framework\TestCase', 'function' => 'runTest', + 'callType' => '->', ]; $processor = new IntrospectionProcessor(Logger::CRITICAL); @@ -113,6 +114,7 @@ public function testLevelHigher() 'line' => null, 'class' => 'PHPUnit\Framework\TestCase', 'function' => 'runTest', + 'callType' => '->', ]; $processor = new IntrospectionProcessor(Logger::CRITICAL); From 22c8b19358e916c52f1d2170d44e172152de7c25 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 20 Feb 2022 14:39:51 +0100 Subject: [PATCH 409/498] Add LogRecord class, drop PHP <8.1 --- .github/workflows/continuous-integration.yml | 11 +- .github/workflows/lint.yml | 3 +- .github/workflows/phpstan.yml | 5 +- composer.json | 15 ++- doc/04-extending.md | 2 +- src/Monolog/Formatter/ChromePHPFormatter.php | 3 +- src/Monolog/Formatter/ElasticaFormatter.php | 7 +- .../Formatter/ElasticsearchFormatter.php | 5 +- src/Monolog/Formatter/FlowdockFormatter.php | 4 +- src/Monolog/Formatter/FluentdFormatter.php | 3 +- src/Monolog/Formatter/FormatterInterface.php | 14 +-- .../Formatter/GelfMessageFormatter.php | 3 +- src/Monolog/Formatter/HtmlFormatter.php | 3 +- src/Monolog/Formatter/JsonFormatter.php | 3 +- src/Monolog/Formatter/LineFormatter.php | 3 +- src/Monolog/Formatter/LogglyFormatter.php | 4 +- src/Monolog/Formatter/LogmaticFormatter.php | 4 +- src/Monolog/Formatter/LogstashFormatter.php | 4 +- src/Monolog/Formatter/MongoDBFormatter.php | 3 +- src/Monolog/Formatter/NormalizerFormatter.php | 5 +- src/Monolog/Formatter/ScalarFormatter.php | 4 +- src/Monolog/Formatter/WildfireFormatter.php | 3 +- src/Monolog/Handler/AbstractHandler.php | 3 +- .../Handler/AbstractProcessingHandler.php | 7 +- src/Monolog/Handler/AmqpHandler.php | 5 +- src/Monolog/Handler/BrowserConsoleHandler.php | 3 +- src/Monolog/Handler/BufferHandler.php | 3 +- src/Monolog/Handler/ChromePHPHandler.php | 3 +- src/Monolog/Handler/CouchDBHandler.php | 3 +- src/Monolog/Handler/CubeHandler.php | 3 +- src/Monolog/Handler/DeduplicationHandler.php | 5 +- .../Handler/DoctrineCouchDBHandler.php | 3 +- src/Monolog/Handler/DynamoDbHandler.php | 5 +- src/Monolog/Handler/ElasticaHandler.php | 3 +- src/Monolog/Handler/ElasticsearchHandler.php | 3 +- src/Monolog/Handler/ErrorLogHandler.php | 3 +- src/Monolog/Handler/FallbackGroupHandler.php | 3 +- src/Monolog/Handler/FilterHandler.php | 7 +- .../ActivationStrategyInterface.php | 4 +- .../ChannelLevelActivationStrategy.php | 3 +- .../ErrorLevelActivationStrategy.php | 3 +- src/Monolog/Handler/FingersCrossedHandler.php | 7 +- src/Monolog/Handler/FirePHPHandler.php | 5 +- src/Monolog/Handler/FleepHookHandler.php | 7 +- src/Monolog/Handler/FlowdockHandler.php | 7 +- src/Monolog/Handler/GelfHandler.php | 3 +- src/Monolog/Handler/GroupHandler.php | 5 +- src/Monolog/Handler/HandlerInterface.php | 19 ++- src/Monolog/Handler/HandlerWrapper.php | 7 +- src/Monolog/Handler/IFTTTHandler.php | 3 +- src/Monolog/Handler/InsightOpsHandler.php | 3 +- src/Monolog/Handler/LogEntriesHandler.php | 3 +- src/Monolog/Handler/LogglyHandler.php | 3 +- src/Monolog/Handler/LogmaticHandler.php | 3 +- src/Monolog/Handler/MailHandler.php | 3 +- src/Monolog/Handler/MongoDBHandler.php | 3 +- src/Monolog/Handler/NewRelicHandler.php | 3 +- src/Monolog/Handler/NoopHandler.php | 6 +- src/Monolog/Handler/NullHandler.php | 5 +- src/Monolog/Handler/OverflowHandler.php | 3 +- src/Monolog/Handler/PHPConsoleHandler.php | 11 +- src/Monolog/Handler/ProcessHandler.php | 3 +- .../Handler/ProcessableHandlerTrait.php | 13 +-- src/Monolog/Handler/PsrHandler.php | 3 +- src/Monolog/Handler/PushoverHandler.php | 7 +- src/Monolog/Handler/RedisHandler.php | 5 +- src/Monolog/Handler/RedisPubSubHandler.php | 3 +- src/Monolog/Handler/RollbarHandler.php | 3 +- src/Monolog/Handler/RotatingFileHandler.php | 3 +- src/Monolog/Handler/SamplingHandler.php | 7 +- src/Monolog/Handler/Slack/SlackRecord.php | 5 +- src/Monolog/Handler/SlackHandler.php | 9 +- src/Monolog/Handler/SlackWebhookHandler.php | 3 +- src/Monolog/Handler/SocketHandler.php | 5 +- src/Monolog/Handler/SqsHandler.php | 3 +- src/Monolog/Handler/StreamHandler.php | 5 +- src/Monolog/Handler/SyslogHandler.php | 3 +- src/Monolog/Handler/SyslogUdpHandler.php | 3 +- src/Monolog/Handler/TelegramBotHandler.php | 3 +- src/Monolog/Handler/TestHandler.php | 22 ++-- .../Handler/WhatFailureGroupHandler.php | 4 +- src/Monolog/Handler/ZendMonitorHandler.php | 3 +- src/Monolog/LogRecord.php | 110 ++++++++++++++++-- src/Monolog/Logger.php | 72 ++++++------ src/Monolog/Processor/GitProcessor.php | 3 +- src/Monolog/Processor/HostnameProcessor.php | 4 +- .../Processor/IntrospectionProcessor.php | 3 +- .../Processor/MemoryPeakUsageProcessor.php | 4 +- .../Processor/MemoryUsageProcessor.php | 4 +- src/Monolog/Processor/MercurialProcessor.php | 3 +- src/Monolog/Processor/ProcessIdProcessor.php | 4 +- src/Monolog/Processor/ProcessorInterface.php | 11 +- .../Processor/PsrLogMessageProcessor.php | 13 ++- src/Monolog/Processor/TagProcessor.php | 6 +- src/Monolog/Processor/UidProcessor.php | 3 +- src/Monolog/Processor/WebProcessor.php | 4 +- src/Monolog/Test/TestCase.php | 28 ++--- src/Monolog/Utils.php | 15 +-- .../Formatter/ElasticaFormatterTest.php | 21 ++-- tests/Monolog/Formatter/LineFormatterTest.php | 6 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 59 +++++----- .../Monolog/Handler/ExceptionTestHandler.php | 3 +- tests/Monolog/Handler/FlowdockHandlerTest.php | 6 +- .../Monolog/Handler/InsightOpsHandlerTest.php | 4 +- .../Monolog/Handler/LogEntriesHandlerTest.php | 4 +- tests/Monolog/Handler/LogmaticHandlerTest.php | 4 +- tests/Monolog/Handler/PushoverHandlerTest.php | 18 +-- tests/Monolog/Handler/SlackHandlerTest.php | 20 ++-- .../MemoryPeakUsageProcessorTest.php | 2 +- .../Processor/MemoryUsageProcessorTest.php | 2 +- .../Processor/PsrLogMessageProcessorTest.php | 19 +-- 111 files changed, 501 insertions(+), 361 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5cb0839c2..7066557e0 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -16,17 +16,10 @@ jobs: strategy: matrix: php-version: - - "7.2" - - "7.3" - - "7.4" - - "8.0" - # disabled for now as phpspec/prophecy does not allow 8.1 - # - "8.1" + - "8.1" dependencies: [highest] include: - - php-version: "7.2" - dependencies: lowest - - php-version: "8.0" + - php-version: "8.1" dependencies: lowest steps: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cd260475a..bac219980 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,8 +13,7 @@ jobs: strategy: matrix: php-version: - - "7.2" - - "8.0" + - "8.1" steps: - name: "Checkout" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 434324ce8..a5ee083c0 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: php-version: - - "8.0" + - "8.1" steps: - name: "Checkout" @@ -44,8 +44,7 @@ jobs: run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' - name: "Install latest dependencies" - # --ignore-platform-req=php here needed as long as elasticsearch/elasticsearch does not support php 8 - run: "composer update ${{ env.COMPOSER_FLAGS }} --ignore-platform-req=php" + run: "composer update ${{ env.COMPOSER_FLAGS }}" - name: Run PHPStan run: composer phpstan diff --git a/composer.json b/composer.json index b151c6549..a5369ba76 100644 --- a/composer.json +++ b/composer.json @@ -13,8 +13,8 @@ } ], "require": { - "php": ">=7.2", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", @@ -25,12 +25,11 @@ "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^9", "predis/predis": "^1.1", - "rollbar/rollbar": "^1.3 || ^2 || ^3", + "rollbar/rollbar": "^3", "ruflin/elastica": ">=0.90@dev", - "swiftmailer/swiftmailer": "^5.3|^6.0", - "phpstan/phpstan": "^0.12.91" + "phpstan/phpstan": "^1.4" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", @@ -56,11 +55,11 @@ "psr-4": {"Monolog\\": "tests/Monolog"} }, "provide": { - "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + "psr/log-implementation": "3.0.0" }, "extra": { "branch-alias": { - "dev-main": "2.x-dev" + "dev-main": "3.x-dev" } }, "scripts": { diff --git a/doc/04-extending.md b/doc/04-extending.md index 5ba7c0fdc..c7075c760 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -36,7 +36,7 @@ class PDOHandler extends AbstractProcessingHandler parent::__construct($level, $bubble); } - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!$this->initialized) { $this->initialize(); diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index aa1884b9c..b588e3164 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\LogRecord; /** * Formats a log message according to the ChromePHP array format @@ -39,7 +40,7 @@ class ChromePHPFormatter implements FormatterInterface /** * {@inheritDoc} */ - public function format(array $record) + public function format(LogRecord $record) { // Retrieve the line and file if set and remove them from the formatted extra $backtrace = 'unknown'; diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 6c8a9ab5e..e60fc6f95 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -12,13 +12,12 @@ namespace Monolog\Formatter; use Elastica\Document; +use Monolog\LogRecord; /** * Format a log message into an Elastica Document * * @author Jelle Vink - * - * @phpstan-import-type Record from \Monolog\Logger */ class ElasticaFormatter extends NormalizerFormatter { @@ -48,7 +47,7 @@ public function __construct(string $index, ?string $type) /** * {@inheritDoc} */ - public function format(array $record) + public function format(LogRecord $record) { $record = parent::format($record); @@ -71,8 +70,6 @@ public function getType(): string /** * Convert a log message into an Elastica Document - * - * @phpstan-param Record $record */ protected function getDocument(array $record): Document { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index b792b819c..477877b17 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use DateTimeInterface; +use Monolog\LogRecord; /** * Format a log message into an Elasticsearch record @@ -46,7 +47,7 @@ public function __construct(string $index, string $type) /** * {@inheritDoc} */ - public function format(array $record) + public function format(LogRecord $record) { $record = parent::format($record); @@ -79,7 +80,7 @@ public function getType(): string * @param mixed[] $record Log message * @return mixed[] */ - protected function getDocument(array $record): array + protected function getDocument(LogRecord $record): array { $record['_index'] = $this->index; $record['_type'] = $this->type; diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 41b56b3c0..8da44074e 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * formats the record to be used in the FlowdockHandler * @@ -39,7 +41,7 @@ public function __construct(string $source, string $sourceEmail) * * @return mixed[] */ - public function format(array $record): array + public function format(LogRecord $record): array { $tags = [ '#logs', diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index 29b14d30d..2b76e7513 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Utils; +use Monolog\LogRecord; /** * Class FluentdFormatter @@ -55,7 +56,7 @@ public function isUsingLevelsInTag(): bool return $this->levelTag; } - public function format(array $record): string + public function format(LogRecord $record): string { $tag = $record['channel']; if ($this->levelTag) { diff --git a/src/Monolog/Formatter/FormatterInterface.php b/src/Monolog/Formatter/FormatterInterface.php index 19617ec5f..d65ae3653 100644 --- a/src/Monolog/Formatter/FormatterInterface.php +++ b/src/Monolog/Formatter/FormatterInterface.php @@ -11,32 +11,28 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * Interface for formatters * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger */ interface FormatterInterface { /** * Formats a log record. * - * @param array $record A record to format + * @param LogRecord $record A record to format * @return mixed The formatted record - * - * @phpstan-param Record $record */ - public function format(array $record); + public function format(LogRecord $record); /** * Formats a set of log records. * - * @param array $records A set of records to format + * @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); } diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index a1a79372d..c69023906 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Gelf\Message; use Monolog\Utils; +use Monolog\LogRecord; /** * Serializes a log message to GELF @@ -83,7 +84,7 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n /** * {@inheritDoc} */ - public function format(array $record): Message + public function format(LogRecord $record): Message { $context = $extra = []; if (isset($record['context'])) { diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 10a4311cb..fb2fb9f66 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Formats incoming records into an HTML table @@ -83,7 +84,7 @@ protected function addTitle(string $title, int $level): string * * @return string The formatted record */ - public function format(array $record): string + public function format(LogRecord $record): string { $output = $this->addTitle($record['level_name'], $record['level']); $output .= ''; diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 42735a6b4..00a0a3f91 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Throwable; +use Monolog\LogRecord; /** * Encodes whatever record data is passed to it as json @@ -72,7 +73,7 @@ public function isAppendingNewlines(): bool /** * {@inheritDoc} */ - public function format(array $record): string + public function format(LogRecord $record): string { $normalized = $this->normalize($record); diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index a855c5259..4da8e6493 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Utils; +use Monolog\LogRecord; /** * Formats incoming records into a one-line string @@ -76,7 +77,7 @@ public function ignoreEmptyContextAndExtra(bool $ignore = true): self /** * {@inheritDoc} */ - public function format(array $record): string + public function format(LogRecord $record): string { $vars = parent::format($record); diff --git a/src/Monolog/Formatter/LogglyFormatter.php b/src/Monolog/Formatter/LogglyFormatter.php index 29841aa38..bb6f5ab1f 100644 --- a/src/Monolog/Formatter/LogglyFormatter.php +++ b/src/Monolog/Formatter/LogglyFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * Encodes message information into JSON in a format compatible with Loggly. * @@ -33,7 +35,7 @@ public function __construct(int $batchMode = self::BATCH_MODE_NEWLINES, bool $ap * @see https://www.loggly.com/docs/automated-parsing/#json * @see \Monolog\Formatter\JsonFormatter::format() */ - public function format(array $record): string + public function format(LogRecord $record): string { if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTimeInterface)) { $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO"); diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index b0451aba7..bf101c17a 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * Encodes message information into JSON in a format compatible with Logmatic. * @@ -50,7 +52,7 @@ public function setAppname(string $appname): self * @see http://doc.logmatic.io/docs/basics-to-send-data * @see \Monolog\Formatter\JsonFormatter::format() */ - public function format(array $record): string + public function format(LogRecord $record): string { if (!empty($this->hostname)) { $record["hostname"] = $this->hostname; diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index f8de0d333..4e9faddcb 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * Serializes a log message to Logstash Event Format * @@ -61,7 +63,7 @@ public function __construct(string $applicationName, ?string $systemName = null, /** * {@inheritDoc} */ - public function format(array $record): string + public function format(LogRecord $record): string { $record = parent::format($record); diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index fca69a899..64d33e875 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -14,6 +14,7 @@ use MongoDB\BSON\Type; use MongoDB\BSON\UTCDateTime; use Monolog\Utils; +use Monolog\LogRecord; /** * Formats a record for use with the MongoDBHandler. @@ -46,7 +47,7 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri * * @return mixed[] */ - public function format(array $record): array + public function format(LogRecord $record): array { /** @var mixed[] $res */ $res = $this->formatArray($record); diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 0c6227150..36118ff4e 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -14,6 +14,7 @@ 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 @@ -50,8 +51,10 @@ public function __construct(?string $dateFormat = null) * * @param mixed[] $record */ - public function format(array $record) + public function format(LogRecord $record) { + $record = $record->toArray(); + return $this->normalize($record); } diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index 187bc550d..f375dbde4 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -11,6 +11,8 @@ namespace Monolog\Formatter; +use Monolog\LogRecord; + /** * Formats data into an associative array of scalar values. * Objects and arrays will be JSON encoded. @@ -24,7 +26,7 @@ class ScalarFormatter extends NormalizerFormatter * * @phpstan-return array $record */ - public function format(array $record): array + public function format(LogRecord $record): array { $result = []; foreach ($record as $key => $value) { diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 6539b3473..335b046b4 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\LogRecord; /** * Serializes a log message according to Wildfire's header requirements @@ -56,7 +57,7 @@ public function __construct(?string $dateFormat = null) * * @return string */ - public function format(array $record): string + public function format(LogRecord $record): string { // Retrieve the line and file if set and remove them from the formatted extra $file = $line = ''; diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index a5cdaa71f..07c0d3e94 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\ResettableInterface; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Base Handler class providing basic level/bubble support @@ -48,7 +49,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return $record['level'] >= $this->level; } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 77e533fca..bed34c12e 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\LogRecord; + /** * Base Handler class providing the Handler structure, including processors and formatters * @@ -32,14 +34,13 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if (!$this->isHandling($record)) { return false; } if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -55,7 +56,7 @@ public function handle(array $record): bool * * @phpstan-param FormattedRecord $record */ - abstract protected function write(array $record): void; + abstract protected function write(LogRecord $record): void; /** * @return void diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index e30d784dd..da84f809b 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -17,6 +17,7 @@ use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; +use Monolog\LogRecord; /** * @phpstan-import-type Record from \Monolog\Logger @@ -54,7 +55,7 @@ public function __construct($exchange, ?string $exchangeName = null, $level = Lo /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $data = $record["formatted"]; $routingKey = $this->getRoutingKey($record); @@ -113,7 +114,7 @@ public function handleBatch(array $records): void * * @phpstan-param Record $record */ - protected function getRoutingKey(array $record): string + protected function getRoutingKey(LogRecord $record): string { $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']); diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index fa383f1c2..471778aa5 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Utils; +use Monolog\LogRecord; use function count; use function headers_list; @@ -57,7 +58,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { // Accumulate records static::$records[] = $record; diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index fcce5d630..6035415f6 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -14,6 +14,7 @@ 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. @@ -58,7 +59,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $le /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($record['level'] < $this->level) { return false; diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index d1a98b8fe..a2afb3be9 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -115,7 +116,7 @@ protected function getDefaultFormatter(): FormatterInterface * @see sendHeader() * @see send() */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!$this->isWebRequest()) { return; diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index 526576132..96bd16997 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use Monolog\Logger; +use Monolog\LogRecord; /** * CouchDB handler @@ -44,7 +45,7 @@ public function __construct(array $options = [], $level = Logger::DEBUG, bool $b /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $basicAuth = null; if ($this->options['username']) { diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index fc8f58f1a..5ea634d5e 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Logs to Cube. @@ -112,7 +113,7 @@ protected function connectHttp(): void /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $date = $record['datetime']; diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 9b85ae7ed..776e293b1 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Simple handler wrapper that deduplicates log records across multiple requests @@ -110,7 +111,7 @@ public function flush(): void /** * @phpstan-param Record $record */ - private function isDuplicate(array $record): bool + private function isDuplicate(LogRecord $record): bool { if (!file_exists($this->deduplicationStore)) { return false; @@ -179,7 +180,7 @@ private function collectLogs(): void /** * @phpstan-param Record $record */ - private function appendRecord(array $record): void + private function appendRecord(LogRecord $record): void { file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); } diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index ebd52c3a0..f2c34c877 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; use Doctrine\CouchDB\CouchDBClient; +use Monolog\LogRecord; /** * CouchDB handler for Doctrine CouchDB ODM @@ -35,7 +36,7 @@ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->client->postDocument($record['formatted']); } diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 21840bf60..55846374a 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -17,6 +17,7 @@ use Aws\DynamoDb\Marshaler; use Monolog\Formatter\ScalarFormatter; use Monolog\Logger; +use Monolog\LogRecord; /** * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/) @@ -67,7 +68,7 @@ public function __construct(DynamoDbClient $client, string $table, $level = Logg /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $filtered = $this->filterEmptyFields($record['formatted']); if ($this->version === 3) { @@ -87,7 +88,7 @@ protected function write(array $record): void * @param mixed[] $record * @return mixed[] */ - protected function filterEmptyFields(array $record): array + protected function filterEmptyFields(LogRecord $record): array { return array_filter($record, function ($value) { return !empty($value) || false === $value || 0 === $value; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index fc92ca42d..8caf2c0a0 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -17,6 +17,7 @@ use Monolog\Logger; use Elastica\Client; use Elastica\Exception\ExceptionInterface; +use Monolog\LogRecord; /** * Elastic Search handler @@ -67,7 +68,7 @@ public function __construct(Client $client, array $options = [], $level = Logger /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->bulkSend([$record['formatted']]); } diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index b9d323d83..a62fc279e 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -19,6 +19,7 @@ use InvalidArgumentException; use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; use Elasticsearch\Client; +use Monolog\LogRecord; /** * Elasticsearch handler @@ -74,7 +75,7 @@ public function __construct(Client $client, array $options = [], $level = Logger /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->bulkSend([$record['formatted']]); } diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index f2e22036b..2815f5e3e 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Stores to PHP error_log() handler. @@ -71,7 +72,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!$this->expandNewlines) { error_log((string) $record['formatted'], $this->messageType); diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index d4e234ce0..1e5b623b3 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Throwable; +use Monolog\LogRecord; /** * Forwards records to at most one handler @@ -27,7 +28,7 @@ class FallbackGroupHandler extends GroupHandler /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->processors) { /** @var Record $record */ diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 718f17ef1..c430b3559 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -15,6 +15,7 @@ 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 @@ -111,7 +112,7 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return isset($this->acceptedLevels[$record['level']]); } @@ -119,7 +120,7 @@ public function isHandling(array $record): bool /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if (!$this->isHandling($record)) { return false; @@ -161,7 +162,7 @@ public function handleBatch(array $records): void * * @phpstan-param Record $record */ - public function getHandler(array $record = null) + public function getHandler(LogRecord $record = null) { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index 0aa5607b1..f10772793 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -11,6 +11,8 @@ namespace Monolog\Handler\FingersCrossed; +use Monolog\LogRecord; + /** * Interface for activation strategies for the FingersCrossedHandler. * @@ -25,5 +27,5 @@ interface ActivationStrategyInterface * * @phpstan-param Record $record */ - public function isHandlerActivated(array $record): bool; + public function isHandlerActivated(LogRecord $record): bool; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 7b9abb582..fd2b22c65 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Channel and Error level based monolog activation strategy. Allows to trigger activation @@ -66,7 +67,7 @@ public function __construct($defaultActionLevel, array $channelToActionLevel = [ /** * @phpstan-param Record $record */ - public function isHandlerActivated(array $record): bool + public function isHandlerActivated(LogRecord $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { return $record['level'] >= $this->channelToActionLevel[$record['channel']]; diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 5ec88eab6..0131e44fe 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Error level based activation strategy. @@ -39,7 +40,7 @@ public function __construct($actionLevel) $this->actionLevel = Logger::toMonologLevel($actionLevel); } - public function isHandlerActivated(array $record): bool + public function isHandlerActivated(LogRecord $record): bool { return $record['level'] >= $this->actionLevel; } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 0627b4451..4bcb23c74 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -17,6 +17,7 @@ use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Buffers all records until a certain level is reached @@ -107,7 +108,7 @@ public function __construct($handler, $activationStrategy = null, int $bufferSiz /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return true; } @@ -128,7 +129,7 @@ public function activate(): void /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->processors) { /** @var Record $record */ @@ -210,7 +211,7 @@ private function flushBuffer(): void * * @phpstan-param Record $record */ - public function getHandler(array $record = null) + public function getHandler(LogRecord $record = null) { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 72718de63..007c80f71 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\WildfireFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. @@ -88,7 +89,7 @@ protected function createHeader(array $meta, string $message): array * * @phpstan-param FormattedRecord $record */ - protected function createRecordHeader(array $record): array + protected function createRecordHeader(LogRecord $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. @@ -140,7 +141,7 @@ protected function sendHeader(string $header, string $content): void * @see sendHeader() * @see sendInitHeaders() */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!self::$sendHeaders || !$this->isWebRequest()) { return; diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 85c95b9d7..5768797c2 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Logger; +use Monolog\LogRecord; /** * Sends logs to Fleep.io using Webhook integrations @@ -89,7 +90,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * Handles a log record */ - public function write(array $record): void + public function write(LogRecord $record): void { parent::write($record); $this->closeSocket(); @@ -98,7 +99,7 @@ public function write(array $record): void /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { $content = $this->buildContent($record); @@ -124,7 +125,7 @@ private function buildHeader(string $content): string * * @phpstan-param FormattedRecord $record */ - private function buildContent(array $record): string + private function buildContent(LogRecord $record): string { $dataArray = [ 'message' => $record['formatted'], diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index b837bdb66..bad8d5768 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -15,6 +15,7 @@ use Monolog\Utils; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * Sends notifications through the Flowdock push API @@ -89,7 +90,7 @@ protected function getDefaultFormatter(): FormatterInterface /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { parent::write($record); @@ -99,7 +100,7 @@ protected function write(array $record): void /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { $content = $this->buildContent($record); @@ -111,7 +112,7 @@ protected function generateDataStream(array $record): string * * @phpstan-param FormattedRecord $record */ - private function buildContent(array $record): string + private function buildContent(LogRecord $record): string { return Utils::jsonEncode($record['formatted']['flowdock']); } diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 4ff26c4cd..2198486af 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -15,6 +15,7 @@ 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 @@ -42,7 +43,7 @@ public function __construct(PublisherInterface $publisher, $level = Logger::DEBU /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->publisher->publish($record['formatted']); } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 3c9dc4b3b..fed86c5b4 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\ResettableInterface; +use Monolog\LogRecord; /** * Forwards records to multiple handlers @@ -49,7 +50,7 @@ public function __construct(array $handlers, bool $bubble = true) /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { @@ -63,7 +64,7 @@ public function isHandling(array $record): bool /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->processors) { /** @var Record $record */ diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index affcc51fc..c63ecbbf5 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -11,12 +11,13 @@ namespace Monolog\Handler; +use Monolog\LogRecord; + /** * Interface that all Monolog Handlers must implement * * @author Jordi Boggiano * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface @@ -30,13 +31,11 @@ interface HandlerInterface * is no guarantee that handle() will not be called, and isHandling() might not be called * for a given record. * - * @param array $record Partial log record containing only a level key + * @param LogRecord $record Partial log record having only a level initialized * * @return bool - * - * @phpstan-param array{level: Level} $record */ - public function isHandling(array $record): bool; + public function isHandling(LogRecord $record): bool; /** * Handles a record. @@ -48,20 +47,16 @@ public function isHandling(array $record): bool; * 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 array $record The record to handle + * @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. - * - * @phpstan-param Record $record */ - public function handle(array $record): bool; + public function handle(LogRecord $record): bool; /** * Handles a set of records at once. * - * @param array $records The records to handle (an array of record arrays) - * - * @phpstan-param Record[] $records + * @param array $records The records to handle */ public function handleBatch(array $records): void; diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index d4351b9f9..a045ccc75 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -13,6 +13,7 @@ use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * This simple wrapper class can be used to extend handlers functionality. @@ -21,7 +22,7 @@ * * Inherit from this class and override handle() like this: * - * public function handle(array $record) + * public function handle(LogRecord $record) * { * if ($record meets certain conditions) { * return false; @@ -46,7 +47,7 @@ public function __construct(HandlerInterface $handler) /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return $this->handler->isHandling($record); } @@ -54,7 +55,7 @@ public function isHandling(array $record): bool /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { return $this->handler->handle($record); } diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 000ccea40..e5b477bcb 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * IFTTTHandler uses cURL to trigger IFTTT Maker actions @@ -51,7 +52,7 @@ public function __construct(string $eventName, string $secretKey, $level = Logge /** * {@inheritDoc} */ - public function write(array $record): void + public function write(LogRecord $record): void { $postData = [ "value1" => $record["channel"], diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index 71f64a267..8d796e6e8 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\LogRecord; /** * Inspired on LogEntriesHandler. @@ -69,7 +70,7 @@ public function __construct( /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 25fcd1594..02d9c7d4d 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\LogRecord; /** * @author Robert Kaufmann III @@ -63,7 +64,7 @@ public function __construct( /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 6d13db375..a1a8e3b7c 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -16,6 +16,7 @@ use Monolog\Formatter\LogglyFormatter; use function array_key_exists; use CurlHandle; +use Monolog\LogRecord; /** * Sends errors to Loggly. @@ -119,7 +120,7 @@ public function addTag($tag): self return $this; } - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->send($record["formatted"], static::ENDPOINT_SINGLE); } diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 859a46906..293194414 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogmaticFormatter; +use Monolog\LogRecord; /** * @author Julien Breux @@ -82,7 +83,7 @@ public function __construct( /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 97f343202..b08124c25 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -13,6 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\HtmlFormatter; +use Monolog\LogRecord; /** * Base class for all mail handlers @@ -57,7 +58,7 @@ abstract protected function send(string $content, array $records): void; /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->send((string) $record['formatted'], [$record]); } diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 306309119..c50375158 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -17,6 +17,7 @@ use Monolog\Logger; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\MongoDBFormatter; +use Monolog\LogRecord; /** * Logs to a MongoDB database. @@ -63,7 +64,7 @@ public function __construct($mongodb, string $database, string $collection, $lev parent::__construct($level, $bubble); } - protected function write(array $record): void + protected function write(LogRecord $record): void { if (isset($this->collection)) { $this->collection->insertOne($record['formatted']); diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 114d749eb..89c37e67c 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -15,6 +15,7 @@ use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * Class to record a log on a NewRelic application. @@ -73,7 +74,7 @@ public function __construct( /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!$this->isNewRelicEnabled()) { throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); diff --git a/src/Monolog/Handler/NoopHandler.php b/src/Monolog/Handler/NoopHandler.php index 1ddf0beb9..19fdf21af 100644 --- a/src/Monolog/Handler/NoopHandler.php +++ b/src/Monolog/Handler/NoopHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\LogRecord; + /** * No-op * @@ -25,7 +27,7 @@ class NoopHandler extends Handler /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return true; } @@ -33,7 +35,7 @@ public function isHandling(array $record): bool /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { return false; } diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index e75ee0c6e..54a40feea 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Blackhole @@ -45,7 +46,7 @@ public function __construct($level = Logger::DEBUG) /** * {@inheritDoc} */ - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return $record['level'] >= $this->level; } @@ -53,7 +54,7 @@ public function isHandling(array $record): bool /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { return $record['level'] >= $this->level; } diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 22068c9a3..4673ecc77 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -13,6 +13,7 @@ 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. @@ -87,7 +88,7 @@ public function __construct( * * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($record['level'] < $this->level) { return false; diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 6e209b190..5424fef7a 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -18,6 +18,7 @@ use PhpConsole\Connector; use PhpConsole\Handler as VendorPhpConsoleHandler; use PhpConsole\Helper; +use Monolog\LogRecord; /** * Monolog handler for Google Chrome extension "PHP Console" @@ -167,7 +168,7 @@ public function getOptions(): array return $this->options; } - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->options['enabled'] && $this->connector->isActiveClient()) { return parent::handle($record); @@ -179,7 +180,7 @@ public function handle(array $record): bool /** * Writes the record down to the log of the implementing handler */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if ($record['level'] < Logger::NOTICE) { $this->handleDebugRecord($record); @@ -193,7 +194,7 @@ protected function write(array $record): void /** * @phpstan-param Record $record */ - private function handleDebugRecord(array $record): void + private function handleDebugRecord(LogRecord $record): void { $tags = $this->getRecordTags($record); $message = $record['message']; @@ -206,7 +207,7 @@ private function handleDebugRecord(array $record): void /** * @phpstan-param Record $record */ - private function handleExceptionRecord(array $record): void + private function handleExceptionRecord(LogRecord $record): void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } @@ -214,7 +215,7 @@ private function handleExceptionRecord(array $record): void /** * @phpstan-param Record $record */ - private function handleErrorRecord(array $record): void + private function handleErrorRecord(LogRecord $record): void { $context = $record['context']; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 8a8cf1be6..7fcbdc788 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\LogRecord; /** * Stores to STDIN of any process, specified by a command. @@ -83,7 +84,7 @@ public function __construct(string $command, $level = Logger::DEBUG, bool $bubbl * * @throws \UnexpectedValueException */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->ensureProcessIsStarted(); diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 9ef6e301c..e8e6b68ca 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -13,19 +13,18 @@ use Monolog\ResettableInterface; use Monolog\Processor\ProcessorInterface; +use Monolog\LogRecord; /** * Helper trait for implementing ProcessableInterface * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger */ trait ProcessableHandlerTrait { /** * @var callable[] - * @phpstan-var array + * @phpstan-var array> */ protected $processors = []; @@ -51,13 +50,7 @@ public function popProcessor(): callable return array_shift($this->processors); } - /** - * Processes a record. - * - * @phpstan-param Record $record - * @phpstan-return Record - */ - protected function processRecord(array $record): array + protected function processRecord(LogRecord $record): LogRecord { foreach ($this->processors as $processor) { $record = $processor($record); diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 36e19cccf..0fad51f22 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Psr\Log\LoggerInterface; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * Proxies log messages to an existing PSR-3 compliant logger. @@ -51,7 +52,7 @@ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, boo /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if (!$this->isHandling($record)) { return false; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index fed2303d7..388e28ab3 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Monolog\Utils; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Sends notifications through the pushover api to mobile phones @@ -136,7 +137,7 @@ public function __construct( $this->expire = $expire; } - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { $content = $this->buildContent($record); @@ -146,7 +147,7 @@ protected function generateDataStream(array $record): string /** * @phpstan-param FormattedRecord $record */ - private function buildContent(array $record): string + private function buildContent(LogRecord $record): string { // Pushover has a limit of 512 characters on title and message combined. $maxMessageLength = 512 - strlen($this->title); @@ -198,7 +199,7 @@ private function buildHeader(string $content): string return $header; } - protected function write(array $record): void + protected function write(LogRecord $record): void { foreach ($this->users as $user) { $this->user = $user; diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 938eee6b2..4c86a1320 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\LogRecord; /** * Logs to a Redis key using rpush @@ -58,7 +59,7 @@ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $b /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if ($this->capSize) { $this->writeCapped($record); @@ -73,7 +74,7 @@ protected function write(array $record): void * * @phpstan-param FormattedRecord $record */ - protected function writeCapped(array $record): void + protected function writeCapped(LogRecord $record): void { if ($this->redisClient instanceof \Redis) { $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1; diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index f9fede8ee..4864de03a 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Logger; +use Monolog\LogRecord; /** * Sends the message to a Redis Pub/Sub channel using PUBLISH @@ -52,7 +53,7 @@ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $b /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->redisClient->publish($this->channelKey, $record["formatted"]); } diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index adcc9395a..05fa74e0b 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -14,6 +14,7 @@ use Rollbar\RollbarLogger; use Throwable; use Monolog\Logger; +use Monolog\LogRecord; /** * Sends errors to Rollbar @@ -73,7 +74,7 @@ public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 2b7c48030..dada67e14 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -14,6 +14,7 @@ use InvalidArgumentException; 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. @@ -110,7 +111,7 @@ public function setFilenameFormat(string $filenameFormat, string $dateFormat): s /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { // on the first record written, if the log is new, we should rotate (once per day) if (null === $this->mustRotate) { diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index c128a32d1..1b8a2f083 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; +use Monolog\LogRecord; /** * Sampling handler @@ -62,12 +63,12 @@ public function __construct($handler, int $factor) } } - public function isHandling(array $record): bool + public function isHandling(LogRecord $record): bool { return $this->getHandler($record)->isHandling($record); } - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { if ($this->processors) { @@ -90,7 +91,7 @@ public function handle(array $record): bool * * @return HandlerInterface */ - public function getHandler(array $record = null) + public function getHandler(LogRecord $record = null) { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 71a410946..deb66aa6a 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -15,6 +15,7 @@ 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. @@ -124,7 +125,7 @@ public function __construct( * @phpstan-param FormattedRecord $record * @phpstan-return mixed[] */ - public function getSlackData(array $record): array + public function getSlackData(LogRecord $record): array { $dataArray = array(); $record = $this->removeExcludedFields($record); @@ -364,7 +365,7 @@ private function generateAttachmentFields(array $data): array * * @return mixed[] */ - private function removeExcludedFields(array $record): array + private function removeExcludedFields(LogRecord $record): array { foreach ($this->excludeFields as $field) { $keys = explode('.', $field); diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index a648513e0..1e6e5517f 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -15,6 +15,7 @@ use Monolog\Logger; use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; +use Monolog\LogRecord; /** * Sends notifications through Slack API @@ -107,7 +108,7 @@ public function getToken(): string /** * {@inheritDoc} */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { $content = $this->buildContent($record); @@ -119,7 +120,7 @@ protected function generateDataStream(array $record): string * * @phpstan-param FormattedRecord $record */ - private function buildContent(array $record): string + private function buildContent(LogRecord $record): string { $dataArray = $this->prepareContentData($record); @@ -130,7 +131,7 @@ private function buildContent(array $record): string * @phpstan-param FormattedRecord $record * @return string[] */ - protected function prepareContentData(array $record): array + protected function prepareContentData(LogRecord $record): array { $dataArray = $this->slackRecord->getSlackData($record); $dataArray['token'] = $this->token; @@ -159,7 +160,7 @@ private function buildHeader(string $content): string /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { parent::write($record); $this->finalizeWrite(); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 8ae3c7882..269b6995c 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -15,6 +15,7 @@ use Monolog\Logger; use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; +use Monolog\LogRecord; /** * Sends notifications through Slack Webhooks @@ -90,7 +91,7 @@ public function getWebhookUrl(): string /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $postData = $this->slackRecord->getSlackData($record); $postString = Utils::jsonEncode($postData); diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 21701afa2..44fdffa94 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\LogRecord; /** * Stores to any socket - uses fsockopen() or pfsockopen(). @@ -92,7 +93,7 @@ public function __construct( * @throws \UnexpectedValueException * @throws \RuntimeException */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->connectIfNotConnected(); $data = $this->generateDataStream($record); @@ -345,7 +346,7 @@ private function connectIfNotConnected(): void /** * @phpstan-param FormattedRecord $record */ - protected function generateDataStream(array $record): string + protected function generateDataStream(LogRecord $record): string { return (string) $record['formatted']; } diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index dcf282b45..bbc2ae84a 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -14,6 +14,7 @@ use Aws\Sqs\SqsClient; use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Writes to any sqs queue. @@ -43,7 +44,7 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Log /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) { throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string' . Utils::getRecordMessageForException($record)); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index e6c795699..b48250f0b 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Stores to any stream resource @@ -125,7 +126,7 @@ public function getStreamChunkSize(): int /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { if (!is_resource($this->stream)) { $url = $this->url; @@ -173,7 +174,7 @@ protected function write(array $record): void * * @phpstan-param FormattedRecord $record */ - protected function streamWrite($stream, array $record): void + protected function streamWrite($stream, LogRecord $record): void { fwrite($stream, (string) $record['formatted']); } diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 1d543b7ec..9652e4d4d 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Logs to syslog service. @@ -58,7 +59,7 @@ public function close(): void /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $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)); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index deaa19f80..c4360cbf6 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -15,6 +15,7 @@ use Monolog\Logger; use Monolog\Handler\SyslogUdp\UdpSocket; use Monolog\Utils; +use Monolog\LogRecord; /** * A Handler for logging to a remote syslogd server. @@ -67,7 +68,7 @@ public function __construct(string $host, int $port = 514, $facility = LOG_USER, $this->socket = new UdpSocket($host, $port); } - protected function write(array $record): void + protected function write(LogRecord $record): void { $lines = $this->splitMessageIntoLines($record['formatted']); diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 8912eba51..d44148d02 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -14,6 +14,7 @@ use RuntimeException; use Monolog\Logger; use Monolog\Utils; +use Monolog\LogRecord; /** * Handler send logs to Telegram using Telegram Bot API. @@ -209,7 +210,7 @@ public function handleBatch(array $records): void /** * @inheritDoc */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->send($record['formatted']); } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 0986da270..71c4795db 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Used for testing purposes. @@ -66,23 +67,20 @@ * @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 Record[] */ + /** @var LogRecord[] */ protected $records = []; - /** @var array */ + /** @var array */ protected $recordsByLevel = []; /** @var bool */ private $skipReset = false; /** - * @return array - * - * @phpstan-return Record[] + * @return array */ public function getRecords() { @@ -127,7 +125,7 @@ public function hasRecords($level): bool } /** - * @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|LogRecord $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 $record @@ -139,11 +137,11 @@ public function hasRecord($record, $level): bool $record = array('message' => $record); } - return $this->hasRecordThatPasses(function ($rec) use ($record) { - if ($rec['message'] !== $record['message']) { + return $this->hasRecordThatPasses(function (LogRecord $rec) use ($record) { + if ($rec->message !== $record['message']) { return false; } - if (isset($record['context']) && $rec['context'] !== $record['context']) { + if (isset($record['context']) && $rec->context !== $record['context']) { return false; } @@ -179,7 +177,7 @@ public function hasRecordThatMatches(string $regex, $level): bool * @param string|int $level Logging level value or name * @return bool * - * @psalm-param callable(Record, int): mixed $predicate + * @psalm-param callable(LogRecord, int): mixed $predicate * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatPasses(callable $predicate, $level) @@ -202,7 +200,7 @@ public function hasRecordThatPasses(callable $predicate, $level) /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->recordsByLevel[$record['level']][] = $record; $this->records[] = $record; diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 2dd136720..0f83fcb8a 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\LogRecord; + /** * Forwards records to multiple handlers suppressing failures of each handler * and continuing through to give every handler a chance to succeed. @@ -24,7 +26,7 @@ class WhatFailureGroupHandler extends GroupHandler /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { if ($this->processors) { /** @var Record $record */ diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index ddd46d8c5..8f974d5a2 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\NormalizerFormatter; use Monolog\Logger; +use Monolog\LogRecord; /** * Handler sending logs to Zend Monitor @@ -59,7 +60,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) /** * {@inheritDoc} */ - protected function write(array $record): void + protected function write(LogRecord $record): void { $this->writeZendMonitorCustomEvent( Logger::getLevelName($record['level']), diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php index 702807d71..1e6aa07ae 100644 --- a/src/Monolog/LogRecord.php +++ b/src/Monolog/LogRecord.php @@ -14,21 +14,109 @@ use ArrayAccess; /** - * 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. + * Monolog log record * * @author Jordi Boggiano - * @template-extends \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> - * @phpstan-import-type Record from Logger + * @template-implements \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra', int|string|\DateTimeImmutable|array> + * @phpstan-import-type Level from Logger + * @phpstan-import-type LevelName from Logger */ -interface LogRecord extends \ArrayAccess +class LogRecord implements \ArrayAccess { + private const MODIFIABLE_FIELDS = [ + 'extra' => true, + 'formatted' => true, + ]; + + /** @var 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY' */ + public readonly string $levelName; // TODO enum? + + public function __construct( + public readonly \DateTimeImmutable $datetime, + public readonly string $channel, + /** @var Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY */ + public readonly int $level, // TODO enum? + public readonly string $message, + /** @var array */ + public readonly array $context = [], + /** @var array */ + public array $extra = [], + public mixed $formatted = null, + ) { + $this->levelName = Logger::getLevelName($level); + } + + 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 = 'levelName'; + } + + 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 Record + * @phpstan-return array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ - public function toArray(): array; + public function toArray(): array + { + return [ + 'message' => $this->message, + 'context' => $this->context, + 'level' => $this->level, + 'level_name' => $this->levelName, + '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); + } } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 1f4ef7f1a..38f862473 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -13,6 +13,7 @@ use DateTimeZone; use Monolog\Handler\HandlerInterface; +use Monolog\Processor\ProcessorInterface; use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; use Psr\Log\LogLevel; @@ -29,7 +30,6 @@ * * @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 { @@ -128,7 +128,7 @@ class Logger implements LoggerInterface, ResettableInterface * * To process records of a single handler instead, add the processor on that specific handler * - * @var callable[] + * @var array<(callable(LogRecord): LogRecord)|ProcessorInterface> */ protected $processors; @@ -148,12 +148,12 @@ class Logger implements LoggerInterface, ResettableInterface protected $exceptionHandler; /** - * @psalm-param 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 $timezone = null) { @@ -291,31 +291,29 @@ public function useMicrosecondTimestamps(bool $micro): self */ public function addRecord(int $level, string $message, array $context = []): bool { - $record = null; + $recordInitialized = count($this->processors) === 0; + + $record = new LogRecord( + message: $message, + context: $context, + level: $level, + channel: $this->name, + datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + extra: [], + ); foreach ($this->handlers as $handler) { - if (null === $record) { - // skip creating the record as long as no handler is going to handle it - if (!$handler->isHandling(['level' => $level])) { + if (false === $recordInitialized) { + // skip initializing the record as long as no handler is going to handle it + if (!$handler->isHandling($record)) { continue; } - $levelName = static::getLevelName($level); - - $record = [ - 'message' => $message, - 'context' => $context, - 'level' => $level, - 'level_name' => $levelName, - 'channel' => $this->name, - '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); @@ -323,7 +321,7 @@ public function addRecord(int $level, string $message, array $context = []): boo } } - // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted + // once the record is initialized, send it to all handlers as long as the bubbling chain is not interrupted try { if (true === $handler->handle($record)) { break; @@ -449,9 +447,12 @@ public static function toMonologLevel($level): int */ public function isHandling(int $level): bool { - $record = [ - 'level' => $level, - ]; + $record = new LogRecord( + datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + channel: $this->name, + message: '', + level: $level, + ); foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { @@ -490,7 +491,7 @@ public function getExceptionHandler(): ?callable * * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function log($level, $message, array $context = []): void + public function log($level, string|\Stringable $message, array $context = []): void { if (!is_int($level) && !is_string($level)) { throw new \InvalidArgumentException('$level is expected to be a string or int'); @@ -509,7 +510,7 @@ public function log($level, $message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function debug($message, array $context = []): void + public function debug(string|\Stringable $message, array $context = []): void { $this->addRecord(static::DEBUG, (string) $message, $context); } @@ -522,7 +523,7 @@ public function debug($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function info($message, array $context = []): void + public function info(string|\Stringable $message, array $context = []): void { $this->addRecord(static::INFO, (string) $message, $context); } @@ -535,7 +536,7 @@ public function info($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function notice($message, array $context = []): void + public function notice(string|\Stringable $message, array $context = []): void { $this->addRecord(static::NOTICE, (string) $message, $context); } @@ -548,7 +549,7 @@ public function notice($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function warning($message, array $context = []): void + public function warning(string|\Stringable $message, array $context = []): void { $this->addRecord(static::WARNING, (string) $message, $context); } @@ -561,7 +562,7 @@ public function warning($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function error($message, array $context = []): void + public function error(string|\Stringable $message, array $context = []): void { $this->addRecord(static::ERROR, (string) $message, $context); } @@ -574,7 +575,7 @@ public function error($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function critical($message, array $context = []): void + public function critical(string|\Stringable $message, array $context = []): void { $this->addRecord(static::CRITICAL, (string) $message, $context); } @@ -587,7 +588,7 @@ public function critical($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function alert($message, array $context = []): void + public function alert(string|\Stringable $message, array $context = []): void { $this->addRecord(static::ALERT, (string) $message, $context); } @@ -600,7 +601,7 @@ public function alert($message, array $context = []): void * @param string|Stringable $message The log message * @param mixed[] $context The log context */ - public function emergency($message, array $context = []): void + public function emergency(string|\Stringable $message, array $context = []): void { $this->addRecord(static::EMERGENCY, (string) $message, $context); } @@ -626,11 +627,8 @@ public function getTimezone(): DateTimeZone /** * 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, array $record): void + protected function handleException(Throwable $e, LogRecord $record): void { if (!$this->exceptionHandler) { throw $e; diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 8166bdca2..cb80ee2fe 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Injects Git branch and Git commit SHA in all records @@ -43,7 +44,7 @@ public function __construct($level = Logger::DEBUG) /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough if ($record['level'] < $this->level) { diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index 91fda7d6d..d8fa3b9ff 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Injects value of gethostname in all records */ @@ -27,7 +29,7 @@ public function __construct() /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { $record['extra']['hostname'] = self::$host; diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index a32e76b21..6414a90c8 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Injects line/file:class/function where the log message came from @@ -58,7 +59,7 @@ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough if ($record['level'] < $this->level) { diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index 37c756fcb..e4b0d6d95 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Injects memory_get_peak_usage in all records * @@ -22,7 +24,7 @@ class MemoryPeakUsageProcessor extends MemoryProcessor /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { $usage = memory_get_peak_usage($this->realUsage); diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index e141921e9..281432edc 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Injects memory_get_usage in all records * @@ -22,7 +24,7 @@ class MemoryUsageProcessor extends MemoryProcessor /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { $usage = memory_get_usage($this->realUsage); diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index d4a628f55..152e1f054 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -13,6 +13,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; +use Monolog\LogRecord; /** * Injects Hg branch and Hg revision number in all records @@ -42,7 +43,7 @@ public function __construct($level = Logger::DEBUG) /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough if ($record['level'] < $this->level) { diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 3b939a951..074cfa4fe 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Adds value of getmypid into records * @@ -21,7 +23,7 @@ class ProcessIdProcessor implements ProcessorInterface /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { $record['extra']['process_id'] = getmypid(); diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index 5defb7eb4..ebe41fc20 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -11,20 +11,17 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * An optional interface to allow labelling Monolog processors. * * @author Nicolas Grekas - * - * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessorInterface { /** - * @return array The processed record - * - * @phpstan-param Record $record - * @phpstan-return Record + * @return LogRecord The processed record */ - public function __invoke(array $record); + public function __invoke(LogRecord $record); } diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 2c2a00e75..339aec510 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -12,6 +12,7 @@ namespace Monolog\Processor; use Monolog\Utils; +use Monolog\LogRecord; /** * Processes a record's message according to PSR-3 rules @@ -43,14 +44,16 @@ public function __construct(?string $dateFormat = null, bool $removeUsedContextF /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { if (false === strpos($record['message'], '{')) { return $record; } $replacements = []; - foreach ($record['context'] as $key => $val) { + $context = $record['context']; + + foreach ($context as $key => $val) { $placeholder = '{' . $key . '}'; if (strpos($record['message'], $placeholder) === false) { continue; @@ -75,12 +78,10 @@ public function __invoke(array $record): array } if ($this->removeUsedContextFields) { - unset($record['context'][$key]); + unset($context[$key]); } } - $record['message'] = strtr($record['message'], $replacements); - - return $record; + return $record->with(message: strtr($record['message'], $replacements), context: $context); } } diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index 80f18747a..bbb7793c0 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Adds a tags array into record * @@ -52,9 +54,9 @@ public function setTags(array $tags = []): self /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { - $record['extra']['tags'] = $this->tags; + $record->extra['tags'] = $this->tags; return $record; } diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index a27b74dbf..58133b426 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -12,6 +12,7 @@ namespace Monolog\Processor; use Monolog\ResettableInterface; +use Monolog\LogRecord; /** * Adds a unique identifier into records @@ -35,7 +36,7 @@ public function __construct(int $length = 7) /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { $record['extra']['uid'] = $this->uid; diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 51850e17f..a1d3dc860 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\LogRecord; + /** * Injects url/method and remote IP of the current web request in all records * @@ -76,7 +78,7 @@ public function __construct($serverData = null, array $extraFields = null) /** * {@inheritDoc} */ - public function __invoke(array $record): array + public function __invoke(LogRecord $record): LogRecord { // skip processing if for some reason request data // is not present (CLI or wonky SAPIs) diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 1824fde45..42e1c870e 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -12,6 +12,7 @@ namespace Monolog\Test; use Monolog\Logger; +use Monolog\LogRecord; use Monolog\DateTimeImmutable; use Monolog\Formatter\FormatterInterface; @@ -20,7 +21,6 @@ * * @author Jordi Boggiano * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ class TestCase extends \PHPUnit\Framework\TestCase @@ -28,26 +28,22 @@ class TestCase extends \PHPUnit\Framework\TestCase /** * @param mixed[] $context * - * @return array Record - * * @phpstan-param Level $level - * @phpstan-return Record */ - protected function getRecord(int $level = Logger::WARNING, string $message = 'test', array $context = []): array + protected function getRecord(int $level = Logger::WARNING, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord { - return [ - 'message' => (string) $message, - 'context' => $context, - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => new DateTimeImmutable(true), - 'extra' => [], - ]; + return new LogRecord( + message: (string) $message, + context: $context, + level: $level, + channel: $channel, + datetime: $datetime, + extra: $extra, + ); } /** - * @phpstan-return Record[] + * @phpstan-return list */ protected function getMultipleRecords(): array { @@ -66,7 +62,7 @@ protected function getIdentityFormatter(): FormatterInterface $formatter->expects($this->any()) ->method('format') ->will($this->returnCallback(function ($record) { - return $record['message']; + return $record->message; })); return $formatter; diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 726c98191..5354c99c7 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -261,24 +261,21 @@ public static function expandIniShorthandBytes($val) return $val; } - /** - * @param array $record - */ - public static function getRecordMessageForException(array $record): string + public static function getRecordMessageForException(LogRecord $record): string { $context = ''; $extra = ''; try { - if ($record['context']) { - $context = "\nContext: " . json_encode($record['context']); + if ($record->context) { + $context = "\nContext: " . json_encode($record->context); } - if ($record['extra']) { - $extra = "\nExtra: " . json_encode($record['extra']); + 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; } } diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index dc280fea1..23081b15a 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\LogRecord; class ElasticaFormatterTest extends \PHPUnit\Framework\TestCase { @@ -30,18 +31,18 @@ public function setUp(): void public function testFormat() { // test log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = new LogRecord( + level: Logger::ERROR, + levelName: 'ERROR', + channel: 'meh', + context: ['foo' => 7, 'bar', 'class' => new \stdClass], + datetime: new \DateTimeImmutable("@0"), + message: 'log', + ); // expected values - $expected = $msg; + $expected = (array) $msg; + unset($expected['formatted']); $expected['datetime'] = '1970-01-01T00:00:00.000000+00:00'; $expected['context'] = [ 'class' => ['stdClass' => []], diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index 86d22d38e..f46cce6c8 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -152,7 +152,7 @@ public function testDefFormatWithExceptionAndStacktrace() $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertRegexp('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 8).'\)\n\[stacktrace]\n#0}', $message); + $this->assertMatchesRegularExpression('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 8).'\)\n\[stacktrace]\n#0}', $message); } public function testDefFormatWithPreviousException() @@ -242,7 +242,7 @@ public function testFormatShouldStripInlineLineBreaks() ] ); - $this->assertRegExp('/foo bar/', $message); + $this->assertMatchesRegularExpression('/foo bar/', $message); } public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() @@ -256,7 +256,7 @@ public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() ] ); - $this->assertRegExp('/foo\nbar/', $message); + $this->assertMatchesRegularExpression('/foo\nbar/', $message); } } diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 7fb9808e9..fdaa14e1c 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -15,6 +15,7 @@ use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; use Monolog\Logger; +use Monolog\LogRecord; use Elastica\Client; use Elastica\Request; use Elastica\Response; @@ -57,15 +58,15 @@ public function setUp(): void public function testHandle() { // log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = new LogRecord( + level: Logger::ERROR, + levelName: 'ERROR', + channel: 'meh', + context: ['foo' => 7, 'bar', 'class' => new \stdClass], + datetime: new \DateTimeImmutable("@0"), + extra: [], + message: 'log', + ); // format expected result $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']); @@ -165,17 +166,17 @@ public function providerTestConnectionErrors() */ public function testHandleIntegration() { - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = new LogRecord( + level: Logger::ERROR, + levelName: 'ERROR', + channel: 'meh', + context: ['foo' => 7, 'bar', 'class' => new \stdClass], + datetime: new \DateTimeImmutable("@0"), + extra: [], + message: 'log', + ); - $expected = $msg; + $expected = (array) $msg; $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); $expected['context'] = [ 'class' => '[object] (stdClass: {})', @@ -219,17 +220,17 @@ public function testHandleIntegration() */ public function testHandleIntegrationNewESVersion() { - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = new LogRecord( + level: Logger::ERROR, + levelName: 'ERROR', + channel: 'meh', + context: ['foo' => 7, 'bar', 'class' => new \stdClass], + datetime: new \DateTimeImmutable("@0"), + extra: [], + message: 'log', + ); - $expected = $msg; + $expected = (array) $msg; $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); $expected['context'] = [ 'class' => '[object] (stdClass: {})', diff --git a/tests/Monolog/Handler/ExceptionTestHandler.php b/tests/Monolog/Handler/ExceptionTestHandler.php index f5df55e4e..721f1fc1d 100644 --- a/tests/Monolog/Handler/ExceptionTestHandler.php +++ b/tests/Monolog/Handler/ExceptionTestHandler.php @@ -12,13 +12,14 @@ namespace Monolog\Handler; use Exception; +use Monolog\LogRecord; class ExceptionTestHandler extends TestHandler { /** * {@inheritDoc} */ - public function handle(array $record): bool + public function handle(LogRecord $record): bool { throw new Exception("ExceptionTestHandler::handle"); diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 04bf063dd..c7612e331 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -45,7 +45,7 @@ public function testWriteHeader() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + $this->assertMatchesRegularExpression('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); return $content; } @@ -55,8 +55,8 @@ public function testWriteHeader() */ public function testWriteContent($content) { - $this->assertRegexp('/"source":"test_source"/', $content); - $this->assertRegexp('/"from_address":"source@test\.com"/', $content); + $this->assertMatchesRegularExpression('/"source":"test_source"/', $content); + $this->assertMatchesRegularExpression('/"from_address":"source@test\.com"/', $content); } private function createHandler($token = 'myToken') diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index 9c98d3796..bbb1ff474 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -38,7 +38,7 @@ public function testWriteContent() fseek($this->resource, 0); $content = fread($this->resource, 1024); - $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] test.CRITICAL: Critical write test/', $content); + $this->assertMatchesRegularExpression('/testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] test.CRITICAL: Critical write test/', $content); } public function testWriteBatchContent() @@ -49,7 +49,7 @@ public function testWriteBatchContent() fseek($this->resource, 0); $content = fread($this->resource, 1024); - $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] .* \[\] \[\]\n){3}/', $content); + $this->assertMatchesRegularExpression('/(testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] .* \[\] \[\]\n){3}/', $content); } private function createHandler() diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 034d6ab8b..1dcd64529 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -37,7 +37,7 @@ public function testWriteContent() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] test.CRITICAL: Critical write test/', $content); + $this->assertMatchesRegularExpression('/testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] test.CRITICAL: Critical write test/', $content); } public function testWriteBatchContent() @@ -53,7 +53,7 @@ public function testWriteBatchContent() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] .* \[\] \[\]\n){3}/', $content); + $this->assertMatchesRegularExpression('/(testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] .* \[\] \[\]\n){3}/', $content); } private function createHandler() diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index c30a17942..d6c781343 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -37,7 +37,7 @@ public function testWriteContent() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/testToken {"message":"Critical write test","context":{},"level":500,"level_name":"CRITICAL","channel":"test","datetime":"(.*)","extra":{},"hostname":"testHostname","appname":"testAppname","@marker":\["sourcecode","php"\]}/', $content); + $this->assertMatchesRegularExpression('/testToken {"message":"Critical write test","context":{},"level":500,"level_name":"CRITICAL","channel":"test","datetime":"(.*)","extra":{},"hostname":"testHostname","appname":"testAppname","@marker":\["sourcecode","php"\]}/', $content); } public function testWriteBatchContent() @@ -53,7 +53,7 @@ public function testWriteBatchContent() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/testToken {"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"(.*)","extra":{},"hostname":"testHostname","appname":"testAppname","@marker":\["sourcecode","php"\]}/', $content); + $this->assertMatchesRegularExpression('/testToken {"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"(.*)","extra":{},"hostname":"testHostname","appname":"testAppname","@marker":\["sourcecode","php"\]}/', $content); } private function createHandler() diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 2c77d30ca..b41ead546 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -33,7 +33,7 @@ public function testWriteHeader() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + $this->assertMatchesRegularExpression('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); return $content; } @@ -43,7 +43,7 @@ public function testWriteHeader() */ public function testWriteContent($content) { - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}$/', $content); + $this->assertMatchesRegularExpression('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}$/', $content); } public function testWriteWithComplexTitle() @@ -53,7 +53,7 @@ public function testWriteWithComplexTitle() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content); + $this->assertMatchesRegularExpression('/title=Backup\+finished\+-\+SQL1/', $content); } public function testWriteWithComplexMessage() @@ -64,7 +64,7 @@ public function testWriteWithComplexMessage() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); + $this->assertMatchesRegularExpression('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); } public function testWriteWithTooLongMessage() @@ -78,7 +78,7 @@ public function testWriteWithTooLongMessage() $expectedMessage = substr($message, 0, 505); - $this->assertRegexp('/message=' . $expectedMessage . '&title/', $content); + $this->assertMatchesRegularExpression('/message=' . $expectedMessage . '&title/', $content); } public function testWriteWithHighPriority() @@ -88,7 +88,7 @@ public function testWriteWithHighPriority() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=1$/', $content); + $this->assertMatchesRegularExpression('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=1$/', $content); } public function testWriteWithEmergencyPriority() @@ -98,7 +98,7 @@ public function testWriteWithEmergencyPriority() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); + $this->assertMatchesRegularExpression('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); } public function testWriteToMultipleUsers() @@ -108,8 +108,8 @@ public function testWriteToMultipleUsers() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content); - $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); + $this->assertMatchesRegularExpression('/token=myToken&user=userA&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content); + $this->assertMatchesRegularExpression('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); } private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog') diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index c6e30a75f..c6252513c 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -46,7 +46,7 @@ public function testWriteHeader() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('{POST /api/chat.postMessage HTTP/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); + $this->assertMatchesRegularExpression('{POST /api/chat.postMessage HTTP/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); } public function testWriteContent() @@ -56,10 +56,10 @@ public function testWriteContent() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegExp('/username=Monolog/', $content); - $this->assertRegExp('/channel=channel1/', $content); - $this->assertRegExp('/token=myToken/', $content); - $this->assertRegExp('/attachments/', $content); + $this->assertMatchesRegularExpression('/username=Monolog/', $content); + $this->assertMatchesRegularExpression('/channel=channel1/', $content); + $this->assertMatchesRegularExpression('/token=myToken/', $content); + $this->assertMatchesRegularExpression('/attachments/', $content); } public function testWriteContentUsesFormatterIfProvided() @@ -75,8 +75,8 @@ public function testWriteContentUsesFormatterIfProvided() fseek($this->res, 0); $content2 = fread($this->res, 1024); - $this->assertRegexp('/text=test1/', $content); - $this->assertRegexp('/text=foo--test2/', $content2); + $this->assertMatchesRegularExpression('/text=test1/', $content); + $this->assertMatchesRegularExpression('/text=foo--test2/', $content2); } public function testWriteContentWithEmoji() @@ -86,7 +86,7 @@ public function testWriteContentWithEmoji() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/icon_emoji=%3Aalien%3A/', $content); + $this->assertMatchesRegularExpression('/icon_emoji=%3Aalien%3A/', $content); } /** @@ -99,7 +99,7 @@ public function testWriteContentWithColors($level, $expectedColor) fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/%22color%22%3A%22'.$expectedColor.'/', $content); + $this->assertMatchesRegularExpression('/%22color%22%3A%22'.$expectedColor.'/', $content); } public function testWriteContentWithPlainTextMessage() @@ -109,7 +109,7 @@ public function testWriteContentWithPlainTextMessage() fseek($this->res, 0); $content = fread($this->res, 1024); - $this->assertRegexp('/text=test1/', $content); + $this->assertMatchesRegularExpression('/text=test1/', $content); } public function provideLevelColors() diff --git a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php index bf9cbedb2..964fbbe2f 100644 --- a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php @@ -24,7 +24,7 @@ public function testProcessor() $processor = new MemoryPeakUsageProcessor(); $record = $processor($this->getRecord()); $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']); + $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']); } /** diff --git a/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/tests/Monolog/Processor/MemoryUsageProcessorTest.php index d16439baa..22c047c2b 100644 --- a/tests/Monolog/Processor/MemoryUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryUsageProcessorTest.php @@ -24,7 +24,7 @@ public function testProcessor() $processor = new MemoryUsageProcessor(); $record = $processor($this->getRecord()); $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertRegExp('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']); + $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']); } /** diff --git a/tests/Monolog/Processor/PsrLogMessageProcessorTest.php b/tests/Monolog/Processor/PsrLogMessageProcessorTest.php index 3b5ec6e94..e44d13c6c 100644 --- a/tests/Monolog/Processor/PsrLogMessageProcessorTest.php +++ b/tests/Monolog/Processor/PsrLogMessageProcessorTest.php @@ -11,7 +11,9 @@ namespace Monolog\Processor; -class PsrLogMessageProcessorTest extends \PHPUnit\Framework\TestCase +use Monolog\Test\TestCase; + +class PsrLogMessageProcessorTest extends TestCase { /** * @dataProvider getPairs @@ -20,10 +22,7 @@ public function testReplacement($val, $expected) { $proc = new PsrLogMessageProcessor; - $message = $proc([ - 'message' => '{foo}', - 'context' => ['foo' => $val], - ]); + $message = $proc($this->getRecord(message: '{foo}', context: ['foo' => $val])); $this->assertEquals($expected, $message['message']); $this->assertSame(['foo' => $val], $message['context']); } @@ -32,10 +31,7 @@ public function testReplacementWithContextRemoval() { $proc = new PsrLogMessageProcessor($dateFormat = null, $removeUsedContextFields = true); - $message = $proc([ - 'message' => '{foo}', - 'context' => ['foo' => 'bar', 'lorem' => 'ipsum'], - ]); + $message = $proc($this->getRecord(message: '{foo}', context: ['foo' => 'bar', 'lorem' => 'ipsum'])); $this->assertSame('bar', $message['message']); $this->assertSame(['lorem' => 'ipsum'], $message['context']); } @@ -47,10 +43,7 @@ public function testCustomDateFormat() $proc = new PsrLogMessageProcessor($format); - $message = $proc([ - 'message' => '{foo}', - 'context' => ['foo' => $date], - ]); + $message = $proc($this->getRecord(message: '{foo}', context: ['foo' => $date])); $this->assertEquals($date->format($format), $message['message']); $this->assertSame(['foo' => $date], $message['context']); } From 400effdd457a30b727084fdf088f67814bd37fc9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 26 Feb 2022 15:09:41 +0100 Subject: [PATCH 410/498] Fix some issues, bump phpunit version --- composer.json | 2 +- .../Formatter/ElasticsearchFormatter.php | 2 +- src/Monolog/Formatter/FlowdockFormatter.php | 4 +- .../Formatter/GelfMessageFormatter.php | 4 - src/Monolog/Formatter/JsonFormatter.php | 4 +- src/Monolog/Formatter/LineFormatter.php | 1 - src/Monolog/Formatter/LogglyFormatter.php | 12 +- src/Monolog/Formatter/LogmaticFormatter.php | 6 +- src/Monolog/Formatter/MongoDBFormatter.php | 2 +- src/Monolog/Formatter/NormalizerFormatter.php | 20 +- src/Monolog/Formatter/ScalarFormatter.php | 12 +- src/Monolog/Formatter/WildfireFormatter.php | 2 +- src/Monolog/Handler/ChromePHPHandler.php | 16 +- src/Monolog/Handler/DynamoDbHandler.php | 2 +- src/Monolog/Handler/FlowdockHandler.php | 2 +- src/Monolog/Handler/MailHandler.php | 7 +- src/Monolog/Handler/PHPConsoleHandler.php | 28 +-- src/Monolog/Handler/Slack/SlackRecord.php | 12 +- src/Monolog/Handler/TestHandler.php | 13 +- src/Monolog/Logger.php | 4 +- .../Formatter/ChromePHPFormatterTest.php | 82 +++---- .../Formatter/ElasticaFormatterTest.php | 13 +- .../Formatter/ElasticsearchFormatterTest.php | 21 +- .../Formatter/FlowdockFormatterTest.php | 6 +- .../Formatter/FluentdFormatterTest.php | 6 +- .../Formatter/GelfMessageFormatterTest.php | 149 +++++------- tests/Monolog/Formatter/JsonFormatterTest.php | 78 +++--- tests/Monolog/Formatter/LineFormatterTest.php | 226 ++++++++---------- .../Formatter/LogstashFormatterTest.php | 101 ++++---- .../Formatter/MongoDBFormatterTest.php | 98 ++++---- .../Formatter/NormalizerFormatterTest.php | 109 ++++----- .../Monolog/Formatter/ScalarFormatterTest.php | 57 ++--- .../Formatter/WildfireFormatterTest.php | 78 +++--- .../Handler/DeduplicationHandlerTest.php | 15 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 32 +-- .../Handler/ElasticsearchHandlerTest.php | 22 +- .../Handler/FingersCrossedHandlerTest.php | 8 +- .../Monolog/Handler/FleepHookHandlerTest.php | 10 +- tests/Monolog/Handler/GelfHandlerTest.php | 9 +- tests/Monolog/Handler/MongoDBHandlerTest.php | 2 +- tests/Monolog/Handler/PsrHandlerTest.php | 4 +- .../Monolog/Handler/SyslogUdpHandlerTest.php | 24 +- tests/Monolog/Handler/TestHandlerTest.php | 10 +- tests/Monolog/LoggerTest.php | 46 +++- .../Processor/IntrospectionProcessorTest.php | 15 +- 45 files changed, 602 insertions(+), 774 deletions(-) diff --git a/composer.json b/composer.json index a5369ba76..341bb181d 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", - "phpunit/phpunit": "^9", + "phpunit/phpunit": "^9.5.16", "predis/predis": "^1.1", "rollbar/rollbar": "^3", "ruflin/elastica": ">=0.90@dev", diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 477877b17..67d03f090 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -80,7 +80,7 @@ public function getType(): string * @param mixed[] $record Log message * @return mixed[] */ - protected function getDocument(LogRecord $record): array + protected function getDocument(array $record): array { $record['_index'] = $this->index; $record['_type'] = $this->type; diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 8da44074e..1b932a2b5 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -60,7 +60,7 @@ public function format(LogRecord $record): array $this->getShortMessage($record['message']) ); - $record['flowdock'] = [ + return [ 'source' => $this->source, 'from_address' => $this->sourceEmail, 'subject' => $subject, @@ -68,8 +68,6 @@ public function format(LogRecord $record): array 'tags' => $tags, 'project' => $this->source, ]; - - return $record; } /** diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index c69023906..ac8eb9dbf 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -96,10 +96,6 @@ public function format(LogRecord $record): Message $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']) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 00a0a3f91..a44aa89d6 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -75,7 +75,7 @@ public function isAppendingNewlines(): bool */ public function format(LogRecord $record): string { - $normalized = $this->normalize($record); + $normalized = parent::format($record); if (isset($normalized['context']) && $normalized['context'] === []) { if ($this->ignoreEmptyContextAndExtra) { @@ -157,7 +157,7 @@ protected function formatBatchNewlines(array $records): string * * @return mixed */ - protected function normalize($data, int $depth = 0) + protected function normalize(mixed $data, int $depth = 0): mixed { if ($depth > $this->maxNormalizeDepth) { return 'Over '.$this->maxNormalizeDepth.' levels deep, aborting normalization'; diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 4da8e6493..713071838 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -82,7 +82,6 @@ public function format(LogRecord $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); diff --git a/src/Monolog/Formatter/LogglyFormatter.php b/src/Monolog/Formatter/LogglyFormatter.php index bb6f5ab1f..5f0b6a453 100644 --- a/src/Monolog/Formatter/LogglyFormatter.php +++ b/src/Monolog/Formatter/LogglyFormatter.php @@ -35,13 +35,13 @@ public function __construct(int $batchMode = self::BATCH_MODE_NEWLINES, bool $ap * @see https://www.loggly.com/docs/automated-parsing/#json * @see \Monolog\Formatter\JsonFormatter::format() */ - public function format(LogRecord $record): string + protected function normalizeRecord(LogRecord $record): array { - if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTimeInterface)) { - $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO"); - unset($record["datetime"]); - } + $recordData = parent::normalizeRecord($record); - return parent::format($record); + $recordData["timestamp"] = $record->datetime->format("Y-m-d\TH:i:s.uO"); + unset($recordData["datetime"]); + + return $recordData; } } diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index bf101c17a..6fc7c2bdf 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -52,8 +52,10 @@ public function setAppname(string $appname): self * @see http://doc.logmatic.io/docs/basics-to-send-data * @see \Monolog\Formatter\JsonFormatter::format() */ - public function format(LogRecord $record): string + public function normalizeRecord(LogRecord $record): array { + $record = parent::normalizeRecord($record); + if (!empty($this->hostname)) { $record["hostname"] = $this->hostname; } @@ -63,6 +65,6 @@ public function format(LogRecord $record): string $record["@marker"] = static::MARKERS; - return parent::format($record); + return $record; } } diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 64d33e875..aa34e520b 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -50,7 +50,7 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri public function format(LogRecord $record): array { /** @var mixed[] $res */ - $res = $this->formatArray($record); + $res = $this->formatArray($record->toArray()); return $res; } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 36118ff4e..b2deffaa3 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -53,9 +53,12 @@ public function __construct(?string $dateFormat = null) */ public function format(LogRecord $record) { - $record = $record->toArray(); + return $this->normalizeRecord($record); + } - return $this->normalize($record); + public function normalizeValue(mixed $data): mixed + { + return $this->normalize($data); } /** @@ -126,11 +129,22 @@ public function setJsonPrettyPrint(bool $enable): self return $this; } + /** + * 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. + */ + protected function normalizeRecord(LogRecord $record): array + { + return $this->normalize($record->toArray()); + } + /** * @param mixed $data * @return null|scalar|array */ - protected function normalize($data, int $depth = 0) + protected function normalize(mixed $data, int $depth = 0): mixed { if ($depth > $this->maxNormalizeDepth) { return 'Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index f375dbde4..e2db7e927 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -14,7 +14,7 @@ use Monolog\LogRecord; /** - * Formats data into an associative array of scalar values. + * Formats data into an associative array of scalar (+ null) values. * Objects and arrays will be JSON encoded. * * @author Andrew Lawson @@ -29,18 +29,14 @@ class ScalarFormatter extends NormalizerFormatter public function format(LogRecord $record): array { $result = []; - foreach ($record as $key => $value) { - $result[$key] = $this->normalizeValue($value); + foreach ($record->toArray() as $key => $value) { + $result[$key] = $this->toScalar($value); } return $result; } - /** - * @param mixed $value - * @return scalar|null - */ - protected function normalizeValue($value) + protected function toScalar(mixed $value): string|int|float|bool|null { $normalized = $this->normalize($value); diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 335b046b4..f686781f9 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -129,7 +129,7 @@ public function formatBatch(array $records) * * @return null|scalar|array|object */ - protected function normalize($data, int $depth = 0) + protected function normalize(mixed $data, int $depth = 0): mixed { if (is_object($data) && !$data instanceof \DateTimeInterface) { return $data; diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index a2afb3be9..f8e9f237d 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -16,6 +16,7 @@ use Monolog\Logger; use Monolog\Utils; use Monolog\LogRecord; +use Monolog\DateTimeImmutable; /** * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) @@ -154,15 +155,12 @@ protected function send(): void if (strlen($data) > 3 * 1024) { self::$overflowed = 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' => [], - ]; + $record = new LogRecord( + message: 'Incomplete logs, chrome header size limit reached', + level: Logger::WARNING, + channel: 'monolog', + datetime: new DateTimeImmutable(true), + ); self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); $json = Utils::jsonEncode(self::$json, null, true); $data = base64_encode(utf8_encode($json)); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 55846374a..f3b8571f6 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -88,7 +88,7 @@ protected function write(LogRecord $record): void * @param mixed[] $record * @return mixed[] */ - protected function filterEmptyFields(LogRecord $record): array + protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { return !empty($value) || false === $value || 0 === $value; diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index bad8d5768..514ebbd0f 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -114,7 +114,7 @@ protected function generateDataStream(LogRecord $record): string */ private function buildContent(LogRecord $record): string { - return Utils::jsonEncode($record['formatted']['flowdock']); + return Utils::jsonEncode($record['formatted']); } /** diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index b08124c25..6061793bf 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -51,7 +51,7 @@ public function handleBatch(array $records): void * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content * - * @phpstan-param Record[] $records + * @phpstan-param non-empty-array $records */ abstract protected function send(string $content, array $records): void; @@ -64,10 +64,9 @@ protected function write(LogRecord $record): void } /** - * @phpstan-param non-empty-array $records - * @phpstan-return Record + * @phpstan-param non-empty-array $records */ - protected function getHighestRecord(array $records): array + protected function getHighestRecord(array $records): LogRecord { $highestRecord = null; foreach ($records as $record) { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 5424fef7a..e06128a58 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -196,10 +196,10 @@ protected function write(LogRecord $record): void */ private function handleDebugRecord(LogRecord $record): void { - $tags = $this->getRecordTags($record); + [$tags, $filteredContext] = $this->getRecordTags($record); $message = $record['message']; - if ($record['context']) { - $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true); + if ($filteredContext) { + $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($filteredContext)), null, true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } @@ -217,7 +217,7 @@ private function handleExceptionRecord(LogRecord $record): void */ private function handleErrorRecord(LogRecord $record): void { - $context = $record['context']; + $context = $record->context; $this->connector->getErrorsDispatcher()->dispatchError( $context['code'] ?? null, @@ -229,28 +229,28 @@ private function handleErrorRecord(LogRecord $record): void } /** - * @phpstan-param Record $record - * @return string + * @return array{string, mixed[]} */ - private function getRecordTags(array &$record) + private function getRecordTags(LogRecord $record): array { $tags = null; - if (!empty($record['context'])) { - $context = & $record['context']; + $filteredContext = []; + if ($record->context !== []) { + $filteredContext = $record->context; foreach ($this->options['debugTagsKeysInContext'] as $key) { - if (!empty($context[$key])) { - $tags = $context[$key]; + if (!empty($filteredContext[$key])) { + $tags = $filteredContext[$key]; if ($key === 0) { - array_shift($context); + array_shift($filteredContext); } else { - unset($context[$key]); + unset($filteredContext[$key]); } break; } } } - return $tags ?: strtolower($record['level_name']); + return [$tags ?: strtolower($record->levelName), $filteredContext]; } /** diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index deb66aa6a..d20cc6918 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -128,7 +128,6 @@ public function __construct( public function getSlackData(LogRecord $record): array { $dataArray = array(); - $record = $this->removeExcludedFields($record); if ($this->username) { $dataArray['username'] = $this->username; @@ -142,9 +141,11 @@ public function getSlackData(LogRecord $record): array /** @phpstan-ignore-next-line */ $message = $this->formatter->format($record); } else { - $message = $record['message']; + $message = $record->message; } + $record = $this->removeExcludedFields($record); + if ($this->useAttachment) { $attachment = array( 'fallback' => $message, @@ -226,8 +227,7 @@ public function getAttachmentColor(int $level): string */ public function stringify(array $fields): string { - /** @var Record $fields */ - $normalized = $this->normalizerFormatter->format($fields); + $normalized = $this->normalizerFormatter->normalizeValue($fields); $hasSecondDimension = count(array_filter($normalized, 'is_array')); $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); @@ -347,8 +347,7 @@ private function generateAttachmentField(string $title, $value): array */ private function generateAttachmentFields(array $data): array { - /** @var Record $data */ - $normalized = $this->normalizerFormatter->format($data); + $normalized = $this->normalizerFormatter->normalizeValue($data); $fields = array(); foreach ($normalized as $key => $value) { @@ -367,6 +366,7 @@ private function generateAttachmentFields(array $data): array */ private function removeExcludedFields(LogRecord $record): array { + $record = $record->toArray(); foreach ($this->excludeFields as $field) { $keys = explode('.', $field); $node = &$record; diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 71c4795db..5f5d51ea1 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -14,6 +14,7 @@ use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; +use Monolog\DateTimeImmutable; /** * Used for testing purposes. @@ -125,16 +126,16 @@ public function hasRecords($level): bool } /** - * @param string|LogRecord $record 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 $record * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function hasRecord($record, $level): bool + public function hasRecord(string|array $record, $level): bool { if (is_string($record)) { - $record = array('message' => $record); + $record = ['message' => $record]; } return $this->hasRecordThatPasses(function (LogRecord $rec) use ($record) { @@ -168,8 +169,8 @@ public function hasRecordThatContains(string $message, $level): bool */ public function hasRecordThatMatches(string $regex, $level): bool { - return $this->hasRecordThatPasses(function (array $rec) use ($regex): bool { - return preg_match($regex, $rec['message']) > 0; + return $this->hasRecordThatPasses(function (LogRecord $rec) use ($regex): bool { + return preg_match($regex, $rec->message) > 0; }, $level); } @@ -202,7 +203,7 @@ public function hasRecordThatPasses(callable $predicate, $level) */ protected function write(LogRecord $record): void { - $this->recordsByLevel[$record['level']][] = $record; + $this->recordsByLevel[$record->level][] = $record; $this->records[] = $record; } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 38f862473..cdc705a50 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -301,6 +301,7 @@ public function addRecord(int $level, string $message, array $context = []): boo datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), extra: [], ); + $handled = false; foreach ($this->handlers as $handler) { if (false === $recordInitialized) { @@ -323,6 +324,7 @@ public function addRecord(int $level, string $message, array $context = []): boo // once the record is initialized, send it to all handlers as long as the bubbling chain is not interrupted try { + $handled = true; if (true === $handler->handle($record)) { break; } @@ -333,7 +335,7 @@ public function addRecord(int $level, string $message, array $context = []): boo } } - return null !== $record; + return $handled; } /** diff --git a/tests/Monolog/Formatter/ChromePHPFormatterTest.php b/tests/Monolog/Formatter/ChromePHPFormatterTest.php index e44de85af..cdfcae254 100644 --- a/tests/Monolog/Formatter/ChromePHPFormatterTest.php +++ b/tests/Monolog/Formatter/ChromePHPFormatterTest.php @@ -12,8 +12,9 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\Test\TestCase; -class ChromePHPFormatterTest extends \PHPUnit\Framework\TestCase +class ChromePHPFormatterTest extends TestCase { /** * @covers Monolog\Formatter\ChromePHPFormatter::format @@ -21,15 +22,14 @@ class ChromePHPFormatterTest extends \PHPUnit\Framework\TestCase public function testDefaultFormat() { $formatter = new ChromePHPFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['ip' => '127.0.0.1'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['ip' => '127.0.0.1'], + ); $message = $formatter->format($record); @@ -54,15 +54,14 @@ public function testDefaultFormat() public function testFormatWithFileAndLine() { $formatter = new ChromePHPFormatter(); - $record = [ - 'level' => Logger::CRITICAL, - 'level_name' => 'CRITICAL', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['ip' => '127.0.0.1', 'file' => 'test', 'line' => 14], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::CRITICAL, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['ip' => '127.0.0.1', 'file' => 'test', 'line' => 14], + ); $message = $formatter->format($record); @@ -87,15 +86,12 @@ public function testFormatWithFileAndLine() public function testFormatWithoutContext() { $formatter = new ChromePHPFormatter(); - $record = [ - 'level' => Logger::DEBUG, - 'level_name' => 'DEBUG', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::DEBUG, + 'log', + channel: 'meh', + datetime: new \DateTimeImmutable("@0"), + ); $message = $formatter->format($record); @@ -117,24 +113,18 @@ public function testBatchFormatThrowException() { $formatter = new ChromePHPFormatter(); $records = [ - [ - 'level' => Logger::INFO, - 'level_name' => 'INFO', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ], - [ - 'level' => Logger::WARNING, - 'level_name' => 'WARNING', - 'channel' => 'foo', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log2', - ], + $this->getRecord( + Logger::INFO, + 'log', + channel: 'meh', + datetime: new \DateTimeImmutable("@0"), + ), + $this->getRecord( + Logger::WARNING, + 'log2', + channel: 'foo', + datetime: new \DateTimeImmutable("@0"), + ), ]; $this->assertEquals( diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index 23081b15a..17d29382d 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -13,8 +13,9 @@ use Monolog\Logger; use Monolog\LogRecord; +use Monolog\Test\TestCase; -class ElasticaFormatterTest extends \PHPUnit\Framework\TestCase +class ElasticaFormatterTest extends TestCase { public function setUp(): void { @@ -31,18 +32,16 @@ public function setUp(): void public function testFormat() { // test log message - $msg = new LogRecord( - level: Logger::ERROR, - levelName: 'ERROR', + $msg = $this->getRecord( + Logger::ERROR, + 'log', channel: 'meh', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0"), - message: 'log', ); // expected values - $expected = (array) $msg; - unset($expected['formatted']); + $expected = $msg->toArray(); $expected['datetime'] = '1970-01-01T00:00:00.000000+00:00'; $expected['context'] = [ 'class' => ['stdClass' => []], diff --git a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php index 2cd868992..2dc89be6c 100644 --- a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php @@ -12,8 +12,9 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\Test\TestCase; -class ElasticsearchFormatterTest extends \PHPUnit\Framework\TestCase +class ElasticsearchFormatterTest extends TestCase { /** * @covers Monolog\Formatter\ElasticsearchFormatter::__construct @@ -23,18 +24,16 @@ class ElasticsearchFormatterTest extends \PHPUnit\Framework\TestCase public function testFormat() { // Test log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['foo' => 7, 'bar', 'class' => new \stdClass], + datetime: new \DateTimeImmutable("@0"), + ); // Expected values - $expected = $msg; + $expected = $msg->toArray(); $expected['datetime'] = '1970-01-01T00:00:00+0000'; $expected['context'] = [ 'class' => ['stdClass' => []], diff --git a/tests/Monolog/Formatter/FlowdockFormatterTest.php b/tests/Monolog/Formatter/FlowdockFormatterTest.php index f922d5302..322e6ed39 100644 --- a/tests/Monolog/Formatter/FlowdockFormatterTest.php +++ b/tests/Monolog/Formatter/FlowdockFormatterTest.php @@ -34,7 +34,7 @@ public function testFormat() ]; $formatted = $formatter->format($record); - $this->assertEquals($expected, $formatted['flowdock']); + $this->assertEquals($expected, $formatted); } /** @@ -49,7 +49,7 @@ public function testFormatBatch() ]; $formatted = $formatter->formatBatch($records); - $this->assertArrayHasKey('flowdock', $formatted[0]); - $this->assertArrayHasKey('flowdock', $formatted[1]); + $this->assertArrayHasKey('from_address', $formatted[0]); + $this->assertArrayHasKey('from_address', $formatted[1]); } } diff --git a/tests/Monolog/Formatter/FluentdFormatterTest.php b/tests/Monolog/Formatter/FluentdFormatterTest.php index ca6ba3bb6..dbebd787c 100644 --- a/tests/Monolog/Formatter/FluentdFormatterTest.php +++ b/tests/Monolog/Formatter/FluentdFormatterTest.php @@ -35,8 +35,7 @@ public function testConstruct() */ public function testFormat() { - $record = $this->getRecord(Logger::WARNING); - $record['datetime'] = new \DateTimeImmutable("@0"); + $record = $this->getRecord(Logger::WARNING, datetime: new \DateTimeImmutable("@0")); $formatter = new FluentdFormatter(); $this->assertEquals( @@ -50,8 +49,7 @@ public function testFormat() */ public function testFormatWithTag() { - $record = $this->getRecord(Logger::ERROR); - $record['datetime'] = new \DateTimeImmutable("@0"); + $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable("@0")); $formatter = new FluentdFormatter(true); $this->assertEquals( diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index 88eb9a4a9..fd1adb7df 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -12,7 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; -use PHPUnit\Framework\TestCase; +use Monolog\Test\TestCase; class GelfMessageFormatterTest extends TestCase { @@ -29,15 +29,12 @@ public function setUp(): void public function testDefaultFormatter() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + datetime: new \DateTimeImmutable("@0"), + ); $message = $formatter->format($record); @@ -64,15 +61,14 @@ public function testDefaultFormatter() public function testFormatWithFileAndLine() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['file' => 'test', 'line' => 14], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['file' => 'test', 'line' => 14], + ); $message = $formatter->format($record); @@ -81,37 +77,20 @@ public function testFormatWithFileAndLine() $this->assertEquals(14, $message->getLine()); } - /** - * @covers Monolog\Formatter\GelfMessageFormatter::format - */ - public function testFormatInvalidFails() - { - $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - ]; - - $this->expectException(\InvalidArgumentException::class); - - $formatter->format($record); - } - /** * @covers Monolog\Formatter\GelfMessageFormatter::format */ public function testFormatWithContext() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => 'pair'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => 'pair'], + ); $message = $formatter->format($record); @@ -140,19 +119,17 @@ public function testFormatWithContext() public function testFormatWithContextContainingException() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger', 'exception' => [ + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger', 'exception' => [ 'class' => '\Exception', 'file' => '/some/file/in/dir.php:56', 'trace' => ['/some/file/1.php:23', '/some/file/2.php:3'], ]], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + datetime: new \DateTimeImmutable("@0"), + ); $message = $formatter->format($record); @@ -168,15 +145,14 @@ public function testFormatWithContextContainingException() public function testFormatWithExtra() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => 'pair'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => 'pair'], + ); $message = $formatter->format($record); @@ -202,15 +178,14 @@ public function testFormatWithExtra() public function testFormatWithLargeData() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['exception' => str_repeat(' ', 32767)], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => str_repeat(' ', 32767)], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['exception' => str_repeat(' ', 32767)], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => str_repeat(' ', 32767)], + ); $message = $formatter->format($record); $messageArray = $message->toArray(); @@ -229,14 +204,13 @@ public function testFormatWithLargeData() public function testFormatWithUnlimitedLength() { $formatter = new GelfMessageFormatter('LONG_SYSTEM_NAME', null, 'ctxt_', PHP_INT_MAX); - $record = array( - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => array('exception' => str_repeat(' ', 32767 * 2)), - 'datetime' => new \DateTime("@0"), - 'extra' => array('key' => str_repeat(' ', 32767 * 2)), - 'message' => 'log', + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['exception' => str_repeat(' ', 32767 * 2)], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => str_repeat(' ', 32767 * 2)], ); $message = $formatter->format($record); $messageArray = $message->toArray(); @@ -256,15 +230,14 @@ public function testFormatWithUnlimitedLength() public function testFormatWithLargeCyrillicData() { $formatter = new GelfMessageFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['exception' => str_repeat('а', 32767)], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => str_repeat('б', 32767)], - 'message' => str_repeat('в', 32767), - ]; + $record = $this->getRecord( + Logger::ERROR, + str_repeat('в', 32767), + channel: 'meh', + context: ['exception' => str_repeat('а', 32767)], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => str_repeat('б', 32767)], + ); $message = $formatter->format($record); $messageArray = $message->toArray(); diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 17a3ba823..ea22ec086 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -12,6 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\LogRecord; use Monolog\Test\TestCase; class JsonFormatterTest extends TestCase @@ -38,8 +39,7 @@ public function testFormat() { $formatter = new JsonFormatter(); $record = $this->getRecord(); - $record['context'] = $record['extra'] = new \stdClass; - $this->assertEquals(json_encode($record)."\n", $formatter->format($record)); + $this->assertEquals(json_encode($record->toArray(), JSON_FORCE_OBJECT)."\n", $formatter->format($record)); $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); $record = $this->getRecord(); @@ -54,8 +54,7 @@ public function testFormatWithPrettyPrint() $formatter = new JsonFormatter(); $formatter->setJsonPrettyPrint(true); $record = $this->getRecord(); - $record['context'] = $record['extra'] = new \stdClass; - $this->assertEquals(json_encode($record, JSON_PRETTY_PRINT)."\n", $formatter->format($record)); + $this->assertEquals(json_encode($record->toArray(), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT)."\n", $formatter->format($record)); $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); $formatter->setJsonPrettyPrint(true); @@ -99,14 +98,11 @@ public function testFormatBatch() public function testFormatBatchNewlines() { $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES); - $records = $expected = [ + $records = [ $this->getRecord(Logger::WARNING), $this->getRecord(Logger::DEBUG), ]; - array_walk($expected, function (&$value, $key) { - $value['context'] = $value['extra'] = new \stdClass; - $value = json_encode($value); - }); + $expected = array_map(fn (LogRecord $record) => json_encode($record->toArray(), JSON_FORCE_OBJECT), $records); $this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records)); } @@ -165,7 +161,7 @@ public function testMaxNormalizeItemCountWith0ItemsMax() $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); $this->assertEquals( - '{"...":"Over 0 items (6 total), aborting normalization"}'."\n", + '{"...":"Over 0 items (7 total), aborting normalization"}'."\n", $message ); } @@ -180,7 +176,7 @@ public function testMaxNormalizeItemCountWith2ItemsMax() $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); $this->assertEquals( - '{"level_name":"CRITICAL","channel":"core","...":"Over 2 items (6 total), aborting normalization"}'."\n", + '{"message":"foobar","context":{"exception":{"class":"Error","message":"Foo","code":0,"file":"'.__FILE__.':'.(__LINE__ - 5).'"}},"...":"Over 2 items (7 total), aborting normalization"}'."\n", $message ); } @@ -188,8 +184,9 @@ public function testMaxNormalizeItemCountWith2ItemsMax() public function testDefFormatWithResource() { $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); - $record = $this->getRecord(); - $record['context'] = ['field_resource' => opendir(__DIR__)]; + $record = $this->getRecord( + context: ['field_resource' => opendir(__DIR__)], + ); $this->assertEquals('{"message":"test","context":{"field_resource":"[resource(stream)]"},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } @@ -202,7 +199,7 @@ public function testDefFormatWithResource() private function assertContextContainsFormattedException($expected, $actual) { $this->assertEquals( - '{"level_name":"CRITICAL","channel":"core","context":{"exception":'.$expected.'},"datetime":null,"extra":{},"message":"foobar"}'."\n", + '{"message":"foobar","context":{"exception":'.$expected.'},"level":500,"level_name":"CRITICAL","channel":"core","datetime":"2022-02-22T00:00:00+00:00","extra":{}}'."\n", $actual ); } @@ -215,14 +212,13 @@ private function assertContextContainsFormattedException($expected, $actual) */ private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \Throwable $exception) { - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => $exception], - 'datetime' => null, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => $exception], + datetime: new \DateTimeImmutable('2022-02-22 00:00:00'), + )); return $message; } @@ -265,13 +261,11 @@ public function testNormalizeHandleLargeArraysWithExactly1000Items() $formatter = new NormalizerFormatter(); $largeArray = range(1, 1000); - $res = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array($largeArray), - 'datetime' => new \DateTime, - 'extra' => array(), + $res = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'bar', + channel: 'test', + context: array($largeArray), )); $this->assertCount(1000, $res['context'][0]); @@ -283,13 +277,11 @@ public function testNormalizeHandleLargeArrays() $formatter = new NormalizerFormatter(); $largeArray = range(1, 2000); - $res = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array($largeArray), - 'datetime' => new \DateTime, - 'extra' => array(), + $res = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'bar', + channel: 'test', + context: array($largeArray), )); $this->assertCount(1001, $res['context'][0]); @@ -300,17 +292,15 @@ public function testEmptyContextAndExtraFieldsCanBeIgnored() { $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true, true); - $record = $formatter->format(array( - 'level' => 100, - 'level_name' => 'DEBUG', - 'channel' => 'test', - 'message' => 'Testing', - 'context' => array(), - 'extra' => array(), + $record = $formatter->format($this->getRecord( + Logger::DEBUG, + 'Testing', + channel: 'test', + datetime: new \DateTimeImmutable('2022-02-22 00:00:00'), )); $this->assertSame( - '{"level":100,"level_name":"DEBUG","channel":"test","message":"Testing"}'."\n", + '{"message":"Testing","level":100,"level_name":"DEBUG","channel":"test","datetime":"2022-02-22T00:00:00+00:00"}'."\n", $record ); } diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index f46cce6c8..f3128a772 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -11,111 +11,101 @@ namespace Monolog\Formatter; +use Monolog\Test\TestCase; +use Monolog\Logger; + /** * @covers Monolog\Formatter\LineFormatter */ -class LineFormatterTest extends \PHPUnit\Framework\TestCase +class LineFormatterTest extends TestCase { public function testDefFormatWithString() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'WARNING', - 'channel' => 'log', - 'context' => [], - 'message' => 'foo', - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - ]); + $message = $formatter->format($this->getRecord( + Logger::WARNING, + 'foo', + channel: 'log', + )); $this->assertEquals('['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); } public function testDefFormatWithArrayContext() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'message' => 'foo', - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'context' => [ + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'foo', + channel: 'meh', + context: [ 'foo' => 'bar', 'baz' => 'qux', 'bool' => false, 'null' => null, ], - ]); + )); $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foo {"foo":"bar","baz":"qux","bool":false,"null":null} []'."\n", $message); } public function testDefFormatExtras() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => ['ip' => '127.0.0.1'], - 'message' => 'log', - ]); + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + extra: ['ip' => '127.0.0.1'], + )); $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] {"ip":"127.0.0.1"}'."\n", $message); } public function testFormatExtras() { $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => ['ip' => '127.0.0.1', 'file' => 'test'], - 'message' => 'log', - ]); + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + extra: ['ip' => '127.0.0.1', 'file' => 'test'], + )); $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log [] test {"ip":"127.0.0.1"}'."\n", $message); } public function testContextAndExtraOptionallyNotShownIfEmpty() { $formatter = new LineFormatter(null, 'Y-m-d', false, true); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'log', - ]); + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + )); $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log '."\n", $message); } public function testContextAndExtraReplacement() { $formatter = new LineFormatter('%context.foo% => %extra.foo%'); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 'bar'], - 'datetime' => new \DateTimeImmutable, - 'extra' => ['foo' => 'xbar'], - 'message' => 'log', - ]); + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['foo' => 'bar'], + extra: ['foo' => 'xbar'], + )); + $this->assertEquals('bar => xbar', $message); } public function testDefFormatWithObject() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => ['foo' => new TestFoo, 'bar' => new TestBar, 'baz' => [], 'res' => fopen('php://memory', 'rb')], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::ERROR, + 'foobar', + channel: 'meh', + context: [], + extra: ['foo' => new TestFoo, 'bar' => new TestBar, 'baz' => [], 'res' => fopen('php://memory', 'rb')], + )); $this->assertEquals('['.date('Y-m-d').'] meh.ERROR: foobar [] {"foo":{"Monolog\\\\Formatter\\\\TestFoo":{"foo":"fooValue"}},"bar":{"Monolog\\\\Formatter\\\\TestBar":"bar"},"baz":[],"res":"[resource(stream)]"}'."\n", $message); } @@ -123,54 +113,48 @@ public function testDefFormatWithObject() public function testDefFormatWithException() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => new \RuntimeException('Foo')], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => new \RuntimeException('Foo')], + )); $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 5).')"} []'."\n", $message); } public function testDefFormatWithExceptionAndStacktrace() { $formatter = new LineFormatter(null, 'Y-m-d'); $formatter->includeStacktraces(); - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => new \RuntimeException('Foo')], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => new \RuntimeException('Foo')], + )); $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertMatchesRegularExpression('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 8).'\)\n\[stacktrace]\n#0}', $message); + $this->assertMatchesRegularExpression('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 5).'\)\n\[stacktrace]\n#0}', $message); } public function testDefFormatWithPreviousException() { $formatter = new LineFormatter(null, 'Y-m-d'); $previous = new \LogicException('Wut?'); - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => new \RuntimeException('Foo', 0, $previous)], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => new \RuntimeException('Foo', 0, $previous)], + )); $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 8).')\n[previous exception] [object] (LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__ - 12).')"} []'."\n", $message); + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (RuntimeException(code: 0): Foo at '.substr($path, 1, -1).':'.(__LINE__ - 5).')\n[previous exception] [object] (LogicException(code: 0): Wut? at '.substr($path, 1, -1).':'.(__LINE__ - 10).')"} []'."\n", $message); } public function testDefFormatWithSoapFaultException() @@ -180,53 +164,43 @@ public function testDefFormatWithSoapFaultException() } $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => new \SoapFault('foo', 'bar', 'hello', 'world')], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => new \SoapFault('foo', 'bar', 'hello', 'world')], + )); $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: world): bar at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: world): bar at '.substr($path, 1, -1).':'.(__LINE__ - 5).')"} []'."\n", $message); - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world'])], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world'])], + )); $path = str_replace('\\/', '/', json_encode(__FILE__)); - $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: {\"bar\":{\"biz\":\"baz\"},\"foo\":\"world\"}): bar at '.substr($path, 1, -1).':'.(__LINE__ - 8).')"} []'."\n", $message); + $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: {\"bar\":{\"biz\":\"baz\"},\"foo\":\"world\"}): bar at '.substr($path, 1, -1).':'.(__LINE__ - 5).')"} []'."\n", $message); } public function testBatchFormat() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->formatBatch([ - [ - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - ], - [ - 'level_name' => 'WARNING', - 'channel' => 'log', - 'message' => 'foo', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - ], + $this->getRecord( + Logger::CRITICAL, + 'bar', + channel: 'test', + ), + $this->getRecord( + Logger::WARNING, + 'foo', + channel: 'log', + ), ]); $this->assertEquals('['.date('Y-m-d').'] test.CRITICAL: bar [] []'."\n".'['.date('Y-m-d').'] log.WARNING: foo [] []'."\n", $message); } @@ -234,13 +208,7 @@ public function testBatchFormat() public function testFormatShouldStripInlineLineBreaks() { $formatter = new LineFormatter(null, 'Y-m-d'); - $message = $formatter->format( - [ - 'message' => "foo\nbar", - 'context' => [], - 'extra' => [], - ] - ); + $message = $formatter->format($this->getRecord(message: "foo\nbar")); $this->assertMatchesRegularExpression('/foo bar/', $message); } @@ -248,13 +216,7 @@ public function testFormatShouldStripInlineLineBreaks() public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() { $formatter = new LineFormatter(null, 'Y-m-d', true); - $message = $formatter->format( - [ - 'message' => "foo\nbar", - 'context' => [], - 'extra' => [], - ] - ); + $message = $formatter->format($this->getRecord(message: "foo\nbar")); $this->assertMatchesRegularExpression('/foo\nbar/', $message); } diff --git a/tests/Monolog/Formatter/LogstashFormatterTest.php b/tests/Monolog/Formatter/LogstashFormatterTest.php index 07a7efe2c..f2d134225 100644 --- a/tests/Monolog/Formatter/LogstashFormatterTest.php +++ b/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -12,7 +12,7 @@ namespace Monolog\Formatter; use Monolog\Logger; -use PHPUnit\Framework\TestCase; +use Monolog\Test\TestCase; class LogstashFormatterTest extends TestCase { @@ -22,15 +22,12 @@ class LogstashFormatterTest extends TestCase public function testDefaultFormatterV1() { $formatter = new LogstashFormatter('test', 'hostname'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + datetime: new \DateTimeImmutable("@0"), + ); $message = json_decode($formatter->format($record), true); @@ -56,15 +53,14 @@ public function testDefaultFormatterV1() public function testFormatWithFileAndLineV1() { $formatter = new LogstashFormatter('test'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['file' => 'test', 'line' => 14], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['file' => 'test', 'line' => 14], + ); $message = json_decode($formatter->format($record), true); @@ -78,15 +74,14 @@ public function testFormatWithFileAndLineV1() public function testFormatWithContextV1() { $formatter = new LogstashFormatter('test'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => 'pair'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => 'pair'], + ); $message = json_decode($formatter->format($record), true); @@ -109,15 +104,14 @@ public function testFormatWithContextV1() public function testFormatWithExtraV1() { $formatter = new LogstashFormatter('test'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => 'pair'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => 'pair'], + ); $message = json_decode($formatter->format($record), true); @@ -137,15 +131,14 @@ public function testFormatWithExtraV1() public function testFormatWithApplicationNameV1() { $formatter = new LogstashFormatter('app', 'test'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['key' => 'pair'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + datetime: new \DateTimeImmutable("@0"), + extra: ['key' => 'pair'], + ); $message = json_decode($formatter->format($record), true); @@ -156,17 +149,15 @@ public function testFormatWithApplicationNameV1() public function testFormatWithLatin9Data() { $formatter = new LogstashFormatter('test', 'hostname'); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => '¯\_(ツ)_/¯', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [ + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: '¯\_(ツ)_/¯', + datetime: new \DateTimeImmutable("@0"), + extra: [ 'user_agent' => "\xD6WN; FBCR/OrangeEspa\xF1a; Vers\xE3o/4.0; F\xE4rist", ], - 'message' => 'log', - ]; + ); $message = json_decode($formatter->format($record), true); diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 67f0657ef..ecdb864cd 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -15,11 +15,12 @@ use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; use Monolog\Logger; +use Monolog\Test\TestCase; /** * @author Florian Plattner */ -class MongoDBFormatterTest extends \PHPUnit\Framework\TestCase +class MongoDBFormatterTest extends TestCase { public function setUp(): void { @@ -59,15 +60,12 @@ public function testConstruct($traceDepth, $traceAsString, $expectedTraceDepth, public function testSimpleFormat() { - $record = [ - 'message' => 'some log message', - 'context' => [], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + $record = $this->getRecord( + message: 'some log message', + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(); $formattedRecord = $formatter->format($record); @@ -89,21 +87,19 @@ public function testRecursiveFormat() $someObject->foo = 'something'; $someObject->bar = 'stuff'; - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'stuff' => new \DateTimeImmutable('1969-01-21T21:11:30.213000+00:00'), 'some_object' => $someObject, 'context_string' => 'some string', 'context_int' => 123456, 'except' => new \Exception('exception message', 987), ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.213000+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.213000+00:00'), + ); $formatter = new MongoDBFormatter(); $formattedRecord = $formatter->format($record); @@ -133,9 +129,9 @@ public function testRecursiveFormat() public function testFormatDepthArray() { - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'nest2' => [ 'property' => 'anything', 'nest3' => [ @@ -144,12 +140,10 @@ public function testFormatDepthArray() ], ], ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(2); $formattedResult = $formatter->format($record); @@ -167,9 +161,9 @@ public function testFormatDepthArray() public function testFormatDepthArrayInfiniteNesting() { - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'nest2' => [ 'property' => 'something', 'nest3' => [ @@ -180,12 +174,10 @@ public function testFormatDepthArrayInfiniteNesting() ], ], ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(0); $formattedResult = $formatter->format($record); @@ -214,17 +206,15 @@ public function testFormatDepthObjects() $someObject->nest3->property = 'nothing'; $someObject->nest3->nest4 = 'invisible'; - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'nest2' => $someObject, ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(2, true); $formattedResult = $formatter->format($record); @@ -243,17 +233,15 @@ public function testFormatDepthObjects() public function testFormatDepthException() { - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'nest2' => new \Exception('exception message', 987), ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(2, false); $formattedRecord = $formatter->format($record); diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 00cc1fb90..ab8d7b172 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -11,7 +11,8 @@ namespace Monolog\Formatter; -use PHPUnit\Framework\TestCase; +use Monolog\Test\TestCase; +use Monolog\Logger; /** * @covers Monolog\Formatter\NormalizerFormatter @@ -21,23 +22,23 @@ class NormalizerFormatterTest extends TestCase public function testFormat() { $formatter = new NormalizerFormatter('Y-m-d'); - $formatted = $formatter->format([ - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'message' => 'foo', - 'datetime' => new \DateTimeImmutable, - 'extra' => ['foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => [], 'res' => fopen('php://memory', 'rb')], - 'context' => [ + $formatted = $formatter->format($this->getRecord( + Logger::ERROR, + 'foo', + channel: 'meh', + extra: ['foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => [], 'res' => fopen('php://memory', 'rb')], + context: [ 'foo' => 'bar', 'baz' => 'qux', 'inf' => INF, '-inf' => -INF, 'nan' => acos(4), ], - ]); + )); $this->assertEquals([ 'level_name' => 'ERROR', + 'level' => Logger::ERROR, 'channel' => 'meh', 'message' => 'foo', 'datetime' => date('Y-m-d'), @@ -62,7 +63,7 @@ public function testFormatExceptions() $formatter = new NormalizerFormatter('Y-m-d'); $e = new \LogicException('bar'); $e2 = new \RuntimeException('foo', 0, $e); - $formatted = $formatter->format([ + $formatted = $formatter->normalizeValue([ 'exception' => $e2, ]); @@ -88,7 +89,7 @@ public function testFormatSoapFaultException() $formatter = new NormalizerFormatter('Y-m-d'); $e = new \SoapFault('foo', 'bar', 'hello', 'world'); - $formatted = $formatter->format([ + $formatted = $formatter->normalizeValue([ 'exception' => $e, ]); @@ -108,7 +109,7 @@ public function testFormatSoapFaultException() $formatter = new NormalizerFormatter('Y-m-d'); $e = new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world']); - $formatted = $formatter->format([ + $formatted = $formatter->normalizeValue([ 'exception' => $e, ]); @@ -132,35 +133,22 @@ public function testFormatToStringExceptionHandle() $formatter = new NormalizerFormatter('Y-m-d'); $this->expectException('RuntimeException'); $this->expectExceptionMessage('Could not convert to string'); - $formatter->format([ + $formatter->format($this->getRecord(context: [ 'myObject' => new TestToStringError(), - ]); + ])); } public function testBatchFormat() { $formatter = new NormalizerFormatter('Y-m-d'); $formatted = $formatter->formatBatch([ - [ - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - ], - [ - 'level_name' => 'WARNING', - 'channel' => 'log', - 'message' => 'foo', - 'context' => [], - 'datetime' => new \DateTimeImmutable, - 'extra' => [], - ], + $this->getRecord(Logger::CRITICAL, 'bar', channel: 'test'), + $this->getRecord(Logger::WARNING, 'foo', channel: 'log'), ]); $this->assertEquals([ [ 'level_name' => 'CRITICAL', + 'level' => Logger::CRITICAL, 'channel' => 'test', 'message' => 'bar', 'context' => [], @@ -169,6 +157,7 @@ public function testBatchFormat() ], [ 'level_name' => 'WARNING', + 'level' => Logger::WARNING, 'channel' => 'log', 'message' => 'foo', 'context' => [], @@ -217,7 +206,7 @@ public function testCanNormalizeReferences() $x = ['foo' => 'bar']; $y = ['x' => &$x]; $x['y'] = &$y; - $formatter->format($y); + $formatter->normalizeValue($y); } public function testToJsonIgnoresInvalidTypes() @@ -251,13 +240,11 @@ public function testNormalizeHandleLargeArraysWithExactly1000Items() $formatter = new NormalizerFormatter(); $largeArray = range(1, 1000); - $res = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array($largeArray), - 'datetime' => new \DateTime, - 'extra' => array(), + $res = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'bar', + channel: 'test', + context: [$largeArray], )); $this->assertCount(1000, $res['context'][0]); @@ -269,13 +256,11 @@ public function testNormalizeHandleLargeArrays() $formatter = new NormalizerFormatter(); $largeArray = range(1, 2000); - $res = $formatter->format(array( - 'level_name' => 'CRITICAL', - 'channel' => 'test', - 'message' => 'bar', - 'context' => array($largeArray), - 'datetime' => new \DateTime, - 'extra' => array(), + $res = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'bar', + channel: 'test', + context: [$largeArray], )); $this->assertCount(1001, $res['context'][0]); @@ -328,12 +313,12 @@ public function testMaxNormalizeItemCountWith0ItemsMax() $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); $this->assertEquals( - ["..." => "Over 0 items (6 total), aborting normalization"], + ["..." => "Over 0 items (7 total), aborting normalization"], $message ); } - public function testMaxNormalizeItemCountWith3ItemsMax() + public function testMaxNormalizeItemCountWith2ItemsMax() { $formatter = new NormalizerFormatter(); $formatter->setMaxNormalizeDepth(9); @@ -342,8 +327,18 @@ public function testMaxNormalizeItemCountWith3ItemsMax() $message = $this->formatRecordWithExceptionInContext($formatter, $throwable); + unset($message['context']['exception']['trace']); + unset($message['context']['exception']['file']); $this->assertEquals( - ["level_name" => "CRITICAL", "channel" => "core", "..." => "Over 2 items (6 total), aborting normalization"], + [ + "message" => "foobar", + "context" => ['exception' => [ + 'class' => 'Error', + 'message' => 'Foo', + 'code' => 0, + ]], + "..." => "Over 2 items (7 total), aborting normalization" + ], $message ); } @@ -366,7 +361,7 @@ public function testExceptionTraceWithArgs() } $formatter = new NormalizerFormatter(); - $record = ['context' => ['exception' => $e]]; + $record = $this->getRecord(context: ['exception' => $e]); $result = $formatter->format($record); $this->assertSame( @@ -383,14 +378,12 @@ public function testExceptionTraceWithArgs() */ private function formatRecordWithExceptionInContext(NormalizerFormatter $formatter, \Throwable $exception) { - $message = $formatter->format([ - 'level_name' => 'CRITICAL', - 'channel' => 'core', - 'context' => ['exception' => $exception], - 'datetime' => null, - 'extra' => [], - 'message' => 'foobar', - ]); + $message = $formatter->format($this->getRecord( + Logger::CRITICAL, + 'foobar', + channel: 'core', + context: ['exception' => $exception], + )); return $message; } @@ -404,7 +397,7 @@ public function testExceptionTraceDoesNotLeakCallUserFuncArgs() } $formatter = new NormalizerFormatter(); - $record = array('context' => array('exception' => $e)); + $record = $this->getRecord(context: ['exception' => $e]); $result = $formatter->format($record); $this->assertSame( diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index c72227f7d..21f9d6cd2 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -12,8 +12,9 @@ namespace Monolog\Formatter; use Monolog\DateTimeImmutable; +use Monolog\Test\TestCase; -class ScalarFormatterTest extends \PHPUnit\Framework\TestCase +class ScalarFormatterTest extends TestCase { private $formatter; @@ -43,7 +44,7 @@ public function encodeJson($data) public function testFormat() { $exception = new \Exception('foo'); - $formatted = $this->formatter->format([ + $formatted = $this->formatter->format($this->getRecord(context: [ 'foo' => 'string', 'bar' => 1, 'baz' => false, @@ -51,56 +52,50 @@ public function testFormat() 'bat' => ['foo' => 'bar'], 'bap' => $dt = new DateTimeImmutable(true), 'ban' => $exception, - ]); + ])); - $this->assertSame([ + $this->assertSame($this->encodeJson([ 'foo' => 'string', 'bar' => 1, 'baz' => false, - 'bam' => $this->encodeJson([1, 2, 3]), - 'bat' => $this->encodeJson(['foo' => 'bar']), + 'bam' => [1, 2, 3], + 'bat' => ['foo' => 'bar'], 'bap' => (string) $dt, - 'ban' => $this->encodeJson([ + 'ban' => [ 'class' => get_class($exception), 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), 'trace' => $this->buildTrace($exception), - ]), - ], $formatted); + ], + ]), $formatted['context']); } public function testFormatWithErrorContext() { $context = ['file' => 'foo', 'line' => 1]; - $formatted = $this->formatter->format([ - 'context' => $context, - ]); + $formatted = $this->formatter->format($this->getRecord( + context: $context, + )); - $this->assertSame([ - 'context' => $this->encodeJson($context), - ], $formatted); + $this->assertSame($this->encodeJson($context), $formatted['context']); } public function testFormatWithExceptionContext() { $exception = new \Exception('foo'); - $formatted = $this->formatter->format([ - 'context' => [ - 'exception' => $exception, - ], - ]); + $formatted = $this->formatter->format($this->getRecord(context: [ + 'exception' => $exception, + ])); - $this->assertSame([ - 'context' => $this->encodeJson([ - 'exception' => [ - 'class' => get_class($exception), - 'message' => $exception->getMessage(), - 'code' => $exception->getCode(), - 'file' => $exception->getFile() . ':' . $exception->getLine(), - 'trace' => $this->buildTrace($exception), - ], - ]), - ], $formatted); + $this->assertSame($this->encodeJson([ + 'exception' => [ + 'class' => get_class($exception), + 'message' => $exception->getMessage(), + 'code' => $exception->getCode(), + 'file' => $exception->getFile() . ':' . $exception->getLine(), + 'trace' => $this->buildTrace($exception), + ] + ]), $formatted['context']); } } diff --git a/tests/Monolog/Formatter/WildfireFormatterTest.php b/tests/Monolog/Formatter/WildfireFormatterTest.php index 06c75169f..a3babee0d 100644 --- a/tests/Monolog/Formatter/WildfireFormatterTest.php +++ b/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -12,8 +12,9 @@ namespace Monolog\Formatter; use Monolog\Logger; +use Monolog\Test\TestCase; -class WildfireFormatterTest extends \PHPUnit\Framework\TestCase +class WildfireFormatterTest extends TestCase { /** * @covers Monolog\Formatter\WildfireFormatter::format @@ -21,15 +22,13 @@ class WildfireFormatterTest extends \PHPUnit\Framework\TestCase public function testDefaultFormat() { $wildfire = new WildfireFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['ip' => '127.0.0.1'], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + extra: ['ip' => '127.0.0.1'], + ); $message = $wildfire->format($record); @@ -46,15 +45,13 @@ public function testDefaultFormat() public function testFormatWithFileAndLine() { $wildfire = new WildfireFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['from' => 'logger'], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => ['ip' => '127.0.0.1', 'file' => 'test', 'line' => 14], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + context: ['from' => 'logger'], + extra: ['ip' => '127.0.0.1', 'file' => 'test', 'line' => 14], + ); $message = $wildfire->format($record); @@ -71,15 +68,11 @@ public function testFormatWithFileAndLine() public function testFormatWithoutContext() { $wildfire = new WildfireFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + ); $message = $wildfire->format($record); @@ -97,15 +90,11 @@ public function testBatchFormatThrowException() $this->expectException(\BadMethodCallException::class); $wildfire = new WildfireFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => [], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $record = $this->getRecord( + Logger::ERROR, + 'log', + channel: 'meh', + ); $wildfire->formatBatch([$record]); } @@ -116,11 +105,11 @@ public function testBatchFormatThrowException() public function testTableFormat() { $wildfire = new WildfireFormatter(); - $record = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'table-channel', - 'context' => [ + $record = $this->getRecord( + Logger::ERROR, + 'table-message', + channel: 'table-channel', + context: [ 'table' => [ ['col1', 'col2', 'col3'], ['val1', 'val2', 'val3'], @@ -128,10 +117,7 @@ public function testTableFormat() ['bar1', 'bar2', 'bar3'], ], ], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'table-message', - ]; + ); $message = $wildfire->format($record); diff --git a/tests/Monolog/Handler/DeduplicationHandlerTest.php b/tests/Monolog/Handler/DeduplicationHandlerTest.php index ef4fb0a6b..b5c760c7d 100644 --- a/tests/Monolog/Handler/DeduplicationHandlerTest.php +++ b/tests/Monolog/Handler/DeduplicationHandlerTest.php @@ -87,11 +87,9 @@ public function testFlushPassthruIfLogTooOld() $test = new TestHandler(); $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); - $record = $this->getRecord(Logger::ERROR); - $record['datetime'] = $record['datetime']->modify('+62seconds'); + $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable('+62seconds')); $handler->handle($record); - $record = $this->getRecord(Logger::CRITICAL); - $record['datetime'] = $record['datetime']->modify('+62seconds'); + $record = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('+62seconds')); $handler->handle($record); $handler->flush(); @@ -114,14 +112,11 @@ public function testGcOldLogs() $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); // handle two records from yesterday, and one recent - $record = $this->getRecord(Logger::ERROR); - $record['datetime'] = $record['datetime']->modify('-1day -10seconds'); + $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable('-1day -10seconds')); $handler->handle($record); - $record2 = $this->getRecord(Logger::CRITICAL); - $record2['datetime'] = $record2['datetime']->modify('-1day -10seconds'); + $record2 = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('-1day -10seconds')); $handler->handle($record2); - $record3 = $this->getRecord(Logger::CRITICAL); - $record3['datetime'] = $record3['datetime']->modify('-30seconds'); + $record3 = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('-30seconds')); $handler->handle($record3); // log is written as none of them are duplicate diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index fdaa14e1c..1fa3be3b4 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -58,15 +58,7 @@ public function setUp(): void public function testHandle() { // log message - $msg = new LogRecord( - level: Logger::ERROR, - levelName: 'ERROR', - channel: 'meh', - context: ['foo' => 7, 'bar', 'class' => new \stdClass], - datetime: new \DateTimeImmutable("@0"), - extra: [], - message: 'log', - ); + $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); // format expected result $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']); @@ -166,17 +158,9 @@ public function providerTestConnectionErrors() */ public function testHandleIntegration() { - $msg = new LogRecord( - level: Logger::ERROR, - levelName: 'ERROR', - channel: 'meh', - context: ['foo' => 7, 'bar', 'class' => new \stdClass], - datetime: new \DateTimeImmutable("@0"), - extra: [], - message: 'log', - ); + $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); - $expected = (array) $msg; + $expected = $msg->toArray(); $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); $expected['context'] = [ 'class' => '[object] (stdClass: {})', @@ -220,15 +204,7 @@ public function testHandleIntegration() */ public function testHandleIntegrationNewESVersion() { - $msg = new LogRecord( - level: Logger::ERROR, - levelName: 'ERROR', - channel: 'meh', - context: ['foo' => 7, 'bar', 'class' => new \stdClass], - datetime: new \DateTimeImmutable("@0"), - extra: [], - message: 'log', - ); + $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); $expected = (array) $msg; $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 764c54c95..ba4de76bb 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -56,15 +56,7 @@ public function setUp(): void public function testHandle() { // log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); // format expected result $formatter = new ElasticsearchFormatter($this->options['index'], $this->options['type']); @@ -180,17 +172,9 @@ public function providerTestConnectionErrors() */ public function testHandleIntegration() { - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; + $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); - $expected = $msg; + $expected = $msg->toArray(); $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); $expected['context'] = [ 'class' => ["stdClass" => []], diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index 7ffff5a1a..8847a16d8 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -209,8 +209,7 @@ public function testChannelLevelActivationStrategy() $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, ['othertest' => Logger::DEBUG])); $handler->handle($this->getRecord(Logger::WARNING)); $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG); - $record['channel'] = 'othertest'; + $record = $this->getRecord(Logger::DEBUG, channel: 'othertest'); $handler->handle($record); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); @@ -226,8 +225,7 @@ public function testChannelLevelActivationStrategyWithPsrLevels() $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy('error', ['othertest' => 'debug'])); $handler->handle($this->getRecord(Logger::WARNING)); $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG); - $record['channel'] = 'othertest'; + $record = $this->getRecord(Logger::DEBUG, channel: 'othertest'); $handler->handle($record); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); @@ -242,7 +240,7 @@ public function testHandleUsesProcessors() $test = new TestHandler(); $handler = new FingersCrossedHandler($test, Logger::INFO); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); diff --git a/tests/Monolog/Handler/FleepHookHandlerTest.php b/tests/Monolog/Handler/FleepHookHandlerTest.php index de01c44b8..029d05081 100644 --- a/tests/Monolog/Handler/FleepHookHandlerTest.php +++ b/tests/Monolog/Handler/FleepHookHandlerTest.php @@ -56,15 +56,7 @@ public function testConstructorSetsExpectedDefaults() */ public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays() { - $record = [ - 'message' => 'msg', - 'context' => [], - 'level' => Logger::DEBUG, - 'level_name' => Logger::getLevelName(Logger::DEBUG), - 'channel' => 'channel', - 'datetime' => new \DateTimeImmutable(), - 'extra' => [], - ]; + $record = $this->getRecord(Logger::DEBUG, 'msg'); $expectedFormatter = new LineFormatter(null, null, true, true); $expected = $expectedFormatter->format($record); diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 6a23423df..eecc2e4c8 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -93,9 +93,12 @@ public function testWarning() public function testInjectedGelfMessageFormatter() { - $record = $this->getRecord(Logger::WARNING, "A test warning message"); - $record['extra']['blarg'] = 'yep'; - $record['context']['from'] = 'logger'; + $record = $this->getRecord( + Logger::WARNING, + "A test warning message", + extra: ['blarg' => 'yep'], + context: ['from' => 'logger'], + ); $expectedMessage = new Message(); $expectedMessage diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index 82be0d6f4..6cc976a70 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -43,7 +43,7 @@ public function testHandleWithLibraryClient() ->will($this->returnValue($collection)); $record = $this->getRecord(); - $expected = $record; + $expected = $record->toArray(); $expected['datetime'] = new \MongoDB\BSON\UTCDateTime((int) floor(((float) $record['datetime']->format('U.u')) * 1000)); $collection->expects($this->once()) diff --git a/tests/Monolog/Handler/PsrHandlerTest.php b/tests/Monolog/Handler/PsrHandlerTest.php index bebaa71d2..e3f30bfaa 100644 --- a/tests/Monolog/Handler/PsrHandlerTest.php +++ b/tests/Monolog/Handler/PsrHandlerTest.php @@ -46,7 +46,7 @@ public function testHandlesAllLevels($levelName, $level) ->with(strtolower($levelName), $message, $context); $handler = new PsrHandler($psrLogger); - $handler->handle(['level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context]); + $handler->handle($this->getRecord($level, $message, context: $context)); } public function testFormatter() @@ -63,6 +63,6 @@ public function testFormatter() $handler = new PsrHandler($psrLogger); $handler->setFormatter(new LineFormatter('dummy')); - $handler->handle(['level' => $level, 'level_name' => $levelName, 'message' => $message, 'context' => $context, 'extra' => [], 'date' => new \DateTimeImmutable()]); + $handler->handle($this->getRecord($level, $message, context: $context, datetime: new \DateTimeImmutable())); } } diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 129ee3743..7cb832542 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -38,12 +38,12 @@ public function testWeSplitIntoLines() ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); - $socket->expects($this->at(0)) + $socket->expects($this->atLeast(2)) ->method('write') - ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - "); - $socket->expects($this->at(1)) - ->method('write') - ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - "); + ->withConsecutive( + [$this->equalTo("lol"), $this->equalTo("<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - ")], + [$this->equalTo("hej"), $this->equalTo("<".(LOG_AUTHPRIV + LOG_WARNING).">1 $time $host php $pid - - ")], + ); $handler->setSocket($socket); @@ -64,7 +64,7 @@ public function testSplitWorksOnEmptyMsg() $handler->setSocket($socket); - $handler->handle($this->getRecordWithMessage(null)); + $handler->handle($this->getRecordWithMessage('')); } public function testRfc() @@ -84,12 +84,12 @@ public function testRfc() ->setConstructorArgs(array('lol', 999)) ->onlyMethods(array('write')) ->getMock(); - $socket->expects($this->at(0)) - ->method('write') - ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: "); - $socket->expects($this->at(1)) + $socket->expects($this->atLeast(2)) ->method('write') - ->with("hej", "<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: "); + ->withConsecutive( + [$this->equalTo("lol"), $this->equalTo("<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: ")], + [$this->equalTo("hej"), $this->equalTo("<".(LOG_AUTHPRIV + LOG_WARNING).">$time $host php[$pid]: ")], + ); $handler->setSocket($socket); @@ -98,6 +98,6 @@ public function testRfc() protected function getRecordWithMessage($msg) { - return ['message' => $msg, 'level' => \Monolog\Logger::WARNING, 'context' => null, 'extra' => [], 'channel' => 'lol', 'datetime' => new \DateTimeImmutable('2014-01-07 12:34:56')]; + return $this->getRecord(message: $msg, level: \Monolog\Logger::WARNING, channel: 'lol', datetime: new \DateTimeImmutable('2014-01-07 12:34:56')); } } diff --git a/tests/Monolog/Handler/TestHandlerTest.php b/tests/Monolog/Handler/TestHandlerTest.php index cc8e60ff2..b4609c92c 100644 --- a/tests/Monolog/Handler/TestHandlerTest.php +++ b/tests/Monolog/Handler/TestHandlerTest.php @@ -27,8 +27,8 @@ public function testHandler($method, $level) $handler = new TestHandler; $record = $this->getRecord($level, 'test'.$method); $this->assertFalse($handler->hasRecords($level)); - $this->assertFalse($handler->hasRecord($record, $level)); - $this->assertFalse($handler->{'has'.$method}($record), 'has'.$method); + $this->assertFalse($handler->hasRecord($record->message, $level)); + $this->assertFalse($handler->{'has'.$method}($record->message), 'has'.$method); $this->assertFalse($handler->{'has'.$method.'ThatContains'}('test'), 'has'.$method.'ThatContains'); $this->assertFalse($handler->{'has'.$method.'ThatPasses'}(function ($rec) { return true; @@ -39,8 +39,8 @@ public function testHandler($method, $level) $this->assertFalse($handler->{'has'.$method}('bar'), 'has'.$method); $this->assertTrue($handler->hasRecords($level)); - $this->assertTrue($handler->hasRecord($record, $level)); - $this->assertTrue($handler->{'has'.$method}($record), 'has'.$method); + $this->assertTrue($handler->hasRecord($record->message, $level)); + $this->assertTrue($handler->{'has'.$method}($record->message), 'has'.$method); $this->assertTrue($handler->{'has'.$method}('test'.$method), 'has'.$method); $this->assertTrue($handler->{'has'.$method.'ThatContains'}('test'), 'has'.$method.'ThatContains'); $this->assertTrue($handler->{'has'.$method.'ThatPasses'}(function ($rec) { @@ -50,7 +50,7 @@ public function testHandler($method, $level) $this->assertTrue($handler->{'has'.$method.'Records'}(), 'has'.$method.'Records'); $records = $handler->getRecords(); - unset($records[0]['formatted']); + $records[0]->formatted = null; $this->assertEquals([$record], $records); } diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index bd5ae20d3..f49a6f457 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -13,8 +13,9 @@ use Monolog\Processor\WebProcessor; use Monolog\Handler\TestHandler; +use Monolog\Test\TestCase; -class LoggerTest extends \PHPUnit\Framework\TestCase +class LoggerTest extends TestCase { /** * @covers Monolog\Logger::getName @@ -91,11 +92,11 @@ public function testLog() { $logger = new Logger(__METHOD__); - $handler = $this->prophesize('Monolog\Handler\NullHandler'); - $handler->handle(\Prophecy\Argument::any())->shouldBeCalled(); - $handler->isHandling(['level' => 300])->willReturn(true); + $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); + $handler->expects($this->never())->method('isHandling'); + $handler->expects($this->once())->method('handle'); - $logger->pushHandler($handler->reveal()); + $logger->pushHandler($handler); $this->assertTrue($logger->addRecord(Logger::WARNING, 'test')); } @@ -103,15 +104,32 @@ public function testLog() /** * @covers Monolog\Logger::addRecord */ - public function testLogNotHandled() + public function testLogAlwaysHandledIfNoProcessorsArePresent() { $logger = new Logger(__METHOD__); - $handler = $this->prophesize('Monolog\Handler\NullHandler'); - $handler->handle()->shouldNotBeCalled(); - $handler->isHandling(['level' => 300])->willReturn(false); + $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); + $handler->expects($this->never())->method('isHandling'); + $handler->expects($this->once())->method('handle'); + + $logger->pushHandler($handler); - $logger->pushHandler($handler->reveal()); + $this->assertTrue($logger->addRecord(Logger::WARNING, 'test')); + } + + /** + * @covers Monolog\Logger::addRecord + */ + public function testLogNotHandledIfProcessorsArePresent() + { + $logger = new Logger(__METHOD__); + + $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); + $handler->expects($this->once())->method('isHandling')->will($this->returnValue(false)); + $handler->expects($this->never())->method('handle'); + + $logger->pushProcessor(fn (LogRecord $record) => $record); + $logger->pushHandler($handler); $this->assertFalse($logger->addRecord(Logger::WARNING, 'test')); } @@ -273,9 +291,10 @@ public function testProcessorsNotCalledWhenNotHandled() /** * @covers Monolog\Logger::addRecord */ - public function testHandlersNotCalledBeforeFirstHandling() + public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresent() { $logger = new Logger(__METHOD__); + $logger->pushProcessor(fn($record) => $record); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->never()) @@ -315,7 +334,7 @@ public function testHandlersNotCalledBeforeFirstHandling() /** * @covers Monolog\Logger::addRecord */ - public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray() + public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresentWithAssocArray() { $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->never()) @@ -347,6 +366,7 @@ public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray() ; $logger = new Logger(__METHOD__, ['last' => $handler3, 'second' => $handler2, 'first' => $handler1]); + $logger->pushProcessor(fn($record) => $record); $logger->debug('test'); } @@ -627,7 +647,7 @@ public function testCustomHandleException() $that = $this; $logger->setExceptionHandler(function ($e, $record) use ($that) { $that->assertEquals($e->getMessage(), 'Some handler exception'); - $that->assertTrue(is_array($record)); + $that->assertInstanceOf(LogRecord::class, $record); $that->assertEquals($record['message'], 'test'); }); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); diff --git a/tests/Monolog/Processor/IntrospectionProcessorTest.php b/tests/Monolog/Processor/IntrospectionProcessorTest.php index b19175af1..cb1d8b91c 100644 --- a/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ b/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -66,10 +66,7 @@ public function testProcessorFromFunc() public function testLevelTooLow() { - $input = [ - 'level' => Logger::DEBUG, - 'extra' => [], - ]; + $input = $this->getRecord(Logger::DEBUG); $expected = $input; @@ -81,10 +78,7 @@ public function testLevelTooLow() public function testLevelEqual() { - $input = [ - 'level' => Logger::CRITICAL, - 'extra' => [], - ]; + $input = $this->getRecord(Logger::CRITICAL); $expected = $input; $expected['extra'] = [ @@ -103,10 +97,7 @@ public function testLevelEqual() public function testLevelHigher() { - $input = [ - 'level' => Logger::EMERGENCY, - 'extra' => [], - ]; + $input = $this->getRecord(Logger::EMERGENCY); $expected = $input; $expected['extra'] = [ From b586dbe8e64e4ba1282ce1a5457a70c5389c9aa7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 27 Feb 2022 09:26:48 +0100 Subject: [PATCH 411/498] Remove SwiftMailerHandler --- src/Monolog/Handler/SwiftMailerHandler.php | 112 ----------------- .../Handler/SwiftMailerHandlerTest.php | 115 ------------------ 2 files changed, 227 deletions(-) delete mode 100644 src/Monolog/Handler/SwiftMailerHandler.php delete mode 100644 tests/Monolog/Handler/SwiftMailerHandlerTest.php diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php deleted file mode 100644 index be7e2a587..000000000 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; -use Monolog\Utils; -use Monolog\Formatter\FormatterInterface; -use Monolog\Formatter\LineFormatter; -use Swift_Message; -use Swift; - -/** - * SwiftMailerHandler uses Swift_Mailer to send the emails - * - * @author Gyula Sallai - * - * @phpstan-import-type Record from \Monolog\Logger - */ -class SwiftMailerHandler extends MailHandler -{ - /** @var \Swift_Mailer */ - protected $mailer; - /** @var Swift_Message|callable(string, Record[]): Swift_Message */ - private $messageTemplate; - - /** - * @psalm-param Swift_Message|callable(string, Record[]): Swift_Message $message - * - * @param \Swift_Mailer $mailer The mailer to use - * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced - */ - public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, bool $bubble = true) - { - parent::__construct($level, $bubble); - - $this->mailer = $mailer; - $this->messageTemplate = $message; - } - - /** - * {@inheritDoc} - */ - protected function send(string $content, array $records): void - { - $this->mailer->send($this->buildMessage($content, $records)); - } - - /** - * Gets the formatter for the Swift_Message subject. - * - * @param string|null $format The format of the subject - */ - protected function getSubjectFormatter(?string $format): FormatterInterface - { - return new LineFormatter($format); - } - - /** - * Creates instance of Swift_Message to be sent - * - * @param string $content formatted email body to be sent - * @param array $records Log records that formed the content - * @return Swift_Message - * - * @phpstan-param Record[] $records - */ - protected function buildMessage(string $content, array $records): Swift_Message - { - $message = null; - if ($this->messageTemplate instanceof Swift_Message) { - $message = clone $this->messageTemplate; - $message->generateId(); - } elseif (is_callable($this->messageTemplate)) { - $message = ($this->messageTemplate)($content, $records); - } - - if (!$message instanceof Swift_Message) { - $record = reset($records); - throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); - } - - if ($records) { - $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); - $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); - } - - $mime = 'text/plain'; - if ($this->isHtmlBody($content)) { - $mime = 'text/html'; - } - - $message->setBody($content, $mime); - /** @phpstan-ignore-next-line */ - if (version_compare(Swift::VERSION, '6.0.0', '>=')) { - $message->setDate(new \DateTimeImmutable()); - } else { - /** @phpstan-ignore-next-line */ - $message->setDate(time()); - } - - return $message; - } -} diff --git a/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/tests/Monolog/Handler/SwiftMailerHandlerTest.php deleted file mode 100644 index 51596c392..000000000 --- a/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ /dev/null @@ -1,115 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; -use Monolog\Test\TestCase; -use PHPUnit\Framework\MockObject\MockObject; - -class SwiftMailerHandlerTest extends TestCase -{ - /** @var \Swift_Mailer|MockObject */ - private $mailer; - - public function setUp(): void - { - $this->mailer = $this - ->getMockBuilder('Swift_Mailer') - ->disableOriginalConstructor() - ->getMock(); - } - - public function testMessageCreationIsLazyWhenUsingCallback() - { - $this->mailer->expects($this->never()) - ->method('send'); - - $callback = function () { - throw new \RuntimeException('Swift_Message creation callback should not have been called in this test'); - }; - $handler = new SwiftMailerHandler($this->mailer, $callback); - - $records = [ - $this->getRecord(Logger::DEBUG), - $this->getRecord(Logger::INFO), - ]; - $handler->handleBatch($records); - } - - public function testMessageCanBeCustomizedGivenLoggedData() - { - // Wire Mailer to expect a specific Swift_Message with a customized Subject - $expectedMessage = new \Swift_Message(); - $this->mailer->expects($this->once()) - ->method('send') - ->with($this->callback(function ($value) use ($expectedMessage) { - return $value instanceof \Swift_Message - && $value->getSubject() === 'Emergency' - && $value === $expectedMessage; - })); - - // Callback dynamically changes subject based on number of logged records - $callback = function ($content, array $records) use ($expectedMessage) { - $subject = count($records) > 0 ? 'Emergency' : 'Normal'; - $expectedMessage->setSubject($subject); - - return $expectedMessage; - }; - $handler = new SwiftMailerHandler($this->mailer, $callback); - - // Logging 1 record makes this an Emergency - $records = [ - $this->getRecord(Logger::EMERGENCY), - ]; - $handler->handleBatch($records); - } - - public function testMessageSubjectFormatting() - { - // Wire Mailer to expect a specific Swift_Message with a customized Subject - $messageTemplate = new \Swift_Message(); - $messageTemplate->setSubject('Alert: %level_name% %message%'); - $receivedMessage = null; - - $this->mailer->expects($this->once()) - ->method('send') - ->with($this->callback(function ($value) use (&$receivedMessage) { - $receivedMessage = $value; - - return true; - })); - - $handler = new SwiftMailerHandler($this->mailer, $messageTemplate); - - $records = [ - $this->getRecord(Logger::EMERGENCY), - ]; - $handler->handleBatch($records); - - $this->assertEquals('Alert: EMERGENCY test', $receivedMessage->getSubject()); - } - - public function testMessageHaveUniqueId() - { - $messageTemplate = new \Swift_Message(); - $handler = new SwiftMailerHandler($this->mailer, $messageTemplate); - - $method = new \ReflectionMethod('Monolog\Handler\SwiftMailerHandler', 'buildMessage'); - $method->setAccessible(true); - $method->invokeArgs($handler, [$messageTemplate, []]); - - $builtMessage1 = $method->invoke($handler, $messageTemplate, []); - $builtMessage2 = $method->invoke($handler, $messageTemplate, []); - - $this->assertFalse($builtMessage1->getId() === $builtMessage2->getId(), 'Two different messages have the same id'); - } -} From 5eb9b8ed931f962be479c62560192a6701c5c130 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 5 Mar 2022 14:03:57 +0100 Subject: [PATCH 412/498] Code cleanups --- doc/01-usage.md | 12 +++--- doc/04-extending.md | 10 ++--- src/Monolog/Formatter/ChromePHPFormatter.php | 20 +++++----- src/Monolog/Formatter/FlowdockFormatter.php | 12 +++--- src/Monolog/Formatter/FluentdFormatter.php | 16 ++++---- .../Formatter/GelfMessageFormatter.php | 22 +++++------ src/Monolog/Formatter/HtmlFormatter.php | 16 ++++---- src/Monolog/Formatter/JsonFormatter.php | 20 +++++----- src/Monolog/Formatter/LogstashFormatter.php | 34 ++++++++--------- src/Monolog/Formatter/MongoDBFormatter.php | 2 +- src/Monolog/Formatter/WildfireFormatter.php | 32 ++++++++-------- src/Monolog/Handler/AbstractHandler.php | 2 +- .../Handler/AbstractProcessingHandler.php | 8 +--- src/Monolog/Handler/AmqpHandler.php | 10 +---- src/Monolog/Handler/BrowserConsoleHandler.php | 34 ++++++++--------- src/Monolog/Handler/BufferHandler.php | 29 +++++++-------- src/Monolog/Handler/ChromePHPHandler.php | 8 ++-- src/Monolog/Handler/CouchDBHandler.php | 2 +- src/Monolog/Handler/CubeHandler.php | 16 ++++---- src/Monolog/Handler/Curl/Util.php | 2 +- src/Monolog/Handler/DeduplicationHandler.php | 18 +++------ .../Handler/DoctrineCouchDBHandler.php | 2 +- src/Monolog/Handler/DynamoDbHandler.php | 2 +- src/Monolog/Handler/ElasticaHandler.php | 2 +- src/Monolog/Handler/ElasticsearchHandler.php | 4 +- src/Monolog/Handler/ErrorLogHandler.php | 4 +- src/Monolog/Handler/FallbackGroupHandler.php | 4 -- src/Monolog/Handler/FilterHandler.php | 11 ++---- .../ActivationStrategyInterface.php | 4 -- .../ChannelLevelActivationStrategy.php | 11 ++---- .../ErrorLevelActivationStrategy.php | 2 +- src/Monolog/Handler/FingersCrossedHandler.php | 13 ++----- src/Monolog/Handler/FirePHPHandler.php | 6 +-- src/Monolog/Handler/FleepHookHandler.php | 6 +-- src/Monolog/Handler/FlowdockHandler.php | 6 +-- src/Monolog/Handler/GelfHandler.php | 2 +- src/Monolog/Handler/GroupHandler.php | 4 -- src/Monolog/Handler/IFTTTHandler.php | 4 +- src/Monolog/Handler/InsightOpsHandler.php | 2 +- src/Monolog/Handler/LogEntriesHandler.php | 2 +- src/Monolog/Handler/LogglyHandler.php | 10 ++--- src/Monolog/Handler/LogmaticHandler.php | 2 +- src/Monolog/Handler/MailHandler.php | 10 ++--- src/Monolog/Handler/MandrillHandler.php | 2 +- src/Monolog/Handler/MongoDBHandler.php | 15 ++++---- src/Monolog/Handler/NewRelicHandler.php | 24 ++++++------ src/Monolog/Handler/NullHandler.php | 4 +- src/Monolog/Handler/OverflowHandler.php | 4 +- src/Monolog/Handler/PHPConsoleHandler.php | 21 +++-------- src/Monolog/Handler/ProcessHandler.php | 2 +- .../Handler/ProcessableHandlerInterface.php | 7 ++-- .../Handler/ProcessableHandlerTrait.php | 2 +- src/Monolog/Handler/PsrHandler.php | 4 +- src/Monolog/Handler/PushoverHandler.php | 16 +++----- src/Monolog/Handler/RedisHandler.php | 14 +++---- src/Monolog/Handler/RedisPubSubHandler.php | 6 +-- src/Monolog/Handler/RollbarHandler.php | 14 +++---- src/Monolog/Handler/RotatingFileHandler.php | 2 +- src/Monolog/Handler/SamplingHandler.php | 9 +---- src/Monolog/Handler/Slack/SlackRecord.php | 37 ++++++++----------- src/Monolog/Handler/SlackHandler.php | 5 --- src/Monolog/Handler/SocketHandler.php | 8 +--- src/Monolog/Handler/SqsHandler.php | 4 +- src/Monolog/Handler/StreamHandler.php | 7 +--- src/Monolog/Handler/SyslogHandler.php | 2 +- src/Monolog/Handler/SyslogUdpHandler.php | 4 +- src/Monolog/Handler/TelegramBotHandler.php | 6 +-- src/Monolog/Handler/TestHandler.php | 26 ++++++------- .../Handler/WhatFailureGroupHandler.php | 9 ++--- src/Monolog/Handler/ZendMonitorHandler.php | 14 +++---- src/Monolog/Processor/GitProcessor.php | 4 +- src/Monolog/Processor/HostnameProcessor.php | 2 +- .../Processor/IntrospectionProcessor.php | 26 ++++++------- .../Processor/MemoryPeakUsageProcessor.php | 2 +- .../Processor/MemoryUsageProcessor.php | 2 +- src/Monolog/Processor/MercurialProcessor.php | 4 +- src/Monolog/Processor/ProcessIdProcessor.php | 2 +- .../Processor/PsrLogMessageProcessor.php | 8 ++-- src/Monolog/Processor/UidProcessor.php | 2 +- src/Monolog/Processor/WebProcessor.php | 2 +- src/Monolog/Test/TestCase.php | 3 +- tests/Monolog/Formatter/JsonFormatterTest.php | 8 ++-- .../Monolog/Formatter/LogglyFormatterTest.php | 2 +- tests/Monolog/Handler/BufferHandlerTest.php | 2 +- .../Handler/DeduplicationHandlerTest.php | 4 +- .../Handler/DoctrineCouchDBHandlerTest.php | 2 +- .../Handler/FallbackGroupHandlerTest.php | 6 +-- tests/Monolog/Handler/FilterHandlerTest.php | 2 +- tests/Monolog/Handler/GelfHandlerTest.php | 12 +++--- tests/Monolog/Handler/GroupHandlerTest.php | 6 +-- tests/Monolog/Handler/MailHandlerTest.php | 2 +- tests/Monolog/Handler/MongoDBHandlerTest.php | 2 +- tests/Monolog/Handler/NewRelicHandlerTest.php | 6 +-- .../Monolog/Handler/Slack/SlackRecordTest.php | 10 ++--- .../Handler/SlackWebhookHandlerTest.php | 2 +- .../Handler/WhatFailureGroupHandlerTest.php | 8 ++-- .../Handler/ZendMonitorHandlerTest.php | 8 ++-- tests/Monolog/LoggerTest.php | 24 ++++++------ tests/Monolog/Processor/GitProcessorTest.php | 4 +- .../Processor/HostnameProcessorTest.php | 8 ++-- .../Processor/IntrospectionProcessorTest.php | 16 ++++---- .../MemoryPeakUsageProcessorTest.php | 10 ++--- .../Processor/MemoryUsageProcessorTest.php | 10 ++--- .../Processor/MercurialProcessorTest.php | 6 +-- .../Processor/ProcessIdProcessorTest.php | 8 ++-- tests/Monolog/Processor/TagProcessorTest.php | 8 ++-- tests/Monolog/Processor/UidProcessorTest.php | 2 +- tests/Monolog/Processor/WebProcessorTest.php | 24 ++++++------ tests/Monolog/PsrLogCompatTest.php | 2 +- 109 files changed, 418 insertions(+), 549 deletions(-) diff --git a/doc/01-usage.md b/doc/01-usage.md index 52deef6d4..89e0fe7fa 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -140,7 +140,7 @@ write a processor adding some dummy data in the record: pushProcessor(function ($record) { - $record['extra']['dummy'] = 'Hello world!'; + $record->extra['dummy'] = 'Hello world!'; return $record; }); @@ -190,23 +190,23 @@ $securityLogger = $logger->withName('security'); ## Customizing the log format In Monolog it's easy to customize the format of the logs written into files, -sockets, mails, databases and other handlers; by the use of "Formatters". +sockets, mails, databases and other handlers; by the use of "Formatters". As mentioned before, a *Formatter* is attached to a *Handler*, and as a general convention, most of the handlers use the ```php -$record['formatted'] +$record->formatted ``` field in the log record to store its formatted value. Again, this field depends on the implementation of the *Handler* but is a good idea to **stick into the good practices and conventions of the project**. You can choose between predefined formatter classes or write your own (e.g. a multiline text file for human-readable output). > Note: -> +> > A very useful formatter to look at, is the `LineFormatter`. -> +> > This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. > -> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'", in this example the values $record["context"]["foo"] and $record["extra"]["foo"] will be rendered as part of the final result. +> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record->context["foo"] and $record->extra["foo"] will be rendered as part of th final result. In the following example, we demonstrate how to: 1. Create a `LineFormatter` instance and set a custom output format template. diff --git a/doc/04-extending.md b/doc/04-extending.md index c7075c760..0a2ad3386 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -43,10 +43,10 @@ class PDOHandler extends AbstractProcessingHandler } $this->statement->execute(array( - 'channel' => $record['channel'], - 'level' => $record['level'], - 'message' => $record['formatted'], - 'time' => $record['datetime']->format('U'), + 'channel' => $record->channel, + 'level' => $record->level, + 'message' => $record->formatted, + 'time' => $record->datetime->format('U'), )); } @@ -78,6 +78,6 @@ $logger->info('My logger is now ready'); The `Monolog\Handler\AbstractProcessingHandler` class provides most of the logic needed for the handler, including the use of processors and the formatting -of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``). +of the record (which is why we use ``$record->formatted`` instead of ``$record->message``). ← [Utility classes](03-utilities.md) diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index b588e3164..e855d64ac 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -44,27 +44,27 @@ public function format(LogRecord $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 ($record['context']) { - $message['context'] = $record['context']; + $message = ['message' => $record->message]; + if ($record->context) { + $message['context'] = $record->context; } - if ($record['extra']) { - $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->logLevels[$record['level']], + $this->logLevels[$record->level], ]; } diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 1b932a2b5..6518976e4 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -45,26 +45,26 @@ public function format(LogRecord $record): array { $tags = [ '#logs', - '#' . strtolower($record['level_name']), - '#' . $record['channel'], + '#' . strtolower($record->levelName), + '#' . $record->channel, ]; - foreach ($record['extra'] as $value) { + foreach ($record->extra as $value) { $tags[] = '#' . $value; } $subject = sprintf( 'in %s: %s - %s', $this->source, - $record['level_name'], - $this->getShortMessage($record['message']) + $record->levelName, + $this->getShortMessage($record->message) ); return [ 'source' => $this->source, 'from_address' => $this->sourceEmail, 'subject' => $subject, - 'content' => $record['message'], + 'content' => $record->message, 'tags' => $tags, 'project' => $this->source, ]; diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index 2b76e7513..31d4d5e2e 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -58,23 +58,23 @@ public function isUsingLevelsInTag(): bool public function format(LogRecord $record): string { - $tag = $record['channel']; + $tag = $record->channel; if ($this->levelTag) { - $tag .= '.' . strtolower($record['level_name']); + $tag .= '.' . strtolower($record->levelName); } $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']; - $message['level_name'] = $record['level_name']; + $message['level'] = $record->level; + $message['level_name'] = $record->levelName; } - return Utils::jsonEncode([$tag, $record['datetime']->getTimestamp(), $message]); + return Utils::jsonEncode([$tag, $record->datetime->getTimestamp(), $message]); } public function formatBatch(array $records): string diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index ac8eb9dbf..bf24b372c 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -87,31 +87,31 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n public function format(LogRecord $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); } $message = new Message(); $message - ->setTimestamp($record['datetime']) - ->setShortMessage((string) $record['message']) + ->setTimestamp($record->datetime) + ->setShortMessage((string) $record->message) ->setHost($this->systemName) - ->setLevel($this->logLevels[$record['level']]); + ->setLevel($this->logLevels[$record->level]); // message length + system name length + 200 for padding / metadata - $len = 200 + strlen((string) $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->setFacility($record['channel']); + if (isset($record->channel)) { + $message->setFacility($record->channel); } if (isset($extra['line'])) { $message->setLine($extra['line']); diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index fb2fb9f66..d534755e2 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -86,23 +86,23 @@ protected function addTitle(string $title, int $level): string */ public function format(LogRecord $record): string { - $output = $this->addTitle($record['level_name'], $record['level']); + $output = $this->addTitle($record->levelName, $record->level); $output .= '
'; - $output .= $this->addRow('Message', (string) $record['message']); - $output .= $this->addRow('Time', $this->formatDate($record['datetime'])); - $output .= $this->addRow('Channel', $record['channel']); - if ($record['context']) { + $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 = '
'; - foreach ($record['context'] as $key => $value) { + foreach ($record->context as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Context', $embeddedTable, false); } - if ($record['extra']) { + if ($record->extra) { $embeddedTable = ''; - foreach ($record['extra'] as $key => $value) { + foreach ($record->extra as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index a44aa89d6..aee6b5df2 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -20,8 +20,6 @@ * This can be useful to log to databases or remote APIs * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger */ class JsonFormatter extends NormalizerFormatter { @@ -29,13 +27,13 @@ class JsonFormatter extends NormalizerFormatter public const BATCH_MODE_NEWLINES = 2; /** @var self::BATCH_MODE_* */ - protected $batchMode; - /** @var bool */ - protected $appendNewline; - /** @var bool */ - protected $ignoreEmptyContextAndExtra; - /** @var bool */ - protected $includeStacktraces = false; + protected int $batchMode; + + protected bool $appendNewline; + + protected bool $ignoreEmptyContextAndExtra; + + protected bool $includeStacktraces = false; /** * @param self::BATCH_MODE_* $batchMode @@ -123,7 +121,7 @@ public function includeStacktraces(bool $include = true): self /** * Return a JSON-encoded array of records. * - * @phpstan-param Record[] $records + * @phpstan-param LogRecord[] $records */ protected function formatBatchJson(array $records): string { @@ -134,7 +132,7 @@ protected function formatBatchJson(array $records): string * Use new lines to separate records instead of a * JSON-encoded array. * - * @phpstan-param Record[] $records + * @phpstan-param LogRecord[] $records */ protected function formatBatchNewlines(array $records): string { diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index 4e9faddcb..b7b96cb4a 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -65,37 +65,37 @@ public function __construct(string $applicationName, ?string $systemName = null, */ public function format(LogRecord $record): string { - $record = parent::format($record); + $recordData = parent::format($record); - if (empty($record['datetime'])) { - $record['datetime'] = gmdate('c'); + if (empty($recordData['datetime'])) { + $recordData['datetime'] = gmdate('c'); } $message = [ - '@timestamp' => $record['datetime'], + '@timestamp' => $recordData['datetime'], '@version' => 1, 'host' => $this->systemName, ]; - if (isset($record['message'])) { - $message['message'] = $record['message']; + if (isset($recordData['message'])) { + $message['message'] = $recordData['message']; } - if (isset($record['channel'])) { - $message['type'] = $record['channel']; - $message['channel'] = $record['channel']; + if (isset($recordData['channel'])) { + $message['type'] = $recordData['channel']; + $message['channel'] = $recordData['channel']; } - if (isset($record['level_name'])) { - $message['level'] = $record['level_name']; + if (isset($recordData['level_name'])) { + $message['level'] = $recordData['level_name']; } - if (isset($record['level'])) { - $message['monolog_level'] = $record['level']; + if (isset($recordData['level'])) { + $message['monolog_level'] = $recordData['level']; } if ($this->applicationName) { $message['type'] = $this->applicationName; } - if (!empty($record['extra'])) { - $message[$this->extraKey] = $record['extra']; + if (!empty($recordData['extra'])) { + $message[$this->extraKey] = $recordData['extra']; } - if (!empty($record['context'])) { - $message[$this->contextKey] = $record['context']; + if (!empty($recordData['context'])) { + $message[$this->contextKey] = $recordData['context']; } return $this->toJson($message) . "\n"; diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index aa34e520b..f72072413 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -31,7 +31,7 @@ class MongoDBFormatter implements FormatterInterface 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) diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index f686781f9..7170b020b 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -61,38 +61,38 @@ public function format(LogRecord $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']); } /** @var mixed[] $record */ $record = $this->normalize($record); - $message = ['message' => $record['message']]; + $message = ['message' => $record->message]; $handleError = false; - if ($record['context']) { - $message['context'] = $record['context']; + if ($record->context) { + $message['context'] = $record->context; $handleError = true; } - if ($record['extra']) { - $message['extra'] = $record['extra']; + if ($record->extra) { + $message['extra'] = $record->extra; $handleError = true; } if (count($message) === 1) { $message = reset($message); } - if (isset($record['context']['table'])) { + if (isset($record->context['table'])) { $type = 'TABLE'; - $label = $record['channel'] .': '. $record['message']; - $message = $record['context']['table']; + $label = $record->channel .': '. $record->message; + $message = $record->context['table']; } else { - $type = $this->logLevels[$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 diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 07c0d3e94..51f3db539 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -51,7 +51,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) */ public function isHandling(LogRecord $record): bool { - return $record['level'] >= $this->level; + return $record->level >= $this->level; } /** diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index bed34c12e..253200533 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -23,8 +23,6 @@ * * @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 { @@ -44,7 +42,7 @@ public function handle(LogRecord $record): bool $record = $this->processRecord($record); } - $record['formatted'] = $this->getFormatter()->format($record); + $record->formatted = $this->getFormatter()->format($record); $this->write($record); @@ -52,9 +50,7 @@ public function handle(LogRecord $record): bool } /** - * Writes the record down to the log of the implementing handler - * - * @phpstan-param FormattedRecord $record + * Writes the (already formatted) record down to the log of the implementing handler */ abstract protected function write(LogRecord $record): void; diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index da84f809b..09c5b3d8a 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -19,9 +19,6 @@ use AMQPExchange; use Monolog\LogRecord; -/** - * @phpstan-import-type Record from \Monolog\Logger - */ class AmqpHandler extends AbstractProcessingHandler { /** @@ -57,7 +54,7 @@ public function __construct($exchange, ?string $exchangeName = null, $level = Lo */ protected function write(LogRecord $record): void { - $data = $record["formatted"]; + $data = $record->formatted; $routingKey = $this->getRoutingKey($record); if ($this->exchange instanceof AMQPExchange) { @@ -95,7 +92,6 @@ public function handleBatch(array $records): void continue; } - /** @var Record $record */ $record = $this->processRecord($record); $data = $this->getFormatter()->format($record); @@ -111,12 +107,10 @@ public function handleBatch(array $records): void /** * Gets the routing key for the AMQP exchange - * - * @phpstan-param Record $record */ protected function getRoutingKey(LogRecord $record): string { - $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']); + $routingKey = sprintf('%s.%s', $record->levelName, $record->channel); return strtolower($routingKey); } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 471778aa5..fa66da4b0 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -27,15 +27,13 @@ * Handler sending logs to browser's javascript console with no browser extension required * * @author Olivier Poitrey - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class BrowserConsoleHandler extends AbstractProcessingHandler { - /** @var bool */ - protected static $initialized = false; - /** @var FormattedRecord[] */ - protected static $records = []; + protected static bool $initialized = false; + + /** @var LogRecord[] */ + protected static array $records = []; protected const FORMAT_HTML = 'html'; protected const FORMAT_JS = 'js'; @@ -174,18 +172,18 @@ private static function generateScript(): string { $script = []; foreach (static::$records as $record) { - $context = static::dump('Context', $record['context']); - $extra = static::dump('Extra', $record['extra']); + $context = self::dump('Context', $record->context); + $extra = self::dump('Extra', $record->extra); if (empty($context) && empty($extra)) { - $script[] = static::call_array('log', static::handleStyles($record['formatted'])); + $script[] = self::call_array('log', self::handleStyles($record->formatted)); } else { $script = array_merge( $script, - [static::call_array('groupCollapsed', static::handleStyles($record['formatted']))], + [self::call_array('groupCollapsed', self::handleStyles($record->formatted))], $context, $extra, - [static::call('groupEnd')] + [self::call('groupEnd')] ); } } @@ -204,14 +202,14 @@ private static function handleStyles(string $formatted): array foreach (array_reverse($matches) as $match) { $args[] = '"font-weight: normal"'; - $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); + $args[] = self::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[] = static::quote('font-weight: normal'); - $args[] = static::quote($format); + $args[] = self::quote('font-weight: normal'); + $args[] = self::quote($format); return array_reverse($args); } @@ -254,13 +252,13 @@ private static function dump(string $title, array $dict): array if (empty($dict)) { return $script; } - $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title)); + $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); foreach ($dict as $key => $value) { $value = json_encode($value); if (empty($value)) { - $value = static::quote(''); + $value = self::quote(''); } - $script[] = static::call('log', static::quote('%s: %o'), static::quote((string) $key), $value); + $script[] = self::call('log', self::quote('%s: %o'), self::quote((string) $key), $value); } return $script; @@ -281,7 +279,7 @@ private static function call(...$args): string throw new \UnexpectedValueException('Expected the first arg to be a string, got: '.var_export($method, true)); } - return static::call_array($method, $args); + return self::call_array($method, $args); } /** diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 6035415f6..8edf6965f 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -23,25 +23,23 @@ * sending one per log message. * * @author Christophe Coevoet - * - * @phpstan-import-type Record from \Monolog\Logger */ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; - /** @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; + protected HandlerInterface $handler; + + protected int $bufferSize = 0; + + protected int $bufferLimit; + + protected bool $flushOnOverflow; + + /** @var LogRecord[] */ + protected array $buffer = []; + + protected bool $initialized = false; /** * @param HandlerInterface $handler Handler. @@ -61,7 +59,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $le */ public function handle(LogRecord $record): bool { - if ($record['level'] < $this->level) { + if ($record->level < $this->level) { return false; } @@ -81,7 +79,6 @@ public function handle(LogRecord $record): bool } if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index f8e9f237d..345ba90cf 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -24,8 +24,6 @@ * This also works out of the box with Firefox 43+ * * @author Christophe Coevoet - * - * @phpstan-import-type Record from \Monolog\Logger */ class ChromePHPHandler extends AbstractProcessingHandler { @@ -88,10 +86,10 @@ public function handleBatch(array $records): void $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; } @@ -123,7 +121,7 @@ protected function write(LogRecord $record): void return; } - self::$json['rows'][] = $record['formatted']; + self::$json['rows'][] = $record->formatted; $this->send(); } diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index 96bd16997..abdce0b51 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -56,7 +56,7 @@ protected function write(LogRecord $record): void $context = stream_context_create([ 'http' => [ 'method' => 'POST', - 'content' => $record['formatted'], + 'content' => $record->formatted, 'ignore_errors' => true, 'max_redirects' => 0, 'header' => 'Content-type: application/json', diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 5ea634d5e..b86d50af2 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -115,20 +115,20 @@ protected function connectHttp(): void */ protected function write(LogRecord $record): void { - $date = $record['datetime']; + $date = $record->datetime; $data = ['time' => $date->format('Y-m-d\TH:i:s.uO')]; - unset($record['datetime']); + unset($record->datetime); - if (isset($record['context']['type'])) { - $data['type'] = $record['context']['type']; - unset($record['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'] = $record['context']; - $data['data']['level'] = $record['level']; + $data['data'] = $record->context; + $data['data']['level'] = $record->level; if ($this->scheme === 'http') { $this->writeHttp(Utils::jsonEncode($data)); diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 7213e8ee2..73a7660bd 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -34,7 +34,7 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param resource|CurlHandle $ch curl handler + * @param CurlHandle $ch curl handler * @param int $retries * @param bool $closeAfterDone * @return bool|string @see curl_exec diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 776e293b1..f9d80f2d2 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -34,8 +34,6 @@ * same way. * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ @@ -88,7 +86,7 @@ public function flush(): void $passthru = null; foreach ($this->buffer as $record) { - if ($record['level'] >= $this->deduplicationLevel) { + if ($record->level >= $this->deduplicationLevel) { $passthru = $passthru || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); @@ -108,9 +106,6 @@ public function flush(): void } } - /** - * @phpstan-param Record $record - */ private function isDuplicate(LogRecord $record): bool { if (!file_exists($this->deduplicationStore)) { @@ -123,13 +118,13 @@ private function isDuplicate(LogRecord $record): bool } $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_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) { + if ($level === $record->levelName && $message === $expectedMessage && $timestamp > $timestampValidity) { return true; } @@ -177,11 +172,8 @@ private function collectLogs(): void $this->gc = false; } - /** - * @phpstan-param Record $record - */ private function appendRecord(LogRecord $record): void { - file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); + file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->levelName . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); } } diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index f2c34c877..9b3426f81 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -38,7 +38,7 @@ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool */ protected function write(LogRecord $record): void { - $this->client->postDocument($record['formatted']); + $this->client->postDocument($record->formatted); } protected function getDefaultFormatter(): FormatterInterface diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index f3b8571f6..b154d1432 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -70,7 +70,7 @@ public function __construct(DynamoDbClient $client, string $table, $level = Logg */ protected function write(LogRecord $record): void { - $filtered = $this->filterEmptyFields($record['formatted']); + $filtered = $this->filterEmptyFields($record->formatted); if ($this->version === 3) { $formatted = $this->marshaler->marshalItem($filtered); } else { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 8caf2c0a0..838d9d2bb 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -70,7 +70,7 @@ public function __construct(Client $client, array $options = [], $level = Logger */ protected function write(LogRecord $record): void { - $this->bulkSend([$record['formatted']]); + $this->bulkSend([$record->formatted]); } /** diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index a62fc279e..0694bcb08 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -77,7 +77,7 @@ public function __construct(Client $client, array $options = [], $level = Logger */ protected function write(LogRecord $record): void { - $this->bulkSend([$record['formatted']]); + $this->bulkSend([$record->formatted]); } /** @@ -122,7 +122,7 @@ public function handleBatch(array $records): void /** * Use Elasticsearch bulk API to send list of documents * - * @param array[] $records Records + _index/_type keys + * @param array> $records Records + _index/_type keys * @throws \RuntimeException */ protected function bulkSend(array $records): void diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 2815f5e3e..c0f622980 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -75,12 +75,12 @@ protected function getDefaultFormatter(): FormatterInterface protected function write(LogRecord $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)); diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index 1e5b623b3..ac6e90424 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -20,8 +20,6 @@ * 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 { @@ -31,7 +29,6 @@ class FallbackGroupHandler extends GroupHandler public function handle(LogRecord $record): bool { if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -56,7 +53,6 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } - /** @var Record[] $records */ $records = $processed; } diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index c430b3559..d6703fe16 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -24,8 +24,6 @@ * * @author Hennadiy Verkh * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ @@ -37,7 +35,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * Handler or factory callable($record, $this) * * @var callable|HandlerInterface - * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface + * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ protected $handler; @@ -57,7 +55,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese protected $bubble; /** - * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler + * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @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 @@ -114,7 +112,7 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L */ public function isHandling(LogRecord $record): bool { - return isset($this->acceptedLevels[$record['level']]); + return isset($this->acceptedLevels[$record->level]); } /** @@ -127,7 +125,6 @@ public function handle(LogRecord $record): bool } if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -159,8 +156,6 @@ public function handleBatch(array $records): void * 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) { diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index f10772793..e8a1b0b0d 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -17,15 +17,11 @@ * Interface for activation strategies for the FingersCrossedHandler. * * @author Johannes M. Schmitt - * - * @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; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index fd2b22c65..ca34b3b78 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -34,8 +34,6 @@ * * * @author Mike Meessen - * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ @@ -64,15 +62,12 @@ public function __construct($defaultActionLevel, array $channelToActionLevel = [ $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } - /** - * @phpstan-param Record $record - */ public function isHandlerActivated(LogRecord $record): bool { - if (isset($this->channelToActionLevel[$record['channel']])) { - return $record['level'] >= $this->channelToActionLevel[$record['channel']]; + if (isset($this->channelToActionLevel[$record->channel])) { + return $record->level >= $this->channelToActionLevel[$record->channel]; } - return $record['level'] >= $this->defaultActionLevel; + return $record->level >= $this->defaultActionLevel; } } diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 0131e44fe..ba98f5052 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -42,6 +42,6 @@ public function __construct($actionLevel) public function isHandlerActivated(LogRecord $record): bool { - return $record['level'] >= $this->actionLevel; + return $record->level >= $this->actionLevel; } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 4bcb23c74..872b9a18e 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -34,8 +34,6 @@ * Monolog\Handler\FingersCrossed\ namespace. * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger */ @@ -45,7 +43,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa /** * @var callable|HandlerInterface - * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface + * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ protected $handler; /** @var ActivationStrategyInterface */ @@ -54,7 +52,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $buffering = true; /** @var int */ protected $bufferSize; - /** @var Record[] */ + /** @var LogRecord[] */ protected $buffer = []; /** @var bool */ protected $stopBuffering; @@ -67,7 +65,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $bubble; /** - * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler + * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @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 @@ -132,7 +130,6 @@ public function activate(): void public function handle(LogRecord $record): bool { if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -191,7 +188,7 @@ private function flushBuffer(): void 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); @@ -208,8 +205,6 @@ private function flushBuffer(): void * 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) { diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 007c80f71..744963f15 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -19,8 +19,6 @@ * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. * * @author Eric Clemmons (@ericclemmons) - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FirePHPHandler extends AbstractProcessingHandler { @@ -86,8 +84,6 @@ protected function createHeader(array $meta, string $message): array * @phpstan-return non-empty-array * * @see createHeader() - * - * @phpstan-param FormattedRecord $record */ protected function createRecordHeader(LogRecord $record): array { @@ -95,7 +91,7 @@ protected function createRecordHeader(LogRecord $record): array // 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 ); } diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 5768797c2..82614cb8b 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -23,8 +23,6 @@ * * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation * @author Ando Roots - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FleepHookHandler extends SocketHandler { @@ -122,13 +120,11 @@ private function buildHeader(string $content): string /** * Builds the body of API call - * - * @phpstan-param FormattedRecord $record */ private function buildContent(LogRecord $record): string { $dataArray = [ - 'message' => $record['formatted'], + 'message' => $record->formatted, ]; return http_build_query($dataArray); diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index 514ebbd0f..f15857ed6 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -27,8 +27,6 @@ * * @author Dominik Liebler * @see https://www.flowdock.com/api/push - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FlowdockHandler extends SocketHandler { @@ -109,12 +107,10 @@ protected function generateDataStream(LogRecord $record): string /** * Builds the body of API call - * - * @phpstan-param FormattedRecord $record */ private function buildContent(LogRecord $record): string { - return Utils::jsonEncode($record['formatted']); + return Utils::jsonEncode($record->formatted); } /** diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 2198486af..b29049c41 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -45,7 +45,7 @@ public function __construct(PublisherInterface $publisher, $level = Logger::DEBU */ protected function write(LogRecord $record): void { - $this->publisher->publish($record['formatted']); + $this->publisher->publish($record->formatted); } /** diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index fed86c5b4..d32632759 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -19,8 +19,6 @@ * Forwards records to multiple handlers * * @author Lenar Lõhmus - * - * @phpstan-import-type Record from \Monolog\Logger */ class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { @@ -67,7 +65,6 @@ public function isHandling(LogRecord $record): bool public function handle(LogRecord $record): bool { if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -88,7 +85,6 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } - /** @var Record[] $records */ $records = $processed; } diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index e5b477bcb..4eaa1c951 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -55,9 +55,9 @@ public function __construct(string $eventName, string $secretKey, $level = Logge public function write(LogRecord $record): void { $postData = [ - "value1" => $record["channel"], + "value1" => $record->channel, "value2" => $record["level_name"], - "value3" => $record["message"], + "value3" => $record->message, ]; $postString = Utils::jsonEncode($postData); diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index 8d796e6e8..0223d5bb4 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -72,6 +72,6 @@ public function __construct( */ protected function generateDataStream(LogRecord $record): string { - return $this->logToken . ' ' . $record['formatted']; + return $this->logToken . ' ' . $record->formatted; } } diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 02d9c7d4d..8fe5d869a 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -66,6 +66,6 @@ public function __construct( */ protected function generateDataStream(LogRecord $record): string { - return $this->logToken . ' ' . $record['formatted']; + return $this->logToken . ' ' . $record->formatted; } } diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index a1a8e3b7c..ef74ee16c 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -34,7 +34,7 @@ class LogglyHandler extends AbstractProcessingHandler /** * Caches the curl handlers for every given endpoint. * - * @var resource[]|CurlHandle[] + * @var CurlHandle[] */ protected $curlHandlers = []; @@ -65,7 +65,7 @@ public function __construct(string $token, $level = Logger::DEBUG, bool $bubble * * @param string $endpoint * - * @return resource|CurlHandle + * @return CurlHandle */ protected function getCurlHandler(string $endpoint) { @@ -81,7 +81,7 @@ protected function getCurlHandler(string $endpoint) * * @param string $endpoint * - * @return resource|CurlHandle + * @return CurlHandle */ private function loadCurlHandle(string $endpoint) { @@ -122,7 +122,7 @@ public function addTag($tag): self protected function write(LogRecord $record): void { - $this->send($record["formatted"], static::ENDPOINT_SINGLE); + $this->send($record->formatted, static::ENDPOINT_SINGLE); } public function handleBatch(array $records): void @@ -130,7 +130,7 @@ public function handleBatch(array $records): void $level = $this->level; $records = array_filter($records, function ($record) use ($level) { - return ($record['level'] >= $level); + return ($record->level >= $level); }); if ($records) { diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 293194414..b2799c2d4 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -85,7 +85,7 @@ public function __construct( */ protected function generateDataStream(LogRecord $record): string { - return $this->logToken . ' ' . $record['formatted']; + return $this->logToken . ' ' . $record->formatted; } /** diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 6061793bf..bfbe98fef 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -19,8 +19,6 @@ * Base class for all mail handlers * * @author Gyula Sallai - * - * @phpstan-import-type Record from \Monolog\Logger */ abstract class MailHandler extends AbstractProcessingHandler { @@ -32,10 +30,10 @@ public function handleBatch(array $records): void $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; } @@ -60,7 +58,7 @@ abstract protected function send(string $content, array $records): void; */ protected function write(LogRecord $record): void { - $this->send((string) $record['formatted'], [$record]); + $this->send((string) $record->formatted, [$record]); } /** @@ -70,7 +68,7 @@ protected function getHighestRecord(array $records): LogRecord { $highestRecord = null; foreach ($records as $record) { - if ($highestRecord === null || $highestRecord['level'] < $record['level']) { + if ($highestRecord === null || $highestRecord['level'] < $record->level) { $highestRecord = $record; } } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 3003500ec..9fe105474 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -28,7 +28,7 @@ class MandrillHandler extends MailHandler protected $apiKey; /** - * @psalm-param Swift_Message|callable(): Swift_Message $message + * @phpstan-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 diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index c50375158..50aaa1e68 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -34,12 +34,11 @@ */ class MongoDBHandler extends AbstractProcessingHandler { - /** @var \MongoDB\Collection */ - private $collection; - /** @var Client|Manager */ - private $manager; - /** @var string */ - private $namespace; + private \MongoDB\Collection $collection; + + private Client|Manager $manager; + + private string|null $namespace = null; /** * Constructor. @@ -67,12 +66,12 @@ public function __construct($mongodb, string $database, string $collection, $lev protected function write(LogRecord $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); } } diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 89c37e67c..113aaa49e 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -21,7 +21,7 @@ * 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 @@ -80,24 +80,24 @@ protected function write(LogRecord $record): void throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); } - if ($appName = $this->getAppName($record['context'])) { + if ($appName = $this->getAppName($record->context)) { $this->setNewRelicAppName($appName); } - if ($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); @@ -108,8 +108,8 @@ protected function write(LogRecord $record): void } } - 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); diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 54a40feea..99c1e6596 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -48,7 +48,7 @@ public function __construct($level = Logger::DEBUG) */ public function isHandling(LogRecord $record): bool { - return $record['level'] >= $this->level; + return $record->level >= $this->level; } /** @@ -56,6 +56,6 @@ public function isHandling(LogRecord $record): bool */ public function handle(LogRecord $record): bool { - return $record['level'] >= $this->level; + return $record->level >= $this->level; } } diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 4673ecc77..af33424fe 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -90,11 +90,11 @@ public function __construct( */ public function handle(LogRecord $record): bool { - if ($record['level'] < $this->level) { + if ($record->level < $this->level) { return false; } - $level = $record['level']; + $level = $record->level; if (!isset($this->thresholdMap[$level])) { $this->thresholdMap[$level] = 0; diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index e06128a58..d4aeb9e96 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -38,8 +38,6 @@ * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin - * - * @phpstan-import-type Record from \Monolog\Logger */ class PHPConsoleHandler extends AbstractProcessingHandler { @@ -182,46 +180,37 @@ public function handle(LogRecord $record): bool */ protected function write(LogRecord $record): void { - if ($record['level'] < Logger::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); } } - /** - * @phpstan-param Record $record - */ private function handleDebugRecord(LogRecord $record): void { [$tags, $filteredContext] = $this->getRecordTags($record); - $message = $record['message']; + $message = $record->message; if ($filteredContext) { $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($filteredContext)), null, true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } - /** - * @phpstan-param Record $record - */ private function handleExceptionRecord(LogRecord $record): void { - $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); + $this->connector->getErrorsDispatcher()->dispatchException($record->context['exception']); } - /** - * @phpstan-param Record $record - */ private function handleErrorRecord(LogRecord $record): void { $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'] diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 7fcbdc788..d2c3cea90 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -88,7 +88,7 @@ protected function write(LogRecord $record): void { $this->ensureProcessIsStarted(); - $this->writeProcessInput($record['formatted']); + $this->writeProcessInput($record->formatted); $errors = $this->readProcessErrors(); if (empty($errors) === false) { diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 3adec7a4d..9fb290faa 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -12,20 +12,19 @@ namespace Monolog\Handler; use Monolog\Processor\ProcessorInterface; +use Monolog\LogRecord; /** * Interface to describe loggers that have processors * * @author Jordi Boggiano - * - * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessableHandlerInterface { /** * Adds a processor in the stack. * - * @psalm-param ProcessorInterface|callable(Record): Record $callback + * @phpstan-param ProcessorInterface|(callable(LogRecord): LogRecord) $callback * * @param ProcessorInterface|callable $callback * @return HandlerInterface self @@ -35,7 +34,7 @@ public function pushProcessor(callable $callback): HandlerInterface; /** * Removes the processor on top of the stack and returns it. * - * @psalm-return ProcessorInterface|callable(Record): Record $callback + * @phpstan-return ProcessorInterface|(callable(LogRecord): LogRecord) $callback * * @throws \LogicException In case the processor stack is empty * @return callable|ProcessorInterface diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index e8e6b68ca..217b21365 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -24,7 +24,7 @@ trait ProcessableHandlerTrait { /** * @var callable[] - * @phpstan-var array> + * @phpstan-var array<(callable(LogRecord): LogRecord)|ProcessorInterface> */ protected $processors = []; diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 0fad51f22..50fee1725 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -60,9 +60,9 @@ public function handle(LogRecord $record): bool if ($this->formatter) { $formatted = $this->formatter->format($record); - $this->logger->log(strtolower($record['level_name']), (string) $formatted, $record['context']); + $this->logger->log(strtolower($record->levelName), (string) $formatted, $record->context); } else { - $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']); + $this->logger->log(strtolower($record->levelName), $record->message, $record->context); } return false === $this->bubble; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 388e28ab3..57bdff8df 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -22,7 +22,6 @@ * @author Sebastian Göttschkes * @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 */ @@ -144,18 +143,15 @@ protected function generateDataStream(LogRecord $record): string return $this->buildHeader($content) . $content; } - /** - * @phpstan-param FormattedRecord $record - */ private function buildContent(LogRecord $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, @@ -165,17 +161,17 @@ private function buildContent(LogRecord $record): string 'timestamp' => $timestamp, ]; - if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) { + if (isset($record->level) && $record->level >= $this->emergencyLevel) { $dataArray['priority'] = 2; $dataArray['retry'] = $this->retry; $dataArray['expire'] = $this->expire; - } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) { + } 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); diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 4c86a1320..6b652ce57 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -26,12 +26,10 @@ * $log->pushHandler($redis); * * @author Thomas Tourlourat - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class RedisHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $redisKey; @@ -39,7 +37,7 @@ class RedisHandler extends AbstractProcessingHandler protected $capSize; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The key name to push records to * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ @@ -64,29 +62,27 @@ protected function write(LogRecord $record): void 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 { 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); }); } diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 4864de03a..0d58ed288 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -29,13 +29,13 @@ */ class RedisPubSubHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $channelKey; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) @@ -55,7 +55,7 @@ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $b */ protected function write(LogRecord $record): void { - $this->redisClient->publish($this->channelKey, $record["formatted"]); + $this->redisClient->publish($this->channelKey, $record->formatted); } /** diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 05fa74e0b..76b320543 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -82,12 +82,12 @@ protected function write(LogRecord $record): void $this->initialized = true; } - $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'), + $context = $record->context; + $context = array_merge($context, $record->extra, [ + 'level' => $this->levelMap[$record->level], + 'monolog_level' => $record->levelName, + 'channel' => $record->channel, + 'datetime' => $record->datetime->format('U'), ]); if (isset($context['exception']) && $context['exception'] instanceof Throwable) { @@ -95,7 +95,7 @@ protected function write(LogRecord $record): void unset($context['exception']); $toLog = $exception; } else { - $toLog = $record['message']; + $toLog = $record->message; } // @phpstan-ignore-next-line diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index dada67e14..39abfc95e 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -118,7 +118,7 @@ protected function write(LogRecord $record): void $this->mustRotate = null === $this->url || !file_exists($this->url); } - if ($this->nextRotation <= $record['datetime']) { + if ($this->nextRotation <= $record->datetime) { $this->mustRotate = true; $this->close(); } diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 1b8a2f083..39f1e0d7c 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -27,8 +27,6 @@ * * @author Bryan Davis * @author Kunal Mehta - * - * @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger */ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface @@ -37,7 +35,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter /** * @var HandlerInterface|callable - * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface + * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ protected $handler; @@ -47,7 +45,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter protected $factor; /** - * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler + * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @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) @@ -72,7 +70,6 @@ public function handle(LogRecord $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -87,8 +84,6 @@ public function handle(LogRecord $record): bool * * 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) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index d20cc6918..fba862258 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -24,9 +24,6 @@ * @author Haralan Dobrev * @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 { @@ -122,7 +119,6 @@ public function __construct( * Returns required data in format that Slack * is expecting. * - * @phpstan-param FormattedRecord $record * @phpstan-return mixed[] */ public function getSlackData(LogRecord $record): array @@ -138,49 +134,48 @@ public function getSlackData(LogRecord $record): array } if ($this->formatter && !$this->useAttachment) { - /** @phpstan-ignore-next-line */ $message = $this->formatter->format($record); } else { $message = $record->message; } - $record = $this->removeExcludedFields($record); + $recordData = $this->removeExcludedFields($record); if ($this->useAttachment) { $attachment = array( - 'fallback' => $message, - 'text' => $message, - 'color' => $this->getAttachmentColor($record['level']), - 'fields' => array(), - 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp(), + 'fallback' => $message, + 'text' => $message, + 'color' => $this->getAttachmentColor($recordData['level']), + 'fields' => array(), + 'mrkdwn_in' => array('fields'), + 'ts' => $recordData['datetime']->getTimestamp(), 'footer' => $this->username, 'footer_icon' => $this->userIcon, ); if ($this->useShortAttachment) { - $attachment['title'] = $record['level_name']; + $attachment['title'] = $recordData['level_name']; } else { $attachment['title'] = 'Message'; - $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']); + $attachment['fields'][] = $this->generateAttachmentField('Level', $recordData['level_name']); } if ($this->includeContextAndExtra) { foreach (array('extra', 'context') as $key) { - if (empty($record[$key])) { + if (empty($recordData[$key])) { continue; } if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( (string) $key, - $record[$key] + $recordData[$key] ); } else { // Add all extra fields as individual fields in attachment $attachment['fields'] = array_merge( $attachment['fields'], - $this->generateAttachmentFields($record[$key]) + $this->generateAttachmentFields($recordData[$key]) ); } } @@ -360,16 +355,14 @@ private function generateAttachmentFields(array $data): array /** * Get a copy of record with fields excluded according to $this->excludeFields * - * @phpstan-param FormattedRecord $record - * * @return mixed[] */ private function removeExcludedFields(LogRecord $record): array { - $record = $record->toArray(); + $recordData = $record->toArray(); foreach ($this->excludeFields as $field) { $keys = explode('.', $field); - $node = &$record; + $node = &$recordData; $lastKey = end($keys); foreach ($keys as $key) { if (!isset($node[$key])) { @@ -383,6 +376,6 @@ private function removeExcludedFields(LogRecord $record): array } } - return $record; + return $recordData; } } diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 1e6e5517f..4f57daee1 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -22,8 +22,6 @@ * * @author Greg Kedzierski * @see https://api.slack.com/ - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SlackHandler extends SocketHandler { @@ -117,8 +115,6 @@ protected function generateDataStream(LogRecord $record): string /** * Builds the body of API call - * - * @phpstan-param FormattedRecord $record */ private function buildContent(LogRecord $record): string { @@ -128,7 +124,6 @@ private function buildContent(LogRecord $record): string } /** - * @phpstan-param FormattedRecord $record * @return string[] */ protected function prepareContentData(LogRecord $record): array diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 44fdffa94..1d8a68f2d 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -19,9 +19,6 @@ * * @author Pablo de Leon Belloc * @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 { @@ -343,12 +340,9 @@ private function connectIfNotConnected(): void $this->connect(); } - /** - * @phpstan-param FormattedRecord $record - */ protected function generateDataStream(LogRecord $record): string { - return (string) $record['formatted']; + return (string) $record->formatted; } /** diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index bbc2ae84a..727c20a8c 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -46,11 +46,11 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Log */ protected function write(LogRecord $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); } diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index b48250f0b..0053db156 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -21,8 +21,6 @@ * Can be used to store into php://stderr, remote and local files, etc. * * @author Jordi Boggiano - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class StreamHandler extends AbstractProcessingHandler { @@ -170,13 +168,10 @@ protected function write(LogRecord $record): void /** * Write to stream * @param resource $stream - * @param array $record - * - * @phpstan-param FormattedRecord $record */ protected function streamWrite($stream, LogRecord $record): void { - fwrite($stream, (string) $record['formatted']); + fwrite($stream, (string) $record->formatted); } private function customErrorHandler(int $code, string $msg): bool diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 9652e4d4d..77ceaa1d0 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -64,6 +64,6 @@ protected function write(LogRecord $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->logLevels[$record['level']], (string) $record['formatted']); + syslog($this->logLevels[$record->level], (string) $record->formatted); } } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index c4360cbf6..07feaa567 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -70,9 +70,9 @@ public function __construct(string $host, int $port = 514, $facility = LOG_USER, protected function write(LogRecord $record): void { - $lines = $this->splitMessageIntoLines($record['formatted']); + $lines = $this->splitMessageIntoLines($record->formatted); - $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']], $record['datetime']); + $header = $this->makeCommonSyslogHeader($this->logLevels[$record->level], $record->datetime); foreach ($lines as $line) { $this->socket->write($line, $header); diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index d44148d02..e2812c997 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -29,8 +29,6 @@ * @link https://core.telegram.org/bots/api * * @author Mazur Alexandr - * - * @phpstan-import-type Record from \Monolog\Logger */ class TelegramBotHandler extends AbstractProcessingHandler { @@ -186,7 +184,6 @@ public function delayBetweenMessages(bool $delayBetweenMessages = false): self */ public function handleBatch(array $records): void { - /** @var Record[] $messages */ $messages = []; foreach ($records as $record) { @@ -195,7 +192,6 @@ public function handleBatch(array $records): void } if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } @@ -212,7 +208,7 @@ public function handleBatch(array $records): void */ protected function write(LogRecord $record): void { - $this->send($record['formatted']); + $this->send($record->formatted); } /** diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 5f5d51ea1..2395889e1 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -126,23 +126,23 @@ public function hasRecords($level): bool } /** - * @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|array $recordAssertions 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 $record + * @phpstan-param array{message: string, context?: mixed[]}|string $recordAssertions * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function hasRecord(string|array $record, $level): bool + public function hasRecord(string|array $recordAssertions, $level): bool { - if (is_string($record)) { - $record = ['message' => $record]; + if (is_string($recordAssertions)) { + $recordAssertions = ['message' => $recordAssertions]; } - return $this->hasRecordThatPasses(function (LogRecord $rec) use ($record) { - if ($rec->message !== $record['message']) { + return $this->hasRecordThatPasses(function (LogRecord $rec) use ($recordAssertions) { + if ($rec->message !== $recordAssertions['message']) { return false; } - if (isset($record['context']) && $rec->context !== $record['context']) { + if (isset($recordAssertions['context']) && $rec->context !== $recordAssertions['context']) { return false; } @@ -157,9 +157,7 @@ public function hasRecord(string|array $record, $level): bool */ public function hasRecordThatContains(string $message, $level): bool { - return $this->hasRecordThatPasses(function ($rec) use ($message) { - return strpos($rec['message'], $message) !== false; - }, $level); + return $this->hasRecordThatPasses(fn (LogRecord $rec) => str_contains($rec->message, $message), $level); } /** @@ -169,16 +167,14 @@ public function hasRecordThatContains(string $message, $level): bool */ public function hasRecordThatMatches(string $regex, $level): bool { - return $this->hasRecordThatPasses(function (LogRecord $rec) use ($regex): bool { - return preg_match($regex, $rec->message) > 0; - }, $level); + return $this->hasRecordThatPasses(fn (LogRecord $rec) => preg_match($regex, $rec->message) > 0, $level); } /** * @param string|int $level Logging level value or name * @return bool * - * @psalm-param callable(LogRecord, int): mixed $predicate + * @phpstan-param callable(LogRecord, int): mixed $predicate * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatPasses(callable $predicate, $level) diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 0f83fcb8a..b26f21f6b 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -12,14 +12,13 @@ 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 - * - * @phpstan-import-type Record from \Monolog\Logger */ class WhatFailureGroupHandler extends GroupHandler { @@ -29,14 +28,13 @@ class WhatFailureGroupHandler extends GroupHandler public function handle(LogRecord $record): bool { if ($this->processors) { - /** @var Record $record */ $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { try { $handler->handle($record); - } catch (\Throwable $e) { + } catch (Throwable) { // What failure? } } @@ -54,14 +52,13 @@ public function handleBatch(array $records): void foreach ($records as $record) { $processed[] = $this->processRecord($record); } - /** @var Record[] $records */ $records = $processed; } foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); - } catch (\Throwable $e) { + } catch (Throwable) { // What failure? } } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 8f974d5a2..b881f4920 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -21,8 +21,6 @@ * * @author Christian Bergau * @author Jason Davis - * - * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class ZendMonitorHandler extends AbstractProcessingHandler { @@ -63,10 +61,10 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) protected function write(LogRecord $record): void { $this->writeZendMonitorCustomEvent( - Logger::getLevelName($record['level']), - $record['message'], - $record['formatted'], - $this->levelMap[$record['level']] + Logger::getLevelName($record->level), + $record->message, + $record->formatted, + $this->levelMap[$record->level] ); } @@ -74,10 +72,8 @@ protected function write(LogRecord $record): void * 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 $formatted Displayed in Custom Variables tab + * @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 { diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index cb80ee2fe..920cbc3f4 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -47,11 +47,11 @@ public function __construct($level = Logger::DEBUG) public function __invoke(LogRecord $record): LogRecord { // 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; } diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index d8fa3b9ff..b999b2842 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -31,7 +31,7 @@ public function __construct() */ public function __invoke(LogRecord $record): LogRecord { - $record['extra']['hostname'] = self::$host; + $record->extra['hostname'] = self::$host; return $record; } diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 6414a90c8..2cbc83b47 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -31,14 +31,14 @@ */ class IntrospectionProcessor implements ProcessorInterface { - /** @var int */ - private $level; - /** @var string[] */ - private $skipClassesPartials; - /** @var int */ - private $skipStackFramesCount; + private int $level; + /** @var string[] */ - private $skipFunctions = [ + private array $skipClassesPartials; + + private int $skipStackFramesCount; + + private const SKIP_FUNCTIONS = [ 'call_user_func', 'call_user_func_array', ]; @@ -62,7 +62,7 @@ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record['level'] < $this->level) { + if ($record->level < $this->level) { return $record; } @@ -84,7 +84,7 @@ public function __invoke(LogRecord $record): LogRecord continue 2; } } - } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) { + } elseif (in_array($trace[$i]['function'], self::SKIP_FUNCTIONS)) { $i++; continue; @@ -96,8 +96,8 @@ public function __invoke(LogRecord $record): LogRecord $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, @@ -111,7 +111,7 @@ public function __invoke(LogRecord $record): LogRecord } /** - * @param array[] $trace + * @param array $trace */ private function isTraceClassOrSkippedFunction(array $trace, int $index): bool { @@ -119,6 +119,6 @@ private function isTraceClassOrSkippedFunction(array $trace, int $index): bool return false; } - return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions); + return isset($trace[$index]['class']) || in_array($trace[$index]['function'], self::SKIP_FUNCTIONS); } } diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index e4b0d6d95..3e98c4808 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -32,7 +32,7 @@ public function __invoke(LogRecord $record): LogRecord $usage = $this->formatBytes($usage); } - $record['extra']['memory_peak_usage'] = $usage; + $record->extra['memory_peak_usage'] = $usage; return $record; } diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index 281432edc..fa48d2466 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -32,7 +32,7 @@ public function __invoke(LogRecord $record): LogRecord $usage = $this->formatBytes($usage); } - $record['extra']['memory_usage'] = $usage; + $record->extra['memory_usage'] = $usage; return $record; } diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 152e1f054..7fb1340dd 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -46,11 +46,11 @@ public function __construct($level = Logger::DEBUG) public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record['level'] < $this->level) { + if ($record->level < $this->level) { return $record; } - $record['extra']['hg'] = self::getMercurialInfo(); + $record->extra['hg'] = self::getMercurialInfo(); return $record; } diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 074cfa4fe..686c50491 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -25,7 +25,7 @@ class ProcessIdProcessor implements ProcessorInterface */ public function __invoke(LogRecord $record): LogRecord { - $record['extra']['process_id'] = getmypid(); + $record->extra['process_id'] = getmypid(); return $record; } diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 339aec510..5f6aede14 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -46,16 +46,16 @@ public function __construct(?string $dateFormat = null, bool $removeUsedContextF */ public function __invoke(LogRecord $record): LogRecord { - if (false === strpos($record['message'], '{')) { + if (false === strpos($record->message, '{')) { return $record; } $replacements = []; - $context = $record['context']; + $context = $record->context; foreach ($context as $key => $val) { $placeholder = '{' . $key . '}'; - if (strpos($record['message'], $placeholder) === false) { + if (strpos($record->message, $placeholder) === false) { continue; } @@ -82,6 +82,6 @@ public function __invoke(LogRecord $record): LogRecord } } - return $record->with(message: strtr($record['message'], $replacements), context: $context); + return $record->with(message: strtr($record->message, $replacements), context: $context); } } diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 58133b426..85d56c3a1 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -38,7 +38,7 @@ public function __construct(int $length = 7) */ public function __invoke(LogRecord $record): LogRecord { - $record['extra']['uid'] = $this->uid; + $record->extra['uid'] = $this->uid; return $record; } diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index a1d3dc860..27496ebb8 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -86,7 +86,7 @@ public function __invoke(LogRecord $record): LogRecord return $record; } - $record['extra'] = $this->appendExtraFields($record['extra']); + $record->extra = $this->appendExtraFields($record->extra); return $record; } diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 42e1c870e..839816367 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -26,7 +26,8 @@ class TestCase extends \PHPUnit\Framework\TestCase { /** - * @param mixed[] $context + * @param array $context + * @param array $extra * * @phpstan-param Level $level */ diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index ea22ec086..38fd66c83 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -43,7 +43,7 @@ public function testFormat() $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); $record = $this->getRecord(); - $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); + $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record->datetime->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } /** @@ -66,7 +66,7 @@ public function testFormatWithPrettyPrint() "level": 300, "level_name": "WARNING", "channel": "test", - "datetime": "'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'", + "datetime": "'.$record->datetime->format('Y-m-d\TH:i:s.uP').'", "extra": {} }', $formatter->format($record) @@ -74,7 +74,7 @@ public function testFormatWithPrettyPrint() $formatter->setJsonPrettyPrint(false); $record = $this->getRecord(); - $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); + $this->assertEquals('{"message":"test","context":{},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record->datetime->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } /** @@ -187,7 +187,7 @@ public function testDefFormatWithResource() $record = $this->getRecord( context: ['field_resource' => opendir(__DIR__)], ); - $this->assertEquals('{"message":"test","context":{"field_resource":"[resource(stream)]"},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record['datetime']->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); + $this->assertEquals('{"message":"test","context":{"field_resource":"[resource(stream)]"},"level":300,"level_name":"WARNING","channel":"test","datetime":"'.$record->datetime->format('Y-m-d\TH:i:s.uP').'","extra":{}}', $formatter->format($record)); } /** diff --git a/tests/Monolog/Formatter/LogglyFormatterTest.php b/tests/Monolog/Formatter/LogglyFormatterTest.php index 2eff4ac5d..de0aeb856 100644 --- a/tests/Monolog/Formatter/LogglyFormatterTest.php +++ b/tests/Monolog/Formatter/LogglyFormatterTest.php @@ -36,6 +36,6 @@ public function testFormat() $formatted_decoded = json_decode($formatter->format($record), true); $this->assertArrayNotHasKey("datetime", $formatted_decoded); $this->assertArrayHasKey("timestamp", $formatted_decoded); - $this->assertEquals($record["datetime"]->format('Y-m-d\TH:i:s.uO'), $formatted_decoded["timestamp"]); + $this->assertEquals($record->datetime->format('Y-m-d\TH:i:s.uO'), $formatted_decoded["timestamp"]); } } diff --git a/tests/Monolog/Handler/BufferHandlerTest.php b/tests/Monolog/Handler/BufferHandlerTest.php index 4867d1826..15c77b386 100644 --- a/tests/Monolog/Handler/BufferHandlerTest.php +++ b/tests/Monolog/Handler/BufferHandlerTest.php @@ -145,7 +145,7 @@ public function testHandleUsesProcessors() $test = new TestHandler(); $handler = new BufferHandler($test); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); diff --git a/tests/Monolog/Handler/DeduplicationHandlerTest.php b/tests/Monolog/Handler/DeduplicationHandlerTest.php index b5c760c7d..86c7c8a5d 100644 --- a/tests/Monolog/Handler/DeduplicationHandlerTest.php +++ b/tests/Monolog/Handler/DeduplicationHandlerTest.php @@ -122,7 +122,7 @@ public function testGcOldLogs() // log is written as none of them are duplicate $handler->flush(); $this->assertSame( - $record['datetime']->getTimestamp() . ":ERROR:test\n" . + $record->datetime->getTimestamp() . ":ERROR:test\n" . $record2['datetime']->getTimestamp() . ":CRITICAL:test\n" . $record3['datetime']->getTimestamp() . ":CRITICAL:test\n", file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log') @@ -144,7 +144,7 @@ public function testGcOldLogs() // log should now contain the new errors and the previous one that was recent enough $this->assertSame( $record3['datetime']->getTimestamp() . ":CRITICAL:test\n" . - $record['datetime']->getTimestamp() . ":ERROR:test\n" . + $record->datetime->getTimestamp() . ":ERROR:test\n" . $record2['datetime']->getTimestamp() . ":CRITICAL:test\n", file_get_contents(sys_get_temp_dir() . '/monolog_dedup.log') ); diff --git a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php index 1d5aa14bc..35330681e 100644 --- a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php +++ b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -38,7 +38,7 @@ public function testHandle() 'level' => Logger::WARNING, 'level_name' => 'WARNING', 'channel' => 'test', - 'datetime' => (string) $record['datetime'], + 'datetime' => (string) $record->datetime, 'extra' => [], ]; diff --git a/tests/Monolog/Handler/FallbackGroupHandlerTest.php b/tests/Monolog/Handler/FallbackGroupHandlerTest.php index f92a5afea..0cb149bcb 100644 --- a/tests/Monolog/Handler/FallbackGroupHandlerTest.php +++ b/tests/Monolog/Handler/FallbackGroupHandlerTest.php @@ -98,7 +98,7 @@ public function testHandleUsesProcessors() $test = new TestHandler(); $handler = new FallbackGroupHandler([$test]); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); @@ -118,12 +118,12 @@ public function testHandleBatchUsesProcessors() $testHandlers = [$testHandlerOne, $testHandlerTwo]; $handler = new FallbackGroupHandler($testHandlers); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); $handler->pushProcessor(function ($record) { - $record['extra']['foo2'] = true; + $record->extra['foo2'] = true; return $record; }); diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index 6058fade2..49ecb12b8 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -110,7 +110,7 @@ public function testHandleUsesProcessors() $handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY); $handler->pushProcessor( function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; } diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index eecc2e4c8..931171402 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -56,8 +56,8 @@ public function testDebug() $expectedMessage ->setLevel(7) ->setFacility("test") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) + ->setShortMessage($record->message) + ->setTimestamp($record->datetime) ; $messagePublisher = $this->getMessagePublisher(); @@ -77,8 +77,8 @@ public function testWarning() $expectedMessage ->setLevel(4) ->setFacility("test") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) + ->setShortMessage($record->message) + ->setTimestamp($record->datetime) ; $messagePublisher = $this->getMessagePublisher(); @@ -105,8 +105,8 @@ public function testInjectedGelfMessageFormatter() ->setLevel(4) ->setFacility("test") ->setHost("mysystem") - ->setShortMessage($record['message']) - ->setTimestamp($record['datetime']) + ->setShortMessage($record->message) + ->setTimestamp($record->datetime) ->setAdditional("EXTblarg", 'yep') ->setAdditional("CTXfrom", 'logger') ; diff --git a/tests/Monolog/Handler/GroupHandlerTest.php b/tests/Monolog/Handler/GroupHandlerTest.php index e2a2a147d..97680db30 100644 --- a/tests/Monolog/Handler/GroupHandlerTest.php +++ b/tests/Monolog/Handler/GroupHandlerTest.php @@ -78,7 +78,7 @@ public function testHandleUsesProcessors() $test = new TestHandler(); $handler = new GroupHandler([$test]); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); @@ -96,12 +96,12 @@ public function testHandleBatchUsesProcessors() $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new GroupHandler($testHandlers); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); $handler->pushProcessor(function ($record) { - $record['extra']['foo2'] = true; + $record->extra['foo2'] = true; return $record; }); diff --git a/tests/Monolog/Handler/MailHandlerTest.php b/tests/Monolog/Handler/MailHandlerTest.php index 5a52819c8..d85a70771 100644 --- a/tests/Monolog/Handler/MailHandlerTest.php +++ b/tests/Monolog/Handler/MailHandlerTest.php @@ -65,7 +65,7 @@ public function testHandle() $record = $this->getRecord(); $records = [$record]; - $records[0]['formatted'] = '['.$record['datetime'].'] test.WARNING: test [] []'."\n"; + $records[0]['formatted'] = '['.$record->datetime.'] test.WARNING: test [] []'."\n"; $handler->expects($this->once()) ->method('send') diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index 6cc976a70..6fbdc5f39 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -44,7 +44,7 @@ public function testHandleWithLibraryClient() $record = $this->getRecord(); $expected = $record->toArray(); - $expected['datetime'] = new \MongoDB\BSON\UTCDateTime((int) floor(((float) $record['datetime']->format('U.u')) * 1000)); + $expected['datetime'] = new \MongoDB\BSON\UTCDateTime((int) floor(((float) $record->datetime->format('U.u')) * 1000)); $collection->expects($this->once()) ->method('insertOne') diff --git a/tests/Monolog/Handler/NewRelicHandlerTest.php b/tests/Monolog/Handler/NewRelicHandlerTest.php index a02a6efef..b60f0b781 100644 --- a/tests/Monolog/Handler/NewRelicHandlerTest.php +++ b/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -67,7 +67,7 @@ public function testThehandlerCanAddExplodedContextParamsToTheNewRelicTrace() public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() { $record = $this->getRecord(Logger::ERROR, 'log message'); - $record['extra'] = ['c' => 'd']; + $record->extra = ['c' => 'd']; $handler = new StubNewRelicHandler(); $handler->handle($record); @@ -78,7 +78,7 @@ public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace() { $record = $this->getRecord(Logger::ERROR, 'log message'); - $record['extra'] = ['c' => ['key1' => 'value1', 'key2' => 'value2']]; + $record->extra = ['c' => ['key1' => 'value1', 'key2' => 'value2']]; $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true); $handler->handle($record); @@ -92,7 +92,7 @@ public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace() public function testThehandlerCanAddExtraContextAndParamsToTheNewRelicTrace() { $record = $this->getRecord(Logger::ERROR, 'log message', ['a' => 'b']); - $record['extra'] = ['c' => 'd']; + $record->extra = ['c' => 'd']; $handler = new StubNewRelicHandler(); $handler->handle($record); diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index 10738955a..563bec728 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -168,7 +168,7 @@ public function testTextEqualsFormatterOutput() ->expects($this->any()) ->method('format') ->will($this->returnCallback(function ($record) { - return $record['message'] . 'test'; + return $record->message . 'test'; })); $formatter2 = $this->createMock('Monolog\\Formatter\\FormatterInterface'); @@ -176,7 +176,7 @@ public function testTextEqualsFormatterOutput() ->expects($this->any()) ->method('format') ->will($this->returnCallback(function ($record) { - return $record['message'] . 'test1'; + return $record->message . 'test1'; })); $message = 'Test message'; @@ -345,7 +345,7 @@ public function testAddsTimestampToAttachment() $attachment = $data['attachments'][0]; $this->assertArrayHasKey('ts', $attachment); - $this->assertSame($record['datetime']->getTimestamp(), $attachment['ts']); + $this->assertSame($record->datetime->getTimestamp(), $attachment['ts']); } public function testContextHasException() @@ -361,9 +361,9 @@ public function testExcludeExtraAndContextFields() $record = $this->getRecord( Logger::WARNING, 'test', - array('info' => array('library' => 'monolog', 'author' => 'Jordi')) + context: array('info' => array('library' => 'monolog', 'author' => 'Jordi')), + extra: array('tags' => array('web', 'cli')), ); - $record['extra'] = array('tags' => array('web', 'cli')); $slackRecord = new SlackRecord(null, null, true, null, false, true, array('context.info.library', 'extra.tags.1')); $data = $slackRecord->getSlackData($record); diff --git a/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/tests/Monolog/Handler/SlackWebhookHandlerTest.php index 36990ebfd..5ff262254 100644 --- a/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ b/tests/Monolog/Handler/SlackWebhookHandlerTest.php @@ -50,7 +50,7 @@ public function testConstructorMinimal() ), 'title' => 'Message', 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp(), + 'ts' => $record->datetime->getTimestamp(), 'footer' => null, 'footer_icon' => null, ), diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 6b8d0d8ed..3d0d3b128 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -78,7 +78,7 @@ public function testHandleUsesProcessors() $test = new TestHandler(); $handler = new WhatFailureGroupHandler([$test]); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); @@ -96,12 +96,12 @@ public function testHandleBatchUsesProcessors() $testHandlers = array(new TestHandler(), new TestHandler()); $handler = new WhatFailureGroupHandler($testHandlers); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); $handler->pushProcessor(function ($record) { - $record['extra']['foo2'] = true; + $record->extra['foo2'] = true; return $record; }); @@ -127,7 +127,7 @@ public function testHandleException() $exception = new ExceptionTestHandler(); $handler = new WhatFailureGroupHandler([$exception, $test, $exception]); $handler->pushProcessor(function ($record) { - $record['extra']['foo'] = true; + $record->extra['foo'] = true; return $record; }); diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index e8fe55c50..42622ffbb 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -32,7 +32,7 @@ public function testWrite() { $record = $this->getRecord(); $formatterResult = [ - 'message' => $record['message'], + 'message' => $record->message, ]; $zendMonitor = $this->getMockBuilder('Monolog\Handler\ZendMonitorHandler') @@ -56,10 +56,10 @@ public function testWrite() $zendMonitor->expects($this->once()) ->method('writeZendMonitorCustomEvent') ->with( - Logger::getLevelName($record['level']), - $record['message'], + Logger::getLevelName($record->level), + $record->message, $formatterResult, - $levelMap[$record['level']] + $levelMap[$record->level] ); $zendMonitor->handle($record); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index f49a6f457..9ba62f749 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -82,7 +82,7 @@ public function testChannel() $logger->pushHandler($handler); $logger->warning('test'); list($record) = $handler->getRecords(); - $this->assertEquals('foo', $record['channel']); + $this->assertEquals('foo', $record->channel); } /** @@ -229,13 +229,13 @@ public function testProcessorsAreExecuted() $handler = new TestHandler; $logger->pushHandler($handler); $logger->pushProcessor(function ($record) { - $record['extra']['win'] = true; + $record->extra['win'] = true; return $record; }); $logger->error('test'); list($record) = $handler->getRecords(); - $this->assertTrue($record['extra']['win']); + $this->assertTrue($record->extra['win']); } /** @@ -478,7 +478,7 @@ public function testLogMethods($method, $expectedLevel) $logger->pushHandler($handler); $logger->{$method}('test'); list($record) = $handler->getRecords(); - $this->assertEquals($expectedLevel, $record['level']); + $this->assertEquals($expectedLevel, $record->level); } public function logMethodProvider() @@ -508,7 +508,7 @@ public function testSetTimezone($tz) $logger->pushHandler($handler); $logger->info('test'); list($record) = $handler->getRecords(); - $this->assertEquals($tz, $record['datetime']->getTimezone()); + $this->assertEquals($tz, $record->datetime->getTimezone()); } public function setTimezoneProvider() @@ -538,8 +538,8 @@ public function testTimezoneIsRespectedInUTC() $logger->info('test'); list($record) = $handler->getRecords(); - $this->assertEquals($tz, $record['datetime']->getTimezone()); - $this->assertEquals($dt->format('Y/m/d H:i'), $record['datetime']->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); + $this->assertEquals($tz, $record->datetime->getTimezone()); + $this->assertEquals($dt->format('Y/m/d H:i'), $record->datetime->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); } } @@ -561,8 +561,8 @@ public function testTimezoneIsRespectedInOtherTimezone() $logger->info('test'); list($record) = $handler->getRecords(); - $this->assertEquals($tz, $record['datetime']->getTimezone()); - $this->assertEquals($dt->format('Y/m/d H:i'), $record['datetime']->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); + $this->assertEquals($tz, $record->datetime->getTimezone()); + $this->assertEquals($dt->format('Y/m/d H:i'), $record->datetime->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); } } @@ -588,8 +588,8 @@ public function testUseMicrosecondTimestamps($micro, $assert, $assertFormat) $logger->pushHandler($handler); $logger->info('test'); list($record) = $handler->getRecords(); - $this->{$assert}('000000', $record['datetime']->format('u')); - $this->assertSame($record['datetime']->format($assertFormat), (string) $record['datetime']); + $this->{$assert}('000000', $record->datetime->format('u')); + $this->assertSame($record->datetime->format($assertFormat), (string) $record->datetime); } public function useMicrosecondTimestampsProvider() @@ -648,7 +648,7 @@ public function testCustomHandleException() $logger->setExceptionHandler(function ($e, $record) use ($that) { $that->assertEquals($e->getMessage(), 'Some handler exception'); $that->assertInstanceOf(LogRecord::class, $record); - $that->assertEquals($record['message'], 'test'); + $that->assertEquals($record->message, 'test'); }); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); $handler->expects($this->any()) diff --git a/tests/Monolog/Processor/GitProcessorTest.php b/tests/Monolog/Processor/GitProcessorTest.php index 0059e6d39..4b0e1b0cd 100644 --- a/tests/Monolog/Processor/GitProcessorTest.php +++ b/tests/Monolog/Processor/GitProcessorTest.php @@ -23,7 +23,7 @@ public function testProcessor() $processor = new GitProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('git', $record['extra']); - $this->assertTrue(!is_array($record['extra']['git']['branch'])); + $this->assertArrayHasKey('git', $record->extra); + $this->assertTrue(!is_array($record->extra['git']['branch'])); } } diff --git a/tests/Monolog/Processor/HostnameProcessorTest.php b/tests/Monolog/Processor/HostnameProcessorTest.php index c5745751e..2329ea858 100644 --- a/tests/Monolog/Processor/HostnameProcessorTest.php +++ b/tests/Monolog/Processor/HostnameProcessorTest.php @@ -22,9 +22,9 @@ public function testProcessor() { $processor = new HostnameProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('hostname', $record['extra']); - $this->assertIsString($record['extra']['hostname']); - $this->assertNotEmpty($record['extra']['hostname']); - $this->assertEquals(gethostname(), $record['extra']['hostname']); + $this->assertArrayHasKey('hostname', $record->extra); + $this->assertIsString($record->extra['hostname']); + $this->assertNotEmpty($record->extra['hostname']); + $this->assertEquals(gethostname(), $record->extra['hostname']); } } diff --git a/tests/Monolog/Processor/IntrospectionProcessorTest.php b/tests/Monolog/Processor/IntrospectionProcessorTest.php index cb1d8b91c..ac5b523d0 100644 --- a/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ b/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -47,10 +47,10 @@ public function testProcessorFromClass() $tester = new \Acme\Tester; $tester->test($handler, $this->getRecord()); list($record) = $handler->getRecords(); - $this->assertEquals(__FILE__, $record['extra']['file']); - $this->assertEquals(18, $record['extra']['line']); - $this->assertEquals('Acme\Tester', $record['extra']['class']); - $this->assertEquals('test', $record['extra']['function']); + $this->assertEquals(__FILE__, $record->extra['file']); + $this->assertEquals(18, $record->extra['line']); + $this->assertEquals('Acme\Tester', $record->extra['class']); + $this->assertEquals('test', $record->extra['function']); } public function testProcessorFromFunc() @@ -58,10 +58,10 @@ public function testProcessorFromFunc() $handler = $this->getHandler(); \Acme\tester($handler, $this->getRecord()); list($record) = $handler->getRecords(); - $this->assertEquals(__FILE__, $record['extra']['file']); - $this->assertEquals(24, $record['extra']['line']); - $this->assertEquals(null, $record['extra']['class']); - $this->assertEquals('Acme\tester', $record['extra']['function']); + $this->assertEquals(__FILE__, $record->extra['file']); + $this->assertEquals(24, $record->extra['line']); + $this->assertEquals(null, $record->extra['class']); + $this->assertEquals('Acme\tester', $record->extra['function']); } public function testLevelTooLow() diff --git a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php index 964fbbe2f..0ff304ae0 100644 --- a/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryPeakUsageProcessorTest.php @@ -23,8 +23,8 @@ public function testProcessor() { $processor = new MemoryPeakUsageProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_peak_usage']); + $this->assertArrayHasKey('memory_peak_usage', $record->extra); + $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record->extra['memory_peak_usage']); } /** @@ -35,8 +35,8 @@ public function testProcessorWithoutFormatting() { $processor = new MemoryPeakUsageProcessor(true, false); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_peak_usage', $record['extra']); - $this->assertIsInt($record['extra']['memory_peak_usage']); - $this->assertGreaterThan(0, $record['extra']['memory_peak_usage']); + $this->assertArrayHasKey('memory_peak_usage', $record->extra); + $this->assertIsInt($record->extra['memory_peak_usage']); + $this->assertGreaterThan(0, $record->extra['memory_peak_usage']); } } diff --git a/tests/Monolog/Processor/MemoryUsageProcessorTest.php b/tests/Monolog/Processor/MemoryUsageProcessorTest.php index 22c047c2b..a68c71eaa 100644 --- a/tests/Monolog/Processor/MemoryUsageProcessorTest.php +++ b/tests/Monolog/Processor/MemoryUsageProcessorTest.php @@ -23,8 +23,8 @@ public function testProcessor() { $processor = new MemoryUsageProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record['extra']['memory_usage']); + $this->assertArrayHasKey('memory_usage', $record->extra); + $this->assertMatchesRegularExpression('#[0-9.]+ (M|K)?B$#', $record->extra['memory_usage']); } /** @@ -35,8 +35,8 @@ public function testProcessorWithoutFormatting() { $processor = new MemoryUsageProcessor(true, false); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('memory_usage', $record['extra']); - $this->assertIsInt($record['extra']['memory_usage']); - $this->assertGreaterThan(0, $record['extra']['memory_usage']); + $this->assertArrayHasKey('memory_usage', $record->extra); + $this->assertIsInt($record->extra['memory_usage']); + $this->assertGreaterThan(0, $record->extra['memory_usage']); } } diff --git a/tests/Monolog/Processor/MercurialProcessorTest.php b/tests/Monolog/Processor/MercurialProcessorTest.php index 9028e41e8..2e20bae15 100644 --- a/tests/Monolog/Processor/MercurialProcessorTest.php +++ b/tests/Monolog/Processor/MercurialProcessorTest.php @@ -35,8 +35,8 @@ public function testProcessor() $processor = new MercurialProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('hg', $record['extra']); - $this->assertTrue(!is_array($record['extra']['hg']['branch'])); - $this->assertTrue(!is_array($record['extra']['hg']['revision'])); + $this->assertArrayHasKey('hg', $record->extra); + $this->assertTrue(!is_array($record->extra['hg']['branch'])); + $this->assertTrue(!is_array($record->extra['hg']['revision'])); } } diff --git a/tests/Monolog/Processor/ProcessIdProcessorTest.php b/tests/Monolog/Processor/ProcessIdProcessorTest.php index 0b3446faa..57de72209 100644 --- a/tests/Monolog/Processor/ProcessIdProcessorTest.php +++ b/tests/Monolog/Processor/ProcessIdProcessorTest.php @@ -22,9 +22,9 @@ public function testProcessor() { $processor = new ProcessIdProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('process_id', $record['extra']); - $this->assertIsInt($record['extra']['process_id']); - $this->assertGreaterThan(0, $record['extra']['process_id']); - $this->assertEquals(getmypid(), $record['extra']['process_id']); + $this->assertArrayHasKey('process_id', $record->extra); + $this->assertIsInt($record->extra['process_id']); + $this->assertGreaterThan(0, $record->extra['process_id']); + $this->assertEquals(getmypid(), $record->extra['process_id']); } } diff --git a/tests/Monolog/Processor/TagProcessorTest.php b/tests/Monolog/Processor/TagProcessorTest.php index da84378b6..db729e549 100644 --- a/tests/Monolog/Processor/TagProcessorTest.php +++ b/tests/Monolog/Processor/TagProcessorTest.php @@ -24,7 +24,7 @@ public function testProcessor() $processor = new TagProcessor($tags); $record = $processor($this->getRecord()); - $this->assertEquals($tags, $record['extra']['tags']); + $this->assertEquals($tags, $record->extra['tags']); } /** @@ -36,14 +36,14 @@ public function testProcessorTagModification() $processor = new TagProcessor($tags); $record = $processor($this->getRecord()); - $this->assertEquals($tags, $record['extra']['tags']); + $this->assertEquals($tags, $record->extra['tags']); $processor->setTags(['a', 'b']); $record = $processor($this->getRecord()); - $this->assertEquals(['a', 'b'], $record['extra']['tags']); + $this->assertEquals(['a', 'b'], $record->extra['tags']); $processor->addTags(['a', 'c', 'foo' => 'bar']); $record = $processor($this->getRecord()); - $this->assertEquals(['a', 'b', 'a', 'c', 'foo' => 'bar'], $record['extra']['tags']); + $this->assertEquals(['a', 'b', 'a', 'c', 'foo' => 'bar'], $record->extra['tags']); } } diff --git a/tests/Monolog/Processor/UidProcessorTest.php b/tests/Monolog/Processor/UidProcessorTest.php index 927d56482..d9288acd5 100644 --- a/tests/Monolog/Processor/UidProcessorTest.php +++ b/tests/Monolog/Processor/UidProcessorTest.php @@ -22,7 +22,7 @@ public function testProcessor() { $processor = new UidProcessor(); $record = $processor($this->getRecord()); - $this->assertArrayHasKey('uid', $record['extra']); + $this->assertArrayHasKey('uid', $record->extra); } public function testGetUid() diff --git a/tests/Monolog/Processor/WebProcessorTest.php b/tests/Monolog/Processor/WebProcessorTest.php index 3f9948932..5a7ac299f 100644 --- a/tests/Monolog/Processor/WebProcessorTest.php +++ b/tests/Monolog/Processor/WebProcessorTest.php @@ -28,12 +28,12 @@ public function testProcessor() $processor = new WebProcessor($server); $record = $processor($this->getRecord()); - $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); - $this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']); - $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']); - $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); - $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']); - $this->assertEquals($server['UNIQUE_ID'], $record['extra']['unique_id']); + $this->assertEquals($server['REQUEST_URI'], $record->extra['url']); + $this->assertEquals($server['REMOTE_ADDR'], $record->extra['ip']); + $this->assertEquals($server['REQUEST_METHOD'], $record->extra['http_method']); + $this->assertEquals($server['HTTP_REFERER'], $record->extra['referrer']); + $this->assertEquals($server['SERVER_NAME'], $record->extra['server']); + $this->assertEquals($server['UNIQUE_ID'], $record->extra['unique_id']); } public function testProcessorDoNothingIfNoRequestUri() @@ -44,7 +44,7 @@ public function testProcessorDoNothingIfNoRequestUri() ]; $processor = new WebProcessor($server); $record = $processor($this->getRecord()); - $this->assertEmpty($record['extra']); + $this->assertEmpty($record->extra); } public function testProcessorReturnNullIfNoHttpReferer() @@ -57,7 +57,7 @@ public function testProcessorReturnNullIfNoHttpReferer() ]; $processor = new WebProcessor($server); $record = $processor($this->getRecord()); - $this->assertNull($record['extra']['referrer']); + $this->assertNull($record->extra['referrer']); } public function testProcessorDoesNotAddUniqueIdIfNotPresent() @@ -70,7 +70,7 @@ public function testProcessorDoesNotAddUniqueIdIfNotPresent() ]; $processor = new WebProcessor($server); $record = $processor($this->getRecord()); - $this->assertFalse(isset($record['extra']['unique_id'])); + $this->assertFalse(isset($record->extra['unique_id'])); } public function testProcessorAddsOnlyRequestedExtraFields() @@ -85,7 +85,7 @@ public function testProcessorAddsOnlyRequestedExtraFields() $processor = new WebProcessor($server, ['url', 'http_method']); $record = $processor($this->getRecord()); - $this->assertSame(['url' => 'A', 'http_method' => 'C'], $record['extra']); + $this->assertSame(['url' => 'A', 'http_method' => 'C'], $record->extra); } public function testProcessorAddsOnlyRequestedExtraFieldsIncludingOptionalFields() @@ -98,7 +98,7 @@ public function testProcessorAddsOnlyRequestedExtraFieldsIncludingOptionalFields $processor = new WebProcessor($server, array('url')); $record = $processor($this->getRecord()); - $this->assertSame(array('url' => 'A'), $record['extra']); + $this->assertSame(array('url' => 'A'), $record->extra); } public function testProcessorConfiguringOfExtraFields() @@ -113,7 +113,7 @@ public function testProcessorConfiguringOfExtraFields() $processor = new WebProcessor($server, ['url' => 'REMOTE_ADDR']); $record = $processor($this->getRecord()); - $this->assertSame(['url' => 'B'], $record['extra']); + $this->assertSame(['url' => 'B'], $record->extra); } public function testInvalidData() diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index eaeb3552c..529b7d29f 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -44,7 +44,7 @@ public function getLogs(): array return strtolower($match[0]); }; - return preg_replace_callback('{^[A-Z]+}', $lower, $record['formatted']); + return preg_replace_callback('{^[A-Z]+}', $lower, $record->formatted); }; return array_map($convert, $this->handler->getRecords()); From 657ff7f91635242527d06380e51e7274caa3b5d2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 5 Mar 2022 14:22:06 +0100 Subject: [PATCH 413/498] Drop support for aws-php-sdk v2 from DynamoDbHandler --- composer.json | 2 +- src/Monolog/Handler/DynamoDbHandler.php | 20 ++------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 341bb181d..888fc88a0 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "psr/log": "^2.0 || ^3.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "aws/aws-sdk-php": "^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7", "mongodb/mongodb": "^1.8", diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index b154d1432..175ab71b7 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -39,11 +39,6 @@ class DynamoDbHandler extends AbstractProcessingHandler */ protected $table; - /** - * @var int - */ - protected $version; - /** * @var Marshaler */ @@ -51,13 +46,7 @@ class DynamoDbHandler extends AbstractProcessingHandler public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true) { - /** @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->marshaler = new Marshaler; $this->client = $client; $this->table = $table; @@ -71,12 +60,7 @@ public function __construct(DynamoDbClient $client, string $table, $level = Logg protected function write(LogRecord $record): void { $filtered = $this->filterEmptyFields($record->formatted); - if ($this->version === 3) { - $formatted = $this->marshaler->marshalItem($filtered); - } else { - /** @phpstan-ignore-next-line */ - $formatted = $this->client->formatAttributes($filtered); - } + $formatted = $this->marshaler->marshalItem($filtered); $this->client->putItem([ 'TableName' => $this->table, From 6b5bd6af5b6e06aeba17a8744e281cbe9f0e9ab1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 5 Mar 2022 14:34:21 +0100 Subject: [PATCH 414/498] More cleanups --- phpstan-baseline.neon | 62 +++++++++++++++++++ phpstan.neon.dist | 20 +----- src/Monolog/Formatter/ElasticaFormatter.php | 2 + src/Monolog/Formatter/JsonFormatter.php | 8 +-- src/Monolog/Formatter/NormalizerFormatter.php | 22 ++++--- src/Monolog/Formatter/WildfireFormatter.php | 16 +++-- src/Monolog/Handler/BrowserConsoleHandler.php | 6 +- src/Monolog/Handler/CubeHandler.php | 8 ++- src/Monolog/Handler/Slack/SlackRecord.php | 2 + src/Monolog/Handler/SyslogUdp/UdpSocket.php | 6 +- src/Monolog/Processor/UidProcessor.php | 11 +++- 11 files changed, 114 insertions(+), 49 deletions(-) create mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..cc808e7ac --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,62 @@ +parameters: + ignoreErrors: + - + message: "#^Property Monolog\\\\ErrorHandler\\:\\:\\$reservedMemory is never read, only written\\.$#" + count: 1 + path: src/Monolog/ErrorHandler.php + + - + message: "#^Cannot access offset 'table' on array\\\\|bool\\|float\\|int\\|object\\|string\\|null\\.$#" + count: 1 + path: src/Monolog/Formatter/WildfireFormatter.php + + - + message: "#^Call to method setBody\\(\\) on an unknown class Swift_Message\\.$#" + count: 1 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Call to method setDate\\(\\) on an unknown class Swift_Message\\.$#" + count: 1 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Class Swift_Message not found\\.$#" + count: 2 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Cloning object of an unknown class Swift_Message\\.$#" + count: 1 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Parameter \\$message of method Monolog\\\\Handler\\\\MandrillHandler\\:\\:__construct\\(\\) has invalid type Swift_Message\\.$#" + count: 2 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Property Monolog\\\\Handler\\\\MandrillHandler\\:\\:\\$message has unknown class Swift_Message as its type\\.$#" + count: 1 + path: src/Monolog/Handler/MandrillHandler.php + + - + message: "#^Comparison operation \"\\<\" between int\\<1, 32\\> and 1 is always false\\.$#" + count: 1 + path: src/Monolog/Processor/UidProcessor.php + + - + message: "#^Comparison operation \"\\>\" between int\\<1, 32\\> and 32 is always false\\.$#" + count: 1 + path: src/Monolog/Processor/UidProcessor.php + + - + message: "#^Method Monolog\\\\Processor\\\\UidProcessor\\:\\:generateUid\\(\\) should return non\\-empty\\-string but returns string\\.$#" + count: 1 + path: src/Monolog/Processor/UidProcessor.php + + - + message: "#^Parameter \\#1 \\$length of function random_bytes expects int\\<1, max\\>, int given\\.$#" + count: 1 + path: src/Monolog/Processor/UidProcessor.php + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 961f7ce47..1ac285245 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,7 @@ parameters: level: 8 treatPhpDocTypesAsCertain: false - reportUnmatchedIgnoredErrors: false + reportUnmatchedIgnoredErrors: true paths: - src/ @@ -19,19 +19,5 @@ parameters: paths: - src/Monolog/Formatter/LineFormatter.php - # blocked until we only support php8+ - - '#Parameter \#1 \$socket of function (socket_close|socket_sendto|socket_send) expects Socket, resource\|Socket(\|null)? given\.#' - - '#Parameter \#1 \$handle of function (curl_exec|curl_close|curl_error|curl_errno|curl_setopt) expects CurlHandle, CurlHandle\|resource(\|null)? given\.#' - - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' - paths: - - src/Monolog/Handler/LogglyHandler.php - - # blocked by https://github.com/phpstan/phpstan/issues/5091 - - '#has unknown class Monolog\\Handler\\Record#' - - '#::processRecord\(\) should return array#' - - '#::processRecord\(\) has invalid type#' - - '#::processRecord\(\) return type has no value type#' - - '#::processRecord\(\) has parameter \$record with no value type#' - - '#::popProcessor\(\) should return callable#' - - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#' - - '#is incompatible with native type array.#' +includes: + - phpstan-baseline.neon diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index e60fc6f95..1d7cdca71 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -70,6 +70,8 @@ public function getType(): string /** * Convert a log message into an Elastica Document + * + * @param mixed[] $record */ protected function getDocument(array $record): Document { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index aee6b5df2..d56185916 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -136,16 +136,12 @@ protected function formatBatchJson(array $records): string */ protected function formatBatchNewlines(array $records): string { - $instance = $this; - $oldNewline = $this->appendNewline; $this->appendNewline = false; - array_walk($records, function (&$value, $key) use ($instance) { - $value = $instance->format($value); - }); + $formatted = array_map(fn (LogRecord $record) => $this->format($record), $records); $this->appendNewline = $oldNewline; - return implode("\n", $records); + return implode("\n", $formatted); } /** diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index b2deffaa3..cc45fe50b 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -48,14 +48,17 @@ public function __construct(?string $dateFormat = null) /** * {@inheritDoc} - * - * @param mixed[] $record */ public function format(LogRecord $record) { return $this->normalizeRecord($record); } + /** + * Normalize an arbitrary value to a scalar|array|null + * + * @return null|scalar|array + */ public function normalizeValue(mixed $data): mixed { return $this->normalize($data); @@ -134,15 +137,20 @@ public function setJsonPrettyPrint(bool $enable): self * * 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 */ protected function normalizeRecord(LogRecord $record): array { - return $this->normalize($record->toArray()); + /** @var array $normalized */ + $normalized = $this->normalize($record->toArray()); + + return $normalized; } /** * @param mixed $data - * @return null|scalar|array + * @return null|scalar|array */ protected function normalize(mixed $data, int $depth = 0): mixed { @@ -189,14 +197,14 @@ protected function normalize(mixed $data, int $depth = 0): mixed } if ($data instanceof \JsonSerializable) { - /** @var null|scalar|array $value */ + /** @var null|scalar|array $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 $value */ + /** @var null|scalar|array $value */ $value = json_decode($this->toJson($data, true), true); } @@ -246,7 +254,7 @@ protected function normalizeException(Throwable $e, int $depth = 0) $trace = $e->getTrace(); foreach ($trace as $frame) { - if (isset($frame['file'])) { + if (isset($frame['file'], $frame['line'])) { $data['trace'][] = $frame['file'].':'.$frame['line']; } } diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 7170b020b..0d7f23f09 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -70,26 +70,24 @@ public function format(LogRecord $record): string unset($record->extra['line']); } - /** @var mixed[] $record */ - $record = $this->normalize($record); $message = ['message' => $record->message]; $handleError = false; - if ($record->context) { - $message['context'] = $record->context; + if (count($record->context) > 0) { + $message['context'] = $this->normalize($record->context); $handleError = true; } - if ($record->extra) { - $message['extra'] = $record->extra; + if (count($record->extra) > 0) { + $message['extra'] = $this->normalize($record->extra); $handleError = true; } if (count($message) === 1) { $message = reset($message); } - if (isset($record->context['table'])) { + if (is_array($message) && isset($message['context']['table'])) { $type = 'TABLE'; $label = $record->channel .': '. $record->message; - $message = $record->context['table']; + $message = $message['context']['table']; } else { $type = $this->logLevels[$record->level]; $label = $record->channel; @@ -127,7 +125,7 @@ public function formatBatch(array $records) /** * {@inheritDoc} * - * @return null|scalar|array|object + * @return null|scalar|array|object */ protected function normalize(mixed $data, int $depth = 0): mixed { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index fa66da4b0..7c560de8c 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -81,9 +81,9 @@ public static function send(): void if (count(static::$records)) { if ($format === self::FORMAT_HTML) { - static::writeOutput(''); + static::writeOutput(''); } elseif ($format === self::FORMAT_JS) { - static::writeOutput(static::generateScript()); + static::writeOutput(self::generateScript()); } static::resetStatic(); } @@ -202,7 +202,7 @@ private static function handleStyles(string $formatted): array foreach (array_reverse($matches) as $match) { $args[] = '"font-weight: normal"'; - $args[] = self::quote(static::handleCustomStyles($match[2][0], $match[1][0])); + $args[] = self::quote(self::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])); diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index b86d50af2..40a16f5cf 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -23,9 +23,9 @@ */ class CubeHandler extends AbstractProcessingHandler { - /** @var resource|\Socket|null */ + /** @var \Socket|null */ private $udpConnection = null; - /** @var resource|\CurlHandle|null */ + /** @var \CurlHandle|null */ private $httpConnection = null; /** @var string */ private $scheme; @@ -143,6 +143,10 @@ private function writeUdp(string $data): void $this->connectUdp(); } + if (null === $this->udpConnection) { + throw new \LogicException('No UDP socket could be opened'); + } + socket_send($this->udpConnection, $data, strlen($data), 0); } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index fba862258..7e9e3233a 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -222,6 +222,7 @@ public function getAttachmentColor(int $level): string */ public function stringify(array $fields): string { + /** @var array $normalized */ $normalized = $this->normalizerFormatter->normalizeValue($fields); $hasSecondDimension = count(array_filter($normalized, 'is_array')); @@ -342,6 +343,7 @@ private function generateAttachmentField(string $title, $value): array */ private function generateAttachmentFields(array $data): array { + /** @var array $normalized */ $normalized = $this->normalizerFormatter->normalizeValue($data); $fields = array(); diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 30b5186bd..059286790 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -22,7 +22,7 @@ class UdpSocket protected $ip; /** @var int */ protected $port; - /** @var resource|Socket|null */ + /** @var Socket|null */ protected $socket; public function __construct(string $ip, int $port = 514) @@ -51,7 +51,7 @@ public function write($line, $header = "") public function close(): void { - if (is_resource($this->socket) || $this->socket instanceof Socket) { + if ($this->socket instanceof Socket) { socket_close($this->socket); $this->socket = null; } @@ -59,7 +59,7 @@ public function close(): void protected function send(string $chunk): void { - if (!is_resource($this->socket) && !$this->socket instanceof Socket) { + if (!$this->socket instanceof Socket) { throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); } socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 85d56c3a1..973b317e6 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -21,9 +21,12 @@ */ class UidProcessor implements ProcessorInterface, ResettableInterface { - /** @var string */ - private $uid; + /** @var non-empty-string */ + private string $uid; + /** + * @param int<1, 32> $length + */ public function __construct(int $length = 7) { if ($length > 32 || $length < 1) { @@ -53,6 +56,10 @@ 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); From 0aef68ce10edc93fac8d0a94ade7da17e8052844 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 14:08:32 +0100 Subject: [PATCH 415/498] Remove rollbar for now as it requires monolog 2.x or psr/log 1.x --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 888fc88a0..625e62e46 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "phpspec/prophecy": "^1.6.1", "phpunit/phpunit": "^9.5.16", "predis/predis": "^1.1", - "rollbar/rollbar": "^3", "ruflin/elastica": ">=0.90@dev", "phpstan/phpstan": "^1.4" }, From a3ba6445a4ce8562dc19209530fc865bb77203d8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 14 Mar 2022 14:11:15 +0100 Subject: [PATCH 416/498] Cleanups --- phpstan.neon.dist | 3 +++ src/Monolog/Formatter/ElasticaFormatter.php | 1 - src/Monolog/Logger.php | 1 - src/Monolog/Utils.php | 4 ++-- tests/Monolog/Formatter/MongoDBFormatterTest.php | 16 +++++++--------- tests/Monolog/Handler/StreamHandlerTest.php | 7 ++++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 1ac285245..5fcb94783 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -19,5 +19,8 @@ parameters: paths: - src/Monolog/Formatter/LineFormatter.php + # can be removed when rollbar/rollbar can be added as dev require again (needs to allow monolog 3.x) + - '#Rollbar\\RollbarLogger#' + includes: - phpstan-baseline.neon diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 1d7cdca71..1ab14c5ee 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -78,7 +78,6 @@ 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); diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index cdc705a50..882438448 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -421,7 +421,6 @@ public static function toMonologLevel($level): int { if (is_string($level)) { if (is_numeric($level)) { - /** @phpstan-ignore-next-line */ return intval($level); } diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 5354c99c7..e8c9d8930 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -267,10 +267,10 @@ public static function getRecordMessageForException(LogRecord $record): string $extra = ''; try { if ($record->context) { - $context = "\nContext: " . json_encode($record->context); + $context = "\nContext: " . json_encode($record->context, JSON_THROW_ON_ERROR); } if ($record->extra) { - $extra = "\nExtra: " . json_encode($record->extra); + $extra = "\nExtra: " . json_encode($record->extra, JSON_THROW_ON_ERROR); } } catch (\Throwable $e) { // noop diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index ecdb864cd..4874755fa 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -253,21 +253,19 @@ public function testFormatDepthException() public function testBsonTypes() { - $record = [ - 'message' => 'some log message', - 'context' => [ + $record = $this->getRecord( + message: 'some log message', + context: [ 'objectid' => new ObjectId(), 'nest' => [ 'timestamp' => new UTCDateTime(), 'regex' => new Regex('pattern'), ], ], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), - 'extra' => [], - ]; + level: Logger::WARNING, + channel: 'test', + datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), + ); $formatter = new MongoDBFormatter(); $formattedRecord = $formatter->format($record); diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 43a520bcd..97d56b8cf 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -166,9 +166,10 @@ public function testWriteInvalidResource() $this->expectExceptionMessage(($majorVersion >= 8) ? $php8xMessage : $php7xMessage); $handler = new StreamHandler('bogus://url'); - $record = $this->getRecord(); - $record['context'] = ['foo' => 'bar']; - $record['extra'] = [1, 2, 3]; + $record = $this->getRecord( + context: ['foo' => 'bar'], + extra: [1, 2, 3], + ); $handler->handle($record); } From 248673e85824f9f910738d870e73eafc7654213f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 21 Mar 2022 14:23:30 +0100 Subject: [PATCH 417/498] Remove at matcher --- tests/Monolog/Handler/UdpSocketTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index c14fa8d48..1e9b32f7f 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -26,7 +26,7 @@ public function testWeDoNotTruncateShortMessages() ->setConstructorArgs(['lol']) ->getMock(); - $socket->expects($this->at(0)) + $socket ->method('send') ->with("HEADER: The quick brown fox jumps over the lazy dog"); From 508df120fac348c1e7ed6e590d83c549fa95434e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:32:03 +0200 Subject: [PATCH 418/498] Make AsMonologProcessor compatible with PHP 7.2 --- src/Monolog/Attribute/AsMonologProcessor.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Attribute/AsMonologProcessor.php b/src/Monolog/Attribute/AsMonologProcessor.php index b52d07761..188bbb0d8 100644 --- a/src/Monolog/Attribute/AsMonologProcessor.php +++ b/src/Monolog/Attribute/AsMonologProcessor.php @@ -22,15 +22,25 @@ #[\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). */ public function __construct( - public ?string $channel = null, - public ?string $handler = null, - public ?string $method = null, + ?string $channel = null, + ?string $handler = null, + ?string $method = null ) { + $this->channel = $channel; + $this->handler = $handler; + $this->method = $method; } -} \ No newline at end of file +} From 4c43f12548a7ed757ce78388ab61fcbca9bf4bd7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:32:35 +0200 Subject: [PATCH 419/498] Link attribute file again --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cd260475a..9e20a03ea 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -29,4 +29,4 @@ jobs: php-version: "${{ matrix.php-version }}" - name: "Lint PHP files" - run: "find src/ -type f -name '*.php' -not -name AsMonologProcessor.php -print0 | xargs -0 -L1 -P4 -- php -l -f" + run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" From 4192345e260f1d51b365536199744b987e160edc Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Apr 2022 17:43:54 +0200 Subject: [PATCH 420/498] Update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dcc7a149..eb4963ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### 2.5.0 (2022-04-08) + +* Added `callType` to IntrospectionProcessor (#1612) +* Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651) + ### 2.4.0 (2022-03-14) * Added [`Monolog\LogRecord`](src/Monolog/LogRecord.php) interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes From 2d006a847235a3308510f638a27b8d12df1d1134 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Apr 2022 21:49:03 +0200 Subject: [PATCH 421/498] Convert level/levelName to enums (#1656) --- .gitignore | 2 +- .php_cs => .php-cs-fixer.php | 16 +- README.md | 4 +- doc/01-usage.md | 8 +- doc/04-extending.md | 2 +- doc/sockets.md | 3 +- src/Monolog/Formatter/ChromePHPFormatter.php | 28 ++-- src/Monolog/Formatter/FlowdockFormatter.php | 4 +- src/Monolog/Formatter/FluentdFormatter.php | 6 +- .../Formatter/GelfMessageFormatter.php | 32 ++-- src/Monolog/Formatter/HtmlFormatter.php | 33 ++-- src/Monolog/Formatter/WildfireFormatter.php | 40 ++--- src/Monolog/Handler/AbstractHandler.php | 31 ++-- .../Handler/AbstractProcessingHandler.php | 3 - src/Monolog/Handler/AbstractSyslogHandler.php | 69 ++++---- src/Monolog/Handler/AmqpHandler.php | 6 +- src/Monolog/Handler/BufferHandler.php | 7 +- src/Monolog/Handler/ChromePHPHandler.php | 6 +- src/Monolog/Handler/CouchDBHandler.php | 4 +- src/Monolog/Handler/CubeHandler.php | 4 +- src/Monolog/Handler/DeduplicationHandler.php | 18 +- .../Handler/DoctrineCouchDBHandler.php | 4 +- src/Monolog/Handler/DynamoDbHandler.php | 4 +- src/Monolog/Handler/ElasticaHandler.php | 4 +- src/Monolog/Handler/ElasticsearchHandler.php | 4 +- src/Monolog/Handler/ErrorLogHandler.php | 4 +- src/Monolog/Handler/FilterHandler.php | 47 +++--- .../ChannelLevelActivationStrategy.php | 33 ++-- .../ErrorLevelActivationStrategy.php | 20 +-- src/Monolog/Handler/FingersCrossedHandler.php | 22 +-- src/Monolog/Handler/FleepHookHandler.php | 4 +- src/Monolog/Handler/FlowdockHandler.php | 4 +- src/Monolog/Handler/GelfHandler.php | 4 +- src/Monolog/Handler/HandlerInterface.php | 2 - src/Monolog/Handler/IFTTTHandler.php | 4 +- src/Monolog/Handler/InsightOpsHandler.php | 4 +- src/Monolog/Handler/LogEntriesHandler.php | 4 +- src/Monolog/Handler/LogglyHandler.php | 4 +- src/Monolog/Handler/LogmaticHandler.php | 4 +- src/Monolog/Handler/MailHandler.php | 4 +- src/Monolog/Handler/MandrillHandler.php | 4 +- src/Monolog/Handler/MongoDBHandler.php | 4 +- src/Monolog/Handler/NativeMailerHandler.php | 4 +- src/Monolog/Handler/NewRelicHandler.php | 4 +- src/Monolog/Handler/NullHandler.php | 22 +-- src/Monolog/Handler/OverflowHandler.php | 25 +-- src/Monolog/Handler/PHPConsoleHandler.php | 8 +- src/Monolog/Handler/ProcessHandler.php | 4 +- src/Monolog/Handler/PsrHandler.php | 8 +- src/Monolog/Handler/PushoverHandler.php | 55 +++--- src/Monolog/Handler/RedisHandler.php | 4 +- src/Monolog/Handler/RedisPubSubHandler.php | 6 +- src/Monolog/Handler/RollbarHandler.php | 38 +++-- src/Monolog/Handler/RotatingFileHandler.php | 4 +- src/Monolog/Handler/SamplingHandler.php | 1 - src/Monolog/Handler/SendGridHandler.php | 4 +- src/Monolog/Handler/Slack/SlackRecord.php | 22 +-- src/Monolog/Handler/SlackHandler.php | 4 +- src/Monolog/Handler/SlackWebhookHandler.php | 4 +- src/Monolog/Handler/SocketHandler.php | 4 +- src/Monolog/Handler/SqsHandler.php | 4 +- src/Monolog/Handler/StreamHandler.php | 4 +- src/Monolog/Handler/SyslogHandler.php | 6 +- src/Monolog/Handler/SyslogUdpHandler.php | 6 +- src/Monolog/Handler/TelegramBotHandler.php | 4 +- src/Monolog/Handler/TestHandler.php | 51 ++---- src/Monolog/Handler/ZendMonitorHandler.php | 53 +++--- src/Monolog/Level.php | 127 ++++++++++++++ src/Monolog/LevelName.php | 53 ++++++ src/Monolog/LogRecord.php | 31 ++-- src/Monolog/Logger.php | 122 ++++++-------- src/Monolog/Processor/GitProcessor.php | 14 +- .../Processor/IntrospectionProcessor.php | 15 +- src/Monolog/Processor/MercurialProcessor.php | 16 +- src/Monolog/SignalHandler.php | 13 +- src/Monolog/Test/TestCase.php | 21 +-- tests/Monolog/ErrorHandlerTest.php | 2 +- .../Formatter/ChromePHPFormatterTest.php | 12 +- .../Formatter/ElasticaFormatterTest.php | 4 +- .../Formatter/ElasticsearchFormatterTest.php | 4 +- .../Formatter/FlowdockFormatterTest.php | 6 +- .../Formatter/FluentdFormatterTest.php | 6 +- .../Formatter/GelfMessageFormatterTest.php | 18 +- tests/Monolog/Formatter/JsonFormatterTest.php | 18 +- tests/Monolog/Formatter/LineFormatterTest.php | 30 ++-- .../Formatter/LogstashFormatterTest.php | 19 ++- .../Formatter/MongoDBFormatterTest.php | 21 +-- .../Formatter/NormalizerFormatterTest.php | 27 +-- .../Formatter/WildfireFormatterTest.php | 12 +- tests/Monolog/Handler/AbstractHandlerTest.php | 18 +- .../Handler/AbstractProcessingHandlerTest.php | 16 +- tests/Monolog/Handler/AmqpHandlerTest.php | 6 +- .../Handler/BrowserConsoleHandlerTest.php | 24 +-- tests/Monolog/Handler/BufferHandlerTest.php | 46 ++--- .../Monolog/Handler/ChromePHPHandlerTest.php | 20 +-- tests/Monolog/Handler/CouchDBHandlerTest.php | 4 +- .../Handler/DeduplicationHandlerTest.php | 38 ++--- .../Handler/DoctrineCouchDBHandlerTest.php | 6 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 8 +- .../Handler/ElasticsearchHandlerTest.php | 6 +- tests/Monolog/Handler/ErrorLogHandlerTest.php | 8 +- .../Handler/FallbackGroupHandlerTest.php | 26 +-- tests/Monolog/Handler/FilterHandlerTest.php | 93 ++++++----- .../Handler/FingersCrossedHandlerTest.php | 88 +++++----- tests/Monolog/Handler/FirePHPHandlerTest.php | 14 +- .../Monolog/Handler/FleepHookHandlerTest.php | 6 +- tests/Monolog/Handler/FlowdockHandlerTest.php | 6 +- tests/Monolog/Handler/GelfHandlerTest.php | 8 +- tests/Monolog/Handler/GroupHandlerTest.php | 20 +-- .../Monolog/Handler/InsightOpsHandlerTest.php | 6 +- .../Monolog/Handler/LogEntriesHandlerTest.php | 6 +- tests/Monolog/Handler/LogmaticHandlerTest.php | 6 +- tests/Monolog/Handler/MailHandlerTest.php | 10 +- .../Handler/NativeMailerHandlerTest.php | 6 +- tests/Monolog/Handler/NewRelicHandlerTest.php | 42 ++--- tests/Monolog/Handler/NoopHandlerTest.php | 12 +- tests/Monolog/Handler/NullHandlerTest.php | 6 +- tests/Monolog/Handler/OverflowHandlerTest.php | 40 ++--- .../Monolog/Handler/PHPConsoleHandlerTest.php | 3 +- tests/Monolog/Handler/ProcessHandlerTest.php | 20 +-- tests/Monolog/Handler/PsrHandlerTest.php | 29 ++-- tests/Monolog/Handler/PushoverHandlerTest.php | 22 +-- tests/Monolog/Handler/RedisHandlerTest.php | 14 +- .../Handler/RedisPubSubHandlerTest.php | 6 +- tests/Monolog/Handler/RollbarHandlerTest.php | 8 +- .../Monolog/Handler/Slack/SlackRecordTest.php | 61 ++++--- tests/Monolog/Handler/SlackHandlerTest.php | 32 ++-- .../Handler/SlackWebhookHandlerTest.php | 9 +- tests/Monolog/Handler/SocketHandlerTest.php | 4 +- tests/Monolog/Handler/StreamHandlerTest.php | 16 +- tests/Monolog/Handler/SyslogHandlerTest.php | 4 +- .../Monolog/Handler/SyslogUdpHandlerTest.php | 3 +- .../Handler/TelegramBotHandlerTest.php | 4 +- tests/Monolog/Handler/TestHandlerTest.php | 24 +-- .../Handler/WhatFailureGroupHandlerTest.php | 22 +-- .../Handler/ZendMonitorHandlerTest.php | 8 +- tests/Monolog/LoggerTest.php | 157 ++++++++---------- .../Processor/IntrospectionProcessorTest.php | 14 +- 138 files changed, 1295 insertions(+), 1214 deletions(-) rename .php_cs => .php-cs-fixer.php (85%) create mode 100644 src/Monolog/Level.php create mode 100644 src/Monolog/LevelName.php diff --git a/.gitignore b/.gitignore index a3ec4bab3..9418cccf3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ composer.phar phpunit.xml composer.lock .DS_Store -.php_cs.cache +.php-cs-fixer.cache .hg .phpunit.result.cache diff --git a/.php_cs b/.php-cs-fixer.php similarity index 85% rename from .php_cs rename to .php-cs-fixer.php index 6fc3ca2ea..2638adc7a 100644 --- a/.php_cs +++ b/.php-cs-fixer.php @@ -17,10 +17,8 @@ ->in(__DIR__.'/tests') ; -return PhpCsFixer\Config::create() - ->setUsingCache(true) - ->setRiskyAllowed(true) - ->setRules(array( +$config = new PhpCsFixer\Config(); +return $config->setRules(array( '@PSR2' => true, // some rules disabled as long as 1.x branch is maintained 'binary_operator_spaces' => array( @@ -30,11 +28,11 @@ 'cast_spaces' => ['space' => 'single'], 'header_comment' => ['header' => $header], 'include' => true, - 'class_attributes_separation' => ['elements' => ['method']], + 'class_attributes_separation' => array('elements' => array('method' => 'one', 'trait_import' => 'none')), 'no_blank_lines_after_class_opening' => true, 'no_blank_lines_after_phpdoc' => true, 'no_empty_statement' => true, - 'no_extra_consecutive_blank_lines' => true, + 'no_extra_blank_lines' => true, 'no_leading_import_slash' => true, 'no_leading_namespace_whitespace' => true, 'no_trailing_comma_in_singleline_array' => true, @@ -49,13 +47,15 @@ //'phpdoc_scalar' => true, 'phpdoc_trim' => true, //'phpdoc_types' => true, - 'psr0' => true, + 'psr_autoloading' => ['dir' => 'src'], //'array_syntax' => array('syntax' => 'short'), 'declare_strict_types' => true, 'single_blank_line_before_namespace' => true, 'standardize_not_equals' => true, 'ternary_operator_spaces' => true, - 'trailing_comma_in_multiline_array' => true, + 'trailing_comma_in_multiline' => true, )) + ->setUsingCache(true) + ->setRiskyAllowed(true) ->setFinder($finder) ; diff --git a/README.md b/README.md index bfcae0c00..8a431d7e3 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ use Monolog\Handler\StreamHandler; // create a log channel $log = new Logger('name'); -$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); +$log->pushHandler(new StreamHandler('path/to/your.log', Level::Warning)); // add records to the log $log->warning('Foo'); @@ -50,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. diff --git a/doc/01-usage.md b/doc/01-usage.md index 89e0fe7fa..54d7b36c9 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -90,7 +90,7 @@ use Monolog\Handler\FirePHPHandler; // Create the logger $logger = new Logger('my_logger'); // Now add some handlers -$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG)); +$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Level::Debug)); $logger->pushHandler(new FirePHPHandler()); // You can now use your logger @@ -170,7 +170,7 @@ use Monolog\Handler\StreamHandler; use Monolog\Handler\FirePHPHandler; // Create some handlers -$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG); +$stream = new StreamHandler(__DIR__.'/my_app.log', Level::Debug); $firephp = new FirePHPHandler(); // Create the main logger of the app @@ -205,7 +205,7 @@ You can choose between predefined formatter classes or write your own (e.g. a mu > A very useful formatter to look at, is the `LineFormatter`. > > This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. -> +> > It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record->context["foo"] and $record->extra["foo"] will be rendered as part of th final result. In the following example, we demonstrate how to: @@ -229,7 +229,7 @@ $output = "%datetime% > %level_name% > %message% %context% %extra%\n"; $formatter = new LineFormatter($output, $dateFormat); // Create a handler -$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG); +$stream = new StreamHandler(__DIR__.'/my_app.log', Level::Debug); $stream->setFormatter($formatter); // bind it to a logger object diff --git a/doc/04-extending.md b/doc/04-extending.md index 0a2ad3386..49cded91b 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -30,7 +30,7 @@ class PDOHandler extends AbstractProcessingHandler private $pdo; private $statement; - public function __construct(PDO $pdo, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(PDO $pdo, $level = Level::Debug, bool $bubble = true) { $this->pdo = $pdo; parent::__construct($level, $bubble); diff --git a/doc/sockets.md b/doc/sockets.md index c1190c235..d02f722de 100644 --- a/doc/sockets.md +++ b/doc/sockets.md @@ -26,7 +26,7 @@ $handler = new SocketHandler('unix:///var/log/httpd_app_log.socket'); $handler->setPersistent(true); // Now add the handler -$logger->pushHandler($handler, Logger::DEBUG); +$logger->pushHandler($handler, Level::Debug); // You can now use your logger $logger->info('My logger is now ready'); @@ -36,4 +36,3 @@ $logger->info('My logger is now ready'); In this example, using syslog-ng, you should see the log on the log server: cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] [] - diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index e855d64ac..0551e1a29 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use Monolog\Level; use Monolog\Logger; use Monolog\LogRecord; @@ -24,18 +25,21 @@ class ChromePHPFormatter implements FormatterInterface /** * Translates Monolog log levels to Wildfire levels. * - * @var array + * @return 'log'|'info'|'warn'|'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', - ]; + 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} @@ -64,7 +68,7 @@ public function format(LogRecord $record) $record->channel, $message, $backtrace, - $this->logLevels[$record->level], + $this->toWildfireLevel($record->level), ]; } diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 6518976e4..83a73c815 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -45,7 +45,7 @@ public function format(LogRecord $record): array { $tags = [ '#logs', - '#' . strtolower($record->levelName), + '#' . strtolower($record->levelName->value), '#' . $record->channel, ]; @@ -56,7 +56,7 @@ public function format(LogRecord $record): array $subject = sprintf( 'in %s: %s - %s', $this->source, - $record->levelName, + $record->levelName->value, $this->getShortMessage($record->message) ); diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index 31d4d5e2e..ce596df64 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -60,7 +60,7 @@ public function format(LogRecord $record): string { $tag = $record->channel; if ($this->levelTag) { - $tag .= '.' . strtolower($record->levelName); + $tag .= '.' . strtolower($record->levelName->value); } $message = [ @@ -70,8 +70,8 @@ public function format(LogRecord $record): string ]; if (!$this->levelTag) { - $message['level'] = $record->level; - $message['level_name'] = $record->levelName; + $message['level'] = $record->level->value; + $message['level_name'] = $record->levelName->value; } return Utils::jsonEncode([$tag, $record->datetime->getTimestamp(), $message]); diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index bf24b372c..5d2d9de89 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use Monolog\Level; use Monolog\Logger; use Gelf\Message; use Monolog\Utils; @@ -21,8 +22,6 @@ * @see http://docs.graylog.org/en/latest/pages/gelf.html * * @author Matt Lehner - * - * @phpstan-import-type Level from \Monolog\Logger */ class GelfMessageFormatter extends NormalizerFormatter { @@ -50,21 +49,20 @@ class GelfMessageFormatter extends NormalizerFormatter /** * Translates Monolog log levels to Graylog2 log priorities. - * - * @var array - * - * @phpstan-var array */ - 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, - ]; + 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, + }; + } public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null) { @@ -101,7 +99,7 @@ public function format(LogRecord $record): Message ->setTimestamp($record->datetime) ->setShortMessage((string) $record->message) ->setHost($this->systemName) - ->setLevel($this->logLevels[$record->level]); + ->setLevel($this->getGraylog2Priority($record->level)); // message length + system name length + 200 for padding / metadata $len = 200 + strlen((string) $record->message) + strlen($this->systemName); diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index d534755e2..2841a38ec 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use Monolog\Level; use Monolog\Logger; use Monolog\Utils; use Monolog\LogRecord; @@ -26,19 +27,20 @@ class HtmlFormatter extends NormalizerFormatter { /** * Translates Monolog log levels to html color priorities. - * - * @var array */ - 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', - ]; + 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', + }; + } /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format @@ -69,14 +71,13 @@ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): * Create a HTML h1 tag * * @param string $title Text to be in the h1 - * @param int $level Error level * @return string */ - protected function addTitle(string $title, int $level): string + protected function addTitle(string $title, Level $level): string { $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8'); - return '

'.$title.'

'; + return '

'.$title.'

'; } /** @@ -86,7 +87,7 @@ protected function addTitle(string $title, int $level): string */ public function format(LogRecord $record): string { - $output = $this->addTitle($record->levelName, $record->level); + $output = $this->addTitle($record->levelName->value, $record->level); $output .= ''; $output .= $this->addRow('Message', (string) $record->message); diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 0d7f23f09..7badab35a 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use Monolog\Level; use Monolog\Logger; use Monolog\LogRecord; @@ -20,27 +21,9 @@ * @author Eric Clemmons (@ericclemmons) * @author Christophe Coevoet * @author Kirill chEbba Chebunin - * - * @phpstan-import-type Level from \Monolog\Logger */ class WildfireFormatter extends NormalizerFormatter { - /** - * Translates Monolog log levels to Wildfire levels. - * - * @var array - */ - 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 */ @@ -52,6 +35,25 @@ public function __construct(?string $dateFormat = null) $this->removeJsonEncodeOption(JSON_UNESCAPED_UNICODE); } + /** + * Translates Monolog log levels to Wildfire levels. + * + * @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} * @@ -89,7 +91,7 @@ public function format(LogRecord $record): string $label = $record->channel .': '. $record->message; $message = $message['context']['table']; } else { - $type = $this->logLevels[$record->level]; + $type = $this->toWildfireLevel($record->level); $label = $record->channel; } diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 51f3db539..8d2486939 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Psr\Log\LogLevel; @@ -20,27 +22,20 @@ * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ abstract class AbstractHandler extends Handler implements ResettableInterface { - /** - * @var int - * @phpstan-var Level - */ - protected $level = Logger::DEBUG; + protected Level $level = Level::Debug; /** @var bool */ protected $bubble = true; /** - * @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 + * @param int|string|Level|LevelName|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 * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG, bool $bubble = true) + public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $this->setLevel($level); $this->bubble = $bubble; @@ -51,7 +46,7 @@ public function __construct($level = Logger::DEBUG, bool $bubble = true) */ public function isHandling(LogRecord $record): bool { - return $record->level >= $this->level; + return $record->level->value >= $this->level->value; } /** @@ -59,8 +54,10 @@ public function isHandling(LogRecord $record): bool * * @param Level|LevelName|LogLevel::* $level Level or level name * @return self + * + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function setLevel($level): self + public function setLevel(int|string|Level|LevelName $level): self { $this->level = Logger::toMonologLevel($level); @@ -69,12 +66,8 @@ public function setLevel($level): self /** * Gets minimum logging level at which this handler will be triggered. - * - * @return int - * - * @phpstan-return Level */ - public function getLevel(): int + public function getLevel(): Level { return $this->level; } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 253200533..56a83cc16 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -20,9 +20,6 @@ * * @author Jordi Boggiano * @author Christophe Coevoet - * - * @phpstan-import-type LevelName from \Monolog\Logger - * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 5e5ad1c1f..0cba315d8 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -11,14 +11,12 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; /** * Common syslog functionality - * - * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractSyslogHandler extends AbstractProcessingHandler { @@ -27,54 +25,55 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * Translates Monolog log levels to syslog log priorities. - * @var array - * @phpstan-var array */ - 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, - ]; + protected function toSyslogPriority(Level $level): int + { + return match ($level) { + Level::Debug => \LOG_DEBUG, + Level::Info => \LOG_INFO, + Level::Notice => \LOG_NOTICE, + Level::Warning => \LOG_WARNING, + Level::Error => \LOG_ERR, + Level::Critical => \LOG_CRIT, + Level::Alert => \LOG_ALERT, + Level::Emergency => \LOG_EMERG, + }; + } /** * List of valid log facility names. * @var array */ 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, + '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($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true) + public function __construct($facility = \LOG_USER, $level = Level::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 diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 09c5b3d8a..3500732a2 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use PhpAmqpLib\Message\AMQPMessage; @@ -35,7 +35,7 @@ class AmqpHandler extends AbstractProcessingHandler * @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) + public function __construct($exchange, ?string $exchangeName = null, $level = Level::Debug, bool $bubble = true) { if ($exchange instanceof AMQPChannel) { $this->exchangeName = (string) $exchangeName; @@ -110,7 +110,7 @@ public function handleBatch(array $records): void */ protected function getRoutingKey(LogRecord $record): string { - $routingKey = sprintf('%s.%s', $record->levelName, $record->channel); + $routingKey = sprintf('%s.%s', $record->levelName->value, $record->channel); return strtolower($routingKey); } diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 8edf6965f..26b3e7c1d 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -11,7 +11,8 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LevelName; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -46,7 +47,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa * @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, $level = Logger::DEBUG, bool $bubble = true, bool $flushOnOverflow = false) + public function __construct(HandlerInterface $handler, int $bufferLimit = 0, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, bool $flushOnOverflow = false) { parent::__construct($level, $bubble); $this->handler = $handler; @@ -59,7 +60,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $le */ public function handle(LogRecord $record): bool { - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { return false; } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 345ba90cf..b08f004c2 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; use Monolog\DateTimeImmutable; @@ -66,7 +66,7 @@ class ChromePHPHandler extends AbstractProcessingHandler /** @var bool */ protected static $sendHeaders = true; - public function __construct($level = Logger::DEBUG, bool $bubble = true) + public function __construct($level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); if (!function_exists('json_encode')) { @@ -155,7 +155,7 @@ protected function send(): void $record = new LogRecord( message: 'Incomplete logs, chrome header size limit reached', - level: Logger::WARNING, + level: Level::Warning, channel: 'monolog', datetime: new DateTimeImmutable(true), ); diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index abdce0b51..0369ee89c 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -29,7 +29,7 @@ class CouchDBHandler extends AbstractProcessingHandler /** * @param mixed[] $options */ - public function __construct(array $options = [], $level = Logger::DEBUG, bool $bubble = true) + public function __construct(array $options = [], $level = Level::Debug, bool $bubble = true) { $this->options = array_merge([ 'host' => 'localhost', diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 40a16f5cf..d013671dd 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -43,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, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $url, $level = Level::Debug, bool $bubble = true) { $urlInfo = parse_url($url); diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index f9d80f2d2..f1f01e3b4 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -34,8 +36,6 @@ * same way. * * @author Jordi Boggiano - * @phpstan-import-type LevelName from \Monolog\Logger - * @phpstan-import-type Level from \Monolog\Logger */ class DeduplicationHandler extends BufferHandler { @@ -62,15 +62,15 @@ class DeduplicationHandler extends BufferHandler /** * @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|string|Level|LevelName|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 * - * @phpstan-param Level|LevelName|LogLevel::* $deduplicationLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $deduplicationLevel */ - public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true) + public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, int|string|Level|LevelName $deduplicationLevel = Level::Error, int $time = 60, bool $bubble = true) { - parent::__construct($handler, 0, Logger::DEBUG, $bubble, false); + parent::__construct($handler, 0, Level::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); @@ -86,7 +86,7 @@ public function flush(): void $passthru = null; foreach ($this->buffer as $record) { - if ($record->level >= $this->deduplicationLevel) { + if ($record->level->value >= $this->deduplicationLevel->value) { $passthru = $passthru || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); @@ -124,7 +124,7 @@ private function isDuplicate(LogRecord $record): bool for ($i = count($store) - 1; $i >= 0; $i--) { list($timestamp, $level, $message) = explode(':', $store[$i], 3); - if ($level === $record->levelName && $message === $expectedMessage && $timestamp > $timestampValidity) { + if ($level === $record->levelName->value && $message === $expectedMessage && $timestamp > $timestampValidity) { return true; } @@ -174,6 +174,6 @@ private function collectLogs(): void private function appendRecord(LogRecord $record): void { - file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->levelName . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); + file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->levelName->value . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); } } diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index 9b3426f81..0ce3ae9f4 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; use Doctrine\CouchDB\CouchDBClient; @@ -27,7 +27,7 @@ class DoctrineCouchDBHandler extends AbstractProcessingHandler /** @var CouchDBClient */ private $client; - public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(CouchDBClient $client, $level = Level::Debug, bool $bubble = true) { $this->client = $client; parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 175ab71b7..c9c469f0d 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -16,7 +16,7 @@ use Monolog\Formatter\FormatterInterface; use Aws\DynamoDb\Marshaler; use Monolog\Formatter\ScalarFormatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -44,7 +44,7 @@ class DynamoDbHandler extends AbstractProcessingHandler */ protected $marshaler; - public function __construct(DynamoDbClient $client, string $table, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(DynamoDbClient $client, string $table, $level = Level::Debug, bool $bubble = true) { $this->marshaler = new Marshaler; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 838d9d2bb..29dc74b1b 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -14,7 +14,7 @@ use Elastica\Document; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\ElasticaFormatter; -use Monolog\Logger; +use Monolog\Level; use Elastica\Client; use Elastica\Exception\ExceptionInterface; use Monolog\LogRecord; @@ -51,7 +51,7 @@ class ElasticaHandler extends AbstractProcessingHandler * @param Client $client Elastica Client object * @param mixed[] $options Handler configuration */ - public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 0694bcb08..a669dde70 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -13,7 +13,7 @@ use Throwable; use RuntimeException; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\ElasticsearchFormatter; use InvalidArgumentException; @@ -58,7 +58,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler * @param Client $client Elasticsearch Client object * @param mixed[] $options Handler configuration */ - public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index c0f622980..a80b63adf 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -36,7 +36,7 @@ class ErrorLogHandler extends AbstractProcessingHandler * @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, $level = Logger::DEBUG, bool $bubble = true, bool $expandNewlines = false) + public function __construct(int $messageType = self::OPERATING_SYSTEM, $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index d6703fe16..b5dec9380 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; @@ -24,8 +26,6 @@ * * @author Hennadiy Verkh * @author Jordi Boggiano - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class FilterHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { @@ -42,10 +42,10 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * Minimum level for logs that are passed to handler * - * @var int[] - * @phpstan-var array + * @var bool[] Map of Level value => true + * @phpstan-var array, true> */ - protected $acceptedLevels; + protected array $acceptedLevels; /** * Whether the messages that are handled can bubble up the stack or not @@ -58,14 +58,14 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @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 int|string|Level|LevelName|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided + * @param int|string|Level|LevelName|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 * - * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList - * @phpstan-param Level|LevelName|LogLevel::* $maxLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel */ - public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) + public function __construct($handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency, bool $bubble = true) { $this->handler = $handler; $this->bubble = $bubble; @@ -77,32 +77,33 @@ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel } /** - * @phpstan-return array + * @phpstan-return list List of levels */ public function getAcceptedLevels(): array { - return array_flip($this->acceptedLevels); + return array_map(fn(int $level) => Level::from($level), array_keys($this->acceptedLevels)); } /** - * @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 + * @param int|string|Level|LevelName|LogLevel::*|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided + * @param int|string|Level|LevelName|LogLevel::* $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array * - * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList - * @phpstan-param Level|LevelName|LogLevel::* $maxLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel */ - public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self + public function setAcceptedLevels(int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency): self { if (is_array($minLevelOrList)) { - $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList); + $acceptedLevels = array_map(Logger::toMonologLevel(...), $minLevelOrList); } else { $minLevelOrList = Logger::toMonologLevel($minLevelOrList); $maxLevel = Logger::toMonologLevel($maxLevel); - $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) { - return $level >= $minLevelOrList && $level <= $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; } - $this->acceptedLevels = array_flip($acceptedLevels); return $this; } @@ -112,7 +113,7 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L */ public function isHandling(LogRecord $record): bool { - return isset($this->acceptedLevels[$record->level]); + return isset($this->acceptedLevels[$record->level->value]); } /** diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index ca34b3b78..4da75dff7 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -11,6 +11,8 @@ namespace Monolog\Handler\FingersCrossed; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -24,50 +26,45 @@ * * * $activationStrategy = new ChannelLevelActivationStrategy( - * Logger::CRITICAL, + * Level::Critical, * array( - * 'request' => Logger::ALERT, - * 'sensitive' => Logger::ERROR, + * 'request' => Level::Alert, + * 'sensitive' => Level::Error, * ) * ); * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy); * * * @author Mike Meessen - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { - /** - * @var Level - */ - private $defaultActionLevel; + private Level $defaultActionLevel; /** * @var array */ - private $channelToActionLevel; + private array $channelToActionLevel; /** - * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $channelToActionLevel An array that maps channel names to action levels. + * @param int|string|Level|LevelName|LogLevel::* $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $channelToActionLevel An array that maps channel names to action levels. * - * @phpstan-param array $channelToActionLevel - * @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $defaultActionLevel + * @phpstan-param array|value-of|Level|LevelName|LogLevel::*> $channelToActionLevel */ - public function __construct($defaultActionLevel, array $channelToActionLevel = []) + public function __construct(int|string|Level|LevelName $defaultActionLevel, array $channelToActionLevel = []) { $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel); - $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); + $this->channelToActionLevel = array_map(Logger::toMonologLevel(...), $channelToActionLevel); } public function isHandlerActivated(LogRecord $record): bool { if (isset($this->channelToActionLevel[$record->channel])) { - return $record->level >= $this->channelToActionLevel[$record->channel]; + return $record->level->value >= $this->channelToActionLevel[$record->channel]->value; } - return $record->level >= $this->defaultActionLevel; + return $record->level->value >= $this->defaultActionLevel->value; } } diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index ba98f5052..2b4e9ec71 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -11,37 +11,33 @@ namespace Monolog\Handler\FingersCrossed; +use Monolog\Level; +use Monolog\LevelName; +use Monolog\LogRecord; use Monolog\Logger; use Psr\Log\LogLevel; -use Monolog\LogRecord; /** * Error level based activation strategy. * * @author Johannes M. Schmitt - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { - /** - * @var Level - */ - private $actionLevel; + private Level $actionLevel; /** - * @param int|string $actionLevel Level or name or value + * @param int|string|Level|LevelName $actionLevel Level or name or value * - * @phpstan-param Level|LevelName|LogLevel::* $actionLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $actionLevel */ - public function __construct($actionLevel) + public function __construct(int|string|Level|LevelName $actionLevel) { $this->actionLevel = Logger::toMonologLevel($actionLevel); } public function isHandlerActivated(LogRecord $record): bool { - return $record->level >= $this->actionLevel; + return $record->level->value >= $this->actionLevel->value; } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 872b9a18e..fab57656c 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -13,6 +13,8 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; @@ -34,8 +36,6 @@ * Monolog\Handler\FingersCrossed\ namespace. * * @author Jordi Boggiano - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { @@ -56,11 +56,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa protected $buffer = []; /** @var bool */ protected $stopBuffering; - /** - * @var ?int - * @phpstan-var ?Level - */ - protected $passthruLevel; + protected Level|null $passthruLevel = null; /** @var bool */ protected $bubble; @@ -68,19 +64,19 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @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|string|Level|LevelName|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 $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * @param int|string|Level|LevelName|LogLevel::* $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * - * @phpstan-param Level|LevelName|LogLevel::* $passthruLevel - * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $passthruLevel */ - public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null) + public function __construct($handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName $passthruLevel = null) { if (null === $activationStrategy) { - $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); + $activationStrategy = new ErrorLevelActivationStrategy(Level::Warning); } // convert simple int activationStrategy to an object diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 82614cb8b..9f84c5bb2 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -46,7 +46,7 @@ class FleepHookHandler extends SocketHandler */ public function __construct( string $token, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, bool $persistent = false, float $timeout = 0.0, diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index f15857ed6..dd3e61325 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\Formatter\FlowdockFormatter; use Monolog\Formatter\FormatterInterface; @@ -40,7 +40,7 @@ class FlowdockHandler extends SocketHandler */ public function __construct( string $apiToken, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, bool $persistent = false, float $timeout = 0.0, diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index b29049c41..1b53dbdad 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Gelf\PublisherInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\GelfMessageFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -33,7 +33,7 @@ class GelfHandler extends AbstractProcessingHandler /** * @param PublisherInterface $publisher a gelf publisher object */ - public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(PublisherInterface $publisher, $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index c63ecbbf5..53bf28bf2 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -17,8 +17,6 @@ * Interface that all Monolog Handlers must implement * * @author Jordi Boggiano - * - * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface { diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 4eaa1c951..da50bdd5e 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -37,7 +37,7 @@ class IFTTTHandler extends AbstractProcessingHandler * @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, $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $eventName, string $secretKey, $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the IFTTTHandler'); diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index 0223d5bb4..f66321879 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -38,7 +38,7 @@ public function __construct( string $token, string $region = 'us', bool $useSSL = true, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, bool $persistent = false, float $timeout = 0.0, diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 8fe5d869a..ffa2b0a94 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -34,7 +34,7 @@ class LogEntriesHandler extends SocketHandler public function __construct( string $token, bool $useSSL = true, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, string $host = 'data.logentries.com', bool $persistent = false, diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index ef74ee16c..07cad3914 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; use function array_key_exists; @@ -49,7 +49,7 @@ class LogglyHandler extends AbstractProcessingHandler * * @throws MissingExtensionException If the curl extension is missing */ - public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(string $token, $level = Level::Debug, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler'); diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index b2799c2d4..b82bfbf19 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogmaticFormatter; use Monolog\LogRecord; @@ -49,7 +49,7 @@ public function __construct( string $hostname = '', string $appname = '', bool $useSSL = true, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, bool $persistent = false, float $timeout = 0.0, diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index bfbe98fef..decd260cc 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -30,7 +30,7 @@ public function handleBatch(array $records): void $messages = []; foreach ($records as $record) { - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { continue; } @@ -68,7 +68,7 @@ protected function getHighestRecord(array $records): LogRecord { $highestRecord = null; foreach ($records as $record) { - if ($highestRecord === null || $highestRecord['level'] < $record->level) { + if ($highestRecord === null || $record->level->isHigherThan($highestRecord->level)) { $highestRecord = $record; } } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 9fe105474..07f85bbc4 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Swift; use Swift_Message; @@ -33,7 +33,7 @@ class MandrillHandler extends MailHandler * @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, $message, $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $apiKey, $message, $level = Level::Error, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 50aaa1e68..d8248f999 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -14,7 +14,7 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Driver\Manager; use MongoDB\Client; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\MongoDBFormatter; use Monolog\LogRecord; @@ -47,7 +47,7 @@ class MongoDBHandler extends AbstractProcessingHandler * @param string $database Database name * @param string $collection Collection name */ - public function __construct($mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true) + public function __construct($mongodb, string $database, string $collection, $level = Level::Debug, bool $bubble = true) { if (!($mongodb instanceof Client || $mongodb instanceof Manager)) { throw new \InvalidArgumentException('MongoDB\Client or MongoDB\Driver\Manager instance required'); diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 0c0a3bdb1..6aad468ae 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; /** @@ -70,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($to, string $subject, string $from, $level = Logger::ERROR, bool $bubble = true, int $maxColumnWidth = 70) + public function __construct($to, string $subject, string $from, $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70) { parent::__construct($level, $bubble); $this->to = (array) $to; diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 113aaa49e..3b3ae7588 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -58,7 +58,7 @@ class NewRelicHandler extends AbstractProcessingHandler * @param string|null $transactionName */ public function __construct( - $level = Logger::ERROR, + $level = Level::Error, bool $bubble = true, ?string $appName = null, bool $explodeArrays = false, diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 99c1e6596..923d59283 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -11,8 +11,10 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LevelName; use Psr\Log\LogLevel; +use Monolog\Logger; use Monolog\LogRecord; /** @@ -22,23 +24,17 @@ * to put on top of an existing stack to override it temporarily. * * @author Jordi Boggiano - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class NullHandler extends Handler { - /** - * @var int - */ - private $level; + private Level $level; /** - * @param string|int $level The minimum logging level at which this handler will be triggered + * @param string|int|Level|LevelName $level The minimum logging level at which this handler will be triggered * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG) + public function __construct(string|int|Level|LevelName $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } @@ -48,7 +44,7 @@ public function __construct($level = Logger::DEBUG) */ public function isHandling(LogRecord $record): bool { - return $record->level >= $this->level; + return $record->level->value >= $this->level->value; } /** @@ -56,6 +52,6 @@ public function isHandling(LogRecord $record): bool */ public function handle(LogRecord $record): bool { - return $record->level >= $this->level; + return $record->level->value >= $this->level->value; } } diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index af33424fe..d1f42781e 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -28,7 +28,7 @@ * $handler = new SomeHandler(...) * * // Pass all warnings to the handler when more than 10 & all error messages when more then 5 - * $overflow = new OverflowHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); + * $overflow = new OverflowHandler($handler, [Level::Warning->value => 10, Level::Error->value => 5]); * * $log->pushHandler($overflow); *``` @@ -40,17 +40,8 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter /** @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, - ]; + /** @var array */ + private $thresholdMap = []; /** * Buffer of all messages passed to the handler before the threshold was reached @@ -61,12 +52,12 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter /** * @param HandlerInterface $handler - * @param int[] $thresholdMap Dictionary of logger level => threshold + * @param array $thresholdMap Dictionary of log level value => threshold */ public function __construct( HandlerInterface $handler, array $thresholdMap = [], - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true ) { $this->handler = $handler; @@ -90,11 +81,11 @@ public function __construct( */ public function handle(LogRecord $record): bool { - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { return false; } - $level = $record->level; + $level = $record->level->value; if (!isset($this->thresholdMap[$level])) { $this->thresholdMap[$level] = 0; diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index d4aeb9e96..ff6c707f3 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use PhpConsole\Connector; use PhpConsole\Handler as VendorPhpConsoleHandler; @@ -73,7 +73,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) * @throws \RuntimeException */ - public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(array $options = [], ?Connector $connector = null, $level = Level::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'); @@ -180,7 +180,7 @@ public function handle(LogRecord $record): bool */ protected function write(LogRecord $record): void { - if ($record->level < Logger::NOTICE) { + if ($record->level->isLowerThan(Level::Notice)) { $this->handleDebugRecord($record); } elseif (isset($record->context['exception']) && $record->context['exception'] instanceof \Throwable) { $this->handleExceptionRecord($record); @@ -239,7 +239,7 @@ private function getRecordTags(LogRecord $record): array } } - return [$tags ?: strtolower($record->levelName), $filteredContext]; + return [$tags ?: strtolower($record->levelName->value), $filteredContext]; } /** diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index d2c3cea90..c43b88631 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -64,7 +64,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, $level = Logger::DEBUG, bool $bubble = true, ?string $cwd = null) + public function __construct(string $command, $level = Level::Debug, bool $bubble = true, ?string $cwd = null) { if ($command === '') { throw new \InvalidArgumentException('The command argument must be a non-empty string.'); diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 50fee1725..30369e27a 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Psr\Log\LoggerInterface; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -42,7 +42,7 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied */ - public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(LoggerInterface $logger, $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); @@ -60,9 +60,9 @@ public function handle(LogRecord $record): bool if ($this->formatter) { $formatted = $this->formatter->format($record); - $this->logger->log(strtolower($record->levelName), (string) $formatted, $record->context); + $this->logger->log(strtolower($record->levelName->value), (string) $formatted, $record->context); } else { - $this->logger->log(strtolower($record->levelName), $record->message, $record->context); + $this->logger->log(strtolower($record->levelName->value), $record->message, $record->context); } return false === $this->bubble; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 57bdff8df..0e3db9dce 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Monolog\Utils; use Psr\Log\LogLevel; @@ -21,9 +23,6 @@ * * @author Sebastian Göttschkes * @see https://www.pushover.net/api - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class PushoverHandler extends SocketHandler { @@ -40,10 +39,8 @@ class PushoverHandler extends SocketHandler /** @var int */ private $expire; - /** @var int */ - private $highPriorityLevel; - /** @var int */ - private $emergencyLevel; + private Level $highPriorityLevel; + private Level $emergencyLevel; /** @var bool */ private $useFormattedMessage = false; @@ -85,28 +82,30 @@ class PushoverHandler extends SocketHandler * @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). * + * @param int|string|Level|LevelName|LogLevel::* $highPriorityLevel The minimum logging level at which this handler will start + * sending "high priority" requests to the Pushover API + * @param int|string|Level|LevelName|LogLevel::* $emergencyLevel The minimum logging level at which this handler will start + * sending "emergency" requests to the Pushover API + * + * * @phpstan-param string|array $users - * @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel - * @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $highPriorityLevel + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $emergencyLevel */ public function __construct( string $token, $users, ?string $title = null, - $level = Logger::CRITICAL, + int|string|Level|LevelName $level = Level::Critical, bool $bubble = true, bool $useSSL = true, - $highPriorityLevel = Logger::CRITICAL, - $emergencyLevel = Logger::EMERGENCY, + int|string|Level|LevelName $highPriorityLevel = Level::Critical, + int|string|Level|LevelName $emergencyLevel = Level::Emergency, int $retry = 30, int $expire = 25200, bool $persistent = false, @@ -161,11 +160,11 @@ private function buildContent(LogRecord $record): string 'timestamp' => $timestamp, ]; - if (isset($record->level) && $record->level >= $this->emergencyLevel) { + if ($record->level->value >= $this->emergencyLevel->value) { $dataArray['priority'] = 2; $dataArray['retry'] = $this->retry; $dataArray['expire'] = $this->expire; - } elseif (isset($record->level) && $record->level >= $this->highPriorityLevel) { + } elseif ($record->level->value >= $this->highPriorityLevel->value) { $dataArray['priority'] = 1; } @@ -208,25 +207,25 @@ protected function write(LogRecord $record): void } /** - * @param int|string $value + * @param int|string|Level|LevelName|LogLevel::* $level * - * @phpstan-param Level|LevelName|LogLevel::* $value + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function setHighPriorityLevel($value): self + public function setHighPriorityLevel(int|string|Level|LevelName $level): self { - $this->highPriorityLevel = Logger::toMonologLevel($value); + $this->highPriorityLevel = Logger::toMonologLevel($level); return $this; } /** - * @param int|string $value + * @param int|string|Level|LevelName|LogLevel::* $level * - * @phpstan-param Level|LevelName|LogLevel::* $value + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function setEmergencyLevel($value): self + public function setEmergencyLevel(int|string|Level|LevelName $level): self { - $this->emergencyLevel = Logger::toMonologLevel($value); + $this->emergencyLevel = Logger::toMonologLevel($level); return $this; } @@ -234,9 +233,9 @@ public function setEmergencyLevel($value): self /** * Use the formatted message? */ - public function useFormattedMessage(bool $value): self + public function useFormattedMessage(bool $useFormattedMessage): self { - $this->useFormattedMessage = $value; + $this->useFormattedMessage = $useFormattedMessage; return $this; } diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 6b652ce57..eecbf837a 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -41,7 +41,7 @@ class RedisHandler extends AbstractProcessingHandler * @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($redis, string $key, $level = Logger::DEBUG, bool $bubble = true, int $capSize = 0) + public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true, int $capSize = 0) { if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { throw new \InvalidArgumentException('Predis\Client or Redis instance required'); diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 0d58ed288..01138cc7c 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -22,7 +22,7 @@ * usage example: * * $log = new Logger('application'); - * $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING); + * $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Level::Warning); * $log->pushHandler($redis); * * @author Gaëtan Faugère @@ -38,7 +38,7 @@ class RedisPubSubHandler extends AbstractProcessingHandler * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The channel key to publish records to */ - public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) + public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true) { if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { throw new \InvalidArgumentException('Predis\Client or Redis instance required'); diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 76b320543..1f082cd61 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -11,9 +11,10 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Rollbar\RollbarLogger; use Throwable; -use Monolog\Logger; use Monolog\LogRecord; /** @@ -39,18 +40,6 @@ class RollbarHandler extends AbstractProcessingHandler */ 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 * @@ -64,13 +53,32 @@ class RollbarHandler extends AbstractProcessingHandler /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token */ - public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true) + public function __construct(RollbarLogger $rollbarLogger, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) { $this->rollbarLogger = $rollbarLogger; parent::__construct($level, $bubble); } + /** + * 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} */ @@ -84,7 +92,7 @@ protected function write(LogRecord $record): void $context = $record->context; $context = array_merge($context, $record->extra, [ - 'level' => $this->levelMap[$record->level], + 'level' => $this->toRollbarLevel($record->level), 'monolog_level' => $record->levelName, 'channel' => $record->channel, 'datetime' => $record->datetime->format('U'), diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 39abfc95e..e7d27aace 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use InvalidArgumentException; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -50,7 +50,7 @@ class RotatingFileHandler extends StreamHandler * @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, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct(string $filename, int $maxFiles = 0, $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 39f1e0d7c..8238de846 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -27,7 +27,6 @@ * * @author Bryan Davis * @author Kunal Mehta - * @phpstan-import-type Level from \Monolog\Logger */ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 1280ee703..50b23e2c7 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; /** * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html @@ -57,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, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) + public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler'); diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 7e9e3233a..0a87babf6 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -11,7 +11,7 @@ namespace Monolog\Handler\Slack; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -145,7 +145,7 @@ public function getSlackData(LogRecord $record): array $attachment = array( 'fallback' => $message, 'text' => $message, - 'color' => $this->getAttachmentColor($recordData['level']), + 'color' => $this->getAttachmentColor($record->level), 'fields' => array(), 'mrkdwn_in' => array('fields'), 'ts' => $recordData['datetime']->getTimestamp(), @@ -201,18 +201,14 @@ public function getSlackData(LogRecord $record): array * Returns a Slack message attachment color associated with * provided level. */ - public function getAttachmentColor(int $level): string + public function getAttachmentColor(Level $level): string { - 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; - } + 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 + }; } /** diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 4f57daee1..fb85cd014 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; use Monolog\LogRecord; @@ -54,7 +54,7 @@ public function __construct( ?string $username = null, bool $useAttachment = true, ?string $iconEmoji = null, - $level = Logger::CRITICAL, + $level = Level::Critical, bool $bubble = true, bool $useShortAttachment = false, bool $includeContextAndExtra = false, diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 269b6995c..c98c1c3d9 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\Handler\Slack\SlackRecord; use Monolog\LogRecord; @@ -55,7 +55,7 @@ public function __construct( ?string $iconEmoji = null, bool $useShortAttachment = false, bool $includeContextAndExtra = false, - $level = Logger::CRITICAL, + $level = Level::Critical, bool $bubble = true, array $excludeFields = array() ) { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 1d8a68f2d..727666c45 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -58,7 +58,7 @@ class SocketHandler extends AbstractProcessingHandler */ public function __construct( string $connectionString, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, bool $persistent = false, float $timeout = 0.0, diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 727c20a8c..fe9e1ecdc 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Aws\Sqs\SqsClient; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -33,7 +33,7 @@ class SqsHandler extends AbstractProcessingHandler /** @var string */ private $queueUrl; - public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Logger::DEBUG, bool $bubble = true) + public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 0053db156..328c4ea65 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -50,7 +50,7 @@ class StreamHandler extends AbstractProcessingHandler * * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct($stream, $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 77ceaa1d0..73d286811 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -40,7 +40,7 @@ class SyslogHandler extends AbstractSyslogHandler * @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, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID) + public function __construct(string $ident, $facility = LOG_USER, $level = Level::Debug, bool $bubble = true, int $logopts = LOG_PID) { parent::__construct($facility, $level, $bubble); @@ -64,6 +64,6 @@ protected function write(LogRecord $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->logLevels[$record->level], (string) $record->formatted); + syslog($this->toSyslogPriority($record->level), (string) $record->formatted); } } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 07feaa567..7fe92b149 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use DateTimeInterface; -use Monolog\Logger; +use Monolog\Level; use Monolog\Handler\SyslogUdp\UdpSocket; use Monolog\Utils; use Monolog\LogRecord; @@ -54,7 +54,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler * * @phpstan-param self::RFC* $rfc */ - public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) + public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Level::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'); @@ -72,7 +72,7 @@ protected function write(LogRecord $record): void { $lines = $this->splitMessageIntoLines($record->formatted); - $header = $this->makeCommonSyslogHeader($this->logLevels[$record->level], $record->datetime); + $header = $this->makeCommonSyslogHeader($this->toSyslogPriority($record->level), $record->datetime); foreach ($lines as $line) { $this->socket->write($line, $header); diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index e2812c997..0d22455c3 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use RuntimeException; -use Monolog\Logger; +use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -105,7 +105,7 @@ class TelegramBotHandler extends AbstractProcessingHandler public function __construct( string $apiKey, string $channel, - $level = Logger::DEBUG, + $level = Level::Debug, bool $bubble = true, string $parseMode = null, bool $disableWebPagePreview = null, diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 2395889e1..531435981 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -11,10 +11,11 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; -use Monolog\DateTimeImmutable; /** * Used for testing purposes. @@ -67,16 +68,13 @@ * @method bool hasNoticeThatPasses($message) * @method bool hasInfoThatPasses($message) * @method bool hasDebugThatPasses($message) - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class TestHandler extends AbstractProcessingHandler { /** @var LogRecord[] */ protected $records = []; - /** @var array */ - protected $recordsByLevel = []; + /** @phpstan-var array, LogRecord[]> */ + protected array $recordsByLevel = []; /** @var bool */ private $skipReset = false; @@ -116,23 +114,21 @@ public function setSkipReset(bool $skipReset) } /** - * @param string|int $level Logging level value or name + * @param int|string|Level|LevelName|LogLevel::* $level Logging level value or name * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function hasRecords($level): bool + public function hasRecords(int|string|Level|LevelName $level): bool { - return isset($this->recordsByLevel[Logger::toMonologLevel($level)]); + return isset($this->recordsByLevel[Logger::toMonologLevel($level)->value]); } /** * @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|int $level Logging level value or name * * @phpstan-param array{message: string, context?: mixed[]}|string $recordAssertions - * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function hasRecord(string|array $recordAssertions, $level): bool + public function hasRecord(string|array $recordAssertions, Level $level): bool { if (is_string($recordAssertions)) { $recordAssertions = ['message' => $recordAssertions]; @@ -150,42 +146,28 @@ public function hasRecord(string|array $recordAssertions, $level): bool }, $level); } - /** - * @param string|int $level Logging level value or name - * - * @phpstan-param Level|LevelName|LogLevel::* $level - */ - public function hasRecordThatContains(string $message, $level): bool + public function hasRecordThatContains(string $message, Level $level): bool { return $this->hasRecordThatPasses(fn (LogRecord $rec) => str_contains($rec->message, $message), $level); } - /** - * @param string|int $level Logging level value or name - * - * @phpstan-param Level|LevelName|LogLevel::* $level - */ - public function hasRecordThatMatches(string $regex, $level): bool + public function hasRecordThatMatches(string $regex, Level $level): bool { return $this->hasRecordThatPasses(fn (LogRecord $rec) => preg_match($regex, $rec->message) > 0, $level); } /** - * @param string|int $level Logging level value or name - * @return bool - * * @phpstan-param callable(LogRecord, int): mixed $predicate - * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function hasRecordThatPasses(callable $predicate, $level) + public function hasRecordThatPasses(callable $predicate, Level $level): bool { $level = Logger::toMonologLevel($level); - if (!isset($this->recordsByLevel[$level])) { + if (!isset($this->recordsByLevel[$level->value])) { return false; } - foreach ($this->recordsByLevel[$level] as $i => $rec) { + foreach ($this->recordsByLevel[$level->value] as $i => $rec) { if ($predicate($rec, $i)) { return true; } @@ -199,7 +181,7 @@ public function hasRecordThatPasses(callable $predicate, $level) */ protected function write(LogRecord $record): void { - $this->recordsByLevel[$record->level][] = $record; + $this->recordsByLevel[$record->level->value][] = $record; $this->records[] = $record; } @@ -212,11 +194,10 @@ 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('Monolog\Logger::' . strtoupper($matches[2])); + $level = constant(Level::class.'::' . $matches[2]); $callback = [$this, $genericMethod]; if (is_callable($callback)) { $args[] = $level; - return call_user_func_array($callback, $args); } } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index b881f4920..32f9c6112 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -13,7 +13,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\NormalizerFormatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; /** @@ -24,47 +24,48 @@ */ class ZendMonitorHandler extends AbstractProcessingHandler { - /** - * Monolog level / ZendMonitor Custom Event priority map - * - * @var array - */ - protected $levelMap = []; - /** * @throws MissingExtensionException */ - public function __construct($level = Logger::DEBUG, bool $bubble = true) + public function __construct($level = Level::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. + */ + 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 { $this->writeZendMonitorCustomEvent( - Logger::getLevelName($record->level), + $record->level->toLevelName()->value, $record->message, $record->formatted, - $this->levelMap[$record->level] + $this->toZendMonitorLevel($record->level) ); } @@ -87,12 +88,4 @@ public function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter(); } - - /** - * @return array - */ - public function getLevelMap(): array - { - return $this->levelMap; - } } diff --git a/src/Monolog/Level.php b/src/Monolog/Level.php new file mode 100644 index 000000000..70c394862 --- /dev/null +++ b/src/Monolog/Level.php @@ -0,0 +1,127 @@ + self::Debug, + LevelName::Info => self::Info, + LevelName::Notice => self::Notice, + LevelName::Warning => self::Warning, + LevelName::Error => self::Error, + LevelName::Critical => self::Critical, + LevelName::Alert => self::Alert, + LevelName::Emergency => self::Emergency, + }; + } + + /** + * 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; + } + + public function toLevelName(): LevelName + { + return LevelName::fromLevel($this); + } + + /** + * @return string + * @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, + }; + } + + public const VALUES = [ + 100, + 200, + 250, + 300, + 400, + 500, + 550, + 600, + ]; +} diff --git a/src/Monolog/LevelName.php b/src/Monolog/LevelName.php new file mode 100644 index 000000000..7d26d9f18 --- /dev/null +++ b/src/Monolog/LevelName.php @@ -0,0 +1,53 @@ + self::Debug, + Level::Info => self::Info, + Level::Notice => self::Notice, + Level::Warning => self::Warning, + Level::Error => self::Error, + Level::Critical => self::Critical, + Level::Alert => self::Alert, + Level::Emergency => self::Emergency, + }; + } + + public function toLevel(): Level + { + return Level::fromLevelName($this); + } + + public const VALUES = [ + 'DEBUG', + 'INFO', + 'NOTICE', + 'WARNING', + 'ERROR', + 'CRITICAL', + 'ALERT', + 'EMERGENCY', + ]; + + public function jsonSerialize(): mixed + { + return $this->value; + } +} diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php index 1e6aa07ae..47fc66c73 100644 --- a/src/Monolog/LogRecord.php +++ b/src/Monolog/LogRecord.php @@ -17,25 +17,21 @@ * Monolog log record * * @author Jordi Boggiano - * @template-implements \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra', int|string|\DateTimeImmutable|array> - * @phpstan-import-type Level from Logger - * @phpstan-import-type LevelName from Logger + * @template-implements ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra', int|string|\DateTimeImmutable|array> */ -class LogRecord implements \ArrayAccess +class LogRecord implements ArrayAccess { private const MODIFIABLE_FIELDS = [ 'extra' => true, 'formatted' => true, ]; - /** @var 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY' */ - public readonly string $levelName; // TODO enum? + public readonly LevelName $levelName; public function __construct( public readonly \DateTimeImmutable $datetime, public readonly string $channel, - /** @var Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY */ - public readonly int $level, // TODO enum? + public readonly Level $level, public readonly string $message, /** @var array */ public readonly array $context = [], @@ -43,7 +39,7 @@ public function __construct( public array $extra = [], public mixed $formatted = null, ) { - $this->levelName = Logger::getLevelName($level); + $this->levelName = LevelName::fromLevel($level); } public function offsetSet(mixed $offset, mixed $value): void @@ -81,8 +77,15 @@ public function offsetUnset(mixed $offset): void public function &offsetGet(mixed $offset): mixed { - if ($offset === 'level_name') { - $offset = 'levelName'; + if ($offset === 'level_name' || $offset === 'level') { + if ($offset === 'level_name') { + $offset = 'levelName'; + } + + // avoid returning readonly props by ref as this is illegal + $copy = $this->{$offset}->value; + + return $copy; } if (isset(self::MODIFIABLE_FIELDS[$offset])) { @@ -96,15 +99,15 @@ public function &offsetGet(mixed $offset): mixed } /** - * @phpstan-return array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} + * @phpstan-return array{message: string, context: mixed[], level: value-of, level_name: value-of, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ public function toArray(): array { return [ 'message' => $this->message, 'context' => $this->context, - 'level' => $this->level, - 'level_name' => $this->levelName, + 'level' => $this->level->value, + 'level_name' => $this->levelName->value, 'channel' => $this->channel, 'datetime' => $this->datetime, 'extra' => $this->extra, diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 882438448..bf985d2c6 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -27,14 +27,13 @@ * and uses them to store records that are added to it. * * @author Jordi Boggiano - * - * @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' */ class Logger implements LoggerInterface, ResettableInterface { /** * Detailed debug information + * + * @deprecated Use \Monolog\Level::Debug */ public const DEBUG = 100; @@ -42,11 +41,15 @@ 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; @@ -55,11 +58,15 @@ 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; @@ -67,6 +74,8 @@ class Logger implements LoggerInterface, ResettableInterface * Critical conditions * * Example: Application component unavailable, unexpected exception. + * + * @deprecated Use \Monolog\Level::Critical */ public const CRITICAL = 500; @@ -75,11 +84,15 @@ 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; @@ -91,25 +104,7 @@ class Logger implements LoggerInterface, ResettableInterface * * @var int */ - public const API = 2; - - /** - * This is a static variable and not a constant to serve as an extension point for custom levels - * - * @var array $levels Logging levels with the levels as key - * - * @phpstan-var array $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', - ]; + public const API = 3; /** * @var string @@ -287,16 +282,16 @@ public function useMicrosecondTimestamps(bool $micro): self * @param mixed[] $context The log context * @return bool Whether the record has been processed * - * @phpstan-param Level $level + * @phpstan-param value-of|Level $level */ - public function addRecord(int $level, string $message, array $context = []): bool + public function addRecord(int|Level $level, string $message, array $context = []): bool { $recordInitialized = count($this->processors) === 0; $record = new LogRecord( message: $message, context: $context, - level: $level, + level: self::toMonologLevel($level), channel: $this->name, datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), extra: [], @@ -381,78 +376,63 @@ public function reset(): void } /** - * Gets all supported logging levels. - * - * @return array Assoc array with human-readable level names => level codes. - * @phpstan-return array - */ - public static function getLevels(): array - { - return array_flip(static::$levels); - } - - /** - * Gets the name of the logging level. + * Converts PSR-3 levels to Monolog ones if necessary * + * @param int|string|Level|LevelName|LogLevel::* $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined * - * @phpstan-param Level $level - * @phpstan-return LevelName + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public static function getLevelName(int $level): string + public static function toMonologLevel(string|int|Level|LevelName $level): Level { - if (!isset(static::$levels[$level])) { - throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + if ($level instanceof Level) { + return $level; } - return static::$levels[$level]; - } + if ($level instanceof LevelName) { + return $level->toLevel(); + } - /** - * Converts PSR-3 levels to Monolog ones if necessary - * - * @param string|int $level Level number (monolog) or name (PSR-3) - * @throws \Psr\Log\InvalidArgumentException If level is not defined - * - * @phpstan-param Level|LevelName|LogLevel::* $level - * @phpstan-return Level - */ - public static function toMonologLevel($level): int - { - if (is_string($level)) { - if (is_numeric($level)) { - return intval($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(', ', LevelName::VALUES + Level::VALUES)); + } + + return $levelEnum; } - // Contains chars of all log levels and avoids using strtoupper() which may have + // Contains first char 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($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); - if (defined(__CLASS__.'::'.$upper)) { - return constant(__CLASS__ . '::' . $upper); + $upper = strtr(substr($level, 0, 1), 'dinweca', 'DINWECA') . strtolower(substr($level, 1)); + if (defined(Level::class.'::'.$upper)) { + return constant(Level::class . '::' . $upper); } - throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', LevelName::VALUES + 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)); + $levelEnum = Level::tryFrom($level); + if ($levelEnum === null) { + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', LevelName::VALUES + Level::VALUES)); } - return $level; + return $levelEnum; } /** * Checks whether the Logger has a handler that listens on the given level * - * @phpstan-param Level $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function isHandling(int $level): bool + public function isHandling(int|string|LevelName|Level $level): bool { $record = new LogRecord( datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), channel: $this->name, message: '', - level: $level, + level: self::toMonologLevel($level), ); foreach ($this->handlers as $handler) { @@ -494,8 +474,8 @@ public function getExceptionHandler(): ?callable */ public function log($level, string|\Stringable $message, array $context = []): void { - if (!is_int($level) && !is_string($level)) { - throw new \InvalidArgumentException('$level is expected to be a string or int'); + if (!is_string($level) && !is_int($level) && !$level instanceof Level) { + throw new \InvalidArgumentException('$level is expected to be a string, int or '.Level::class.' instance'); } $level = static::toMonologLevel($level); diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 920cbc3f4..2cefe4521 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -20,23 +22,19 @@ * * @author Nick Otter * @author Jordi Boggiano - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class GitProcessor implements ProcessorInterface { - /** @var int */ - private $level; + private Level $level; /** @var array{branch: string, commit: string}|array|null */ private static $cache = null; /** - * @param string|int $level The minimum logging level at which this Processor will be triggered + * @param int|string|Level|LevelName|LogLevel::* $level The minimum logging level at which this Processor will be triggered * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG) + public function __construct(int|string|Level|LevelName $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 2cbc83b47..357bd71fe 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -25,13 +27,10 @@ * triggered the FingersCrossedHandler. * * @author Jordi Boggiano - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class IntrospectionProcessor implements ProcessorInterface { - private int $level; + private Level $level; /** @var string[] */ private array $skipClassesPartials; @@ -44,12 +43,12 @@ class IntrospectionProcessor implements ProcessorInterface ]; /** - * @param string|int $level The minimum logging level at which this Processor will be triggered + * @param string|int|Level|LevelName $level The minimum logging level at which this Processor will be triggered * @param string[] $skipClassesPartials * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) + public function __construct(int|string|Level|LevelName $level = Level::Debug, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { $this->level = Logger::toMonologLevel($level); $this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials); @@ -62,7 +61,7 @@ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { return $record; } diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 7fb1340dd..37222a344 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -11,6 +11,8 @@ namespace Monolog\Processor; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -19,23 +21,19 @@ * Injects Hg branch and Hg revision number in all records * * @author Jonathan A. Schweder - * - * @phpstan-import-type LevelName from \Monolog\Logger - * @phpstan-import-type Level from \Monolog\Logger */ class MercurialProcessor implements ProcessorInterface { - /** @var Level */ - private $level; + private Level $level; /** @var array{branch: string, revision: string}|array|null */ private static $cache = null; /** - * @param int|string $level The minimum logging level at which this Processor will be triggered + * @param int|string|Level|LevelName $level The minimum logging level at which this Processor will be triggered * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG) + public function __construct(int|string|Level|LevelName $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } @@ -46,7 +44,7 @@ public function __construct($level = Logger::DEBUG) public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { return $record; } diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index d730eea3a..b9f92abd2 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -19,9 +19,6 @@ * Monolog POSIX signal handler * * @author Robert Gust-Bardon - * - * @phpstan-import-type Level from \Monolog\Logger - * @phpstan-import-type LevelName from \Monolog\Logger */ class SignalHandler { @@ -30,7 +27,7 @@ class SignalHandler /** @var array SIG_DFL, SIG_IGN or previous callable */ private $previousSignalHandler = []; - /** @var array */ + /** @var array */ private $signalLevelMap = []; /** @var array */ private $signalRestartSyscalls = []; @@ -41,21 +38,21 @@ public function __construct(LoggerInterface $logger) } /** - * @param int|string $level Level or level name + * @param int|string|Level|LevelName $level Level or level name * @param bool $callPrevious * @param bool $restartSyscalls * @param bool|null $async * @return $this * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self + public function registerSignalHandler(int $signo, int|string|Level|LevelName $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); + $level = Logger::toMonologLevel($level)->toPsrLogLevel(); if ($callPrevious) { $handler = pcntl_signal_get_handler($signo); diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 839816367..aa7144882 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -11,17 +11,18 @@ namespace Monolog\Test; +use Monolog\Level; +use Monolog\LevelName; 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 - * - * @phpstan-import-type Level from \Monolog\Logger */ class TestCase extends \PHPUnit\Framework\TestCase { @@ -29,14 +30,14 @@ class TestCase extends \PHPUnit\Framework\TestCase * @param array $context * @param array $extra * - * @phpstan-param Level $level + * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ - protected function getRecord(int $level = Logger::WARNING, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord + protected function getRecord(int|string|LevelName|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord { return new LogRecord( message: (string) $message, context: $context, - level: $level, + level: Logger::toMonologLevel($level), channel: $channel, datetime: $datetime, extra: $extra, @@ -49,11 +50,11 @@ protected function getRecord(int $level = Logger::WARNING, string|\Stringable $m protected function getMultipleRecords(): array { return [ - $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'), + $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'), ]; } diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 05123f2af..bc637efdf 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -37,7 +37,7 @@ public function testHandleError() $this->assertTrue(is_callable($prop)); $this->assertSame($prevHandler, $prop); - $resHandler = $errHandler->registerErrorHandler([E_USER_NOTICE => Logger::EMERGENCY], false); + $resHandler = $errHandler->registerErrorHandler([E_USER_NOTICE => LogLevel::EMERGENCY], false); $this->assertSame($errHandler, $resHandler); trigger_error('Foo', E_USER_ERROR); $this->assertCount(1, $handler->getRecords()); diff --git a/tests/Monolog/Formatter/ChromePHPFormatterTest.php b/tests/Monolog/Formatter/ChromePHPFormatterTest.php index cdfcae254..f290ba699 100644 --- a/tests/Monolog/Formatter/ChromePHPFormatterTest.php +++ b/tests/Monolog/Formatter/ChromePHPFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class ChromePHPFormatterTest extends TestCase @@ -23,7 +23,7 @@ public function testDefaultFormat() { $formatter = new ChromePHPFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -55,7 +55,7 @@ public function testFormatWithFileAndLine() { $formatter = new ChromePHPFormatter(); $record = $this->getRecord( - Logger::CRITICAL, + Level::Critical, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -87,7 +87,7 @@ public function testFormatWithoutContext() { $formatter = new ChromePHPFormatter(); $record = $this->getRecord( - Logger::DEBUG, + Level::Debug, 'log', channel: 'meh', datetime: new \DateTimeImmutable("@0"), @@ -114,13 +114,13 @@ public function testBatchFormatThrowException() $formatter = new ChromePHPFormatter(); $records = [ $this->getRecord( - Logger::INFO, + Level::Info, 'log', channel: 'meh', datetime: new \DateTimeImmutable("@0"), ), $this->getRecord( - Logger::WARNING, + Level::Warning, 'log2', channel: 'foo', datetime: new \DateTimeImmutable("@0"), diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index 17d29382d..64b642861 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; use Monolog\Test\TestCase; @@ -33,7 +33,7 @@ public function testFormat() { // test log message $msg = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['foo' => 7, 'bar', 'class' => new \stdClass], diff --git a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php index 2dc89be6c..438bbfd39 100644 --- a/tests/Monolog/Formatter/ElasticsearchFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticsearchFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class ElasticsearchFormatterTest extends TestCase @@ -25,7 +25,7 @@ public function testFormat() { // Test log message $msg = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['foo' => 7, 'bar', 'class' => new \stdClass], diff --git a/tests/Monolog/Formatter/FlowdockFormatterTest.php b/tests/Monolog/Formatter/FlowdockFormatterTest.php index 322e6ed39..1b4e81768 100644 --- a/tests/Monolog/Formatter/FlowdockFormatterTest.php +++ b/tests/Monolog/Formatter/FlowdockFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class FlowdockFormatterTest extends TestCase @@ -44,8 +44,8 @@ public function testFormatBatch() { $formatter = new FlowdockFormatter('test_source', 'source@test.com'); $records = [ - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), + $this->getRecord(Level::Warning), + $this->getRecord(Level::Debug), ]; $formatted = $formatter->formatBatch($records); diff --git a/tests/Monolog/Formatter/FluentdFormatterTest.php b/tests/Monolog/Formatter/FluentdFormatterTest.php index dbebd787c..318a5ca04 100644 --- a/tests/Monolog/Formatter/FluentdFormatterTest.php +++ b/tests/Monolog/Formatter/FluentdFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class FluentdFormatterTest extends TestCase @@ -35,7 +35,7 @@ public function testConstruct() */ public function testFormat() { - $record = $this->getRecord(Logger::WARNING, datetime: new \DateTimeImmutable("@0")); + $record = $this->getRecord(Level::Warning, datetime: new \DateTimeImmutable("@0")); $formatter = new FluentdFormatter(); $this->assertEquals( @@ -49,7 +49,7 @@ public function testFormat() */ public function testFormatWithTag() { - $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable("@0")); + $record = $this->getRecord(Level::Error, datetime: new \DateTimeImmutable("@0")); $formatter = new FluentdFormatter(true); $this->assertEquals( diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index fd1adb7df..b33687a68 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class GelfMessageFormatterTest extends TestCase @@ -30,7 +30,7 @@ public function testDefaultFormatter() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', datetime: new \DateTimeImmutable("@0"), @@ -62,7 +62,7 @@ public function testFormatWithFileAndLine() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -84,7 +84,7 @@ public function testFormatWithContext() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -120,7 +120,7 @@ public function testFormatWithContextContainingException() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger', 'exception' => [ @@ -146,7 +146,7 @@ public function testFormatWithExtra() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -179,7 +179,7 @@ public function testFormatWithLargeData() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['exception' => str_repeat(' ', 32767)], @@ -205,7 +205,7 @@ public function testFormatWithUnlimitedLength() { $formatter = new GelfMessageFormatter('LONG_SYSTEM_NAME', null, 'ctxt_', PHP_INT_MAX); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['exception' => str_repeat(' ', 32767 * 2)], @@ -231,7 +231,7 @@ public function testFormatWithLargeCyrillicData() { $formatter = new GelfMessageFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, str_repeat('в', 32767), channel: 'meh', context: ['exception' => str_repeat('а', 32767)], diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 38fd66c83..cab71f936 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; use Monolog\Test\TestCase; @@ -85,8 +85,8 @@ public function testFormatBatch() { $formatter = new JsonFormatter(); $records = [ - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), + $this->getRecord(Level::Warning), + $this->getRecord(Level::Debug), ]; $this->assertEquals(json_encode($records), $formatter->formatBatch($records)); } @@ -99,8 +99,8 @@ public function testFormatBatchNewlines() { $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_NEWLINES); $records = [ - $this->getRecord(Logger::WARNING), - $this->getRecord(Logger::DEBUG), + $this->getRecord(Level::Warning), + $this->getRecord(Level::Debug), ]; $expected = array_map(fn (LogRecord $record) => json_encode($record->toArray(), JSON_FORCE_OBJECT), $records); $this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records)); @@ -213,7 +213,7 @@ private function assertContextContainsFormattedException($expected, $actual) private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \Throwable $exception) { $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => $exception], @@ -262,7 +262,7 @@ public function testNormalizeHandleLargeArraysWithExactly1000Items() $largeArray = range(1, 1000); $res = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'bar', channel: 'test', context: array($largeArray), @@ -278,7 +278,7 @@ public function testNormalizeHandleLargeArrays() $largeArray = range(1, 2000); $res = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'bar', channel: 'test', context: array($largeArray), @@ -293,7 +293,7 @@ public function testEmptyContextAndExtraFieldsCanBeIgnored() $formatter = new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, true, true); $record = $formatter->format($this->getRecord( - Logger::DEBUG, + Level::Debug, 'Testing', channel: 'test', datetime: new \DateTimeImmutable('2022-02-22 00:00:00'), diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index f3128a772..0cc5d246f 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -12,7 +12,7 @@ namespace Monolog\Formatter; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Formatter\LineFormatter @@ -23,7 +23,7 @@ public function testDefFormatWithString() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::WARNING, + Level::Warning, 'foo', channel: 'log', )); @@ -34,7 +34,7 @@ public function testDefFormatWithArrayContext() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'foo', channel: 'meh', context: [ @@ -51,7 +51,7 @@ public function testDefFormatExtras() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', extra: ['ip' => '127.0.0.1'], @@ -63,7 +63,7 @@ public function testFormatExtras() { $formatter = new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context% %extra.file% %extra%\n", 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', extra: ['ip' => '127.0.0.1', 'file' => 'test'], @@ -75,7 +75,7 @@ public function testContextAndExtraOptionallyNotShownIfEmpty() { $formatter = new LineFormatter(null, 'Y-m-d', false, true); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', )); @@ -86,7 +86,7 @@ public function testContextAndExtraReplacement() { $formatter = new LineFormatter('%context.foo% => %extra.foo%'); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['foo' => 'bar'], @@ -100,7 +100,7 @@ public function testDefFormatWithObject() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'foobar', channel: 'meh', context: [], @@ -114,7 +114,7 @@ public function testDefFormatWithException() { $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => new \RuntimeException('Foo')], @@ -130,7 +130,7 @@ public function testDefFormatWithExceptionAndStacktrace() $formatter = new LineFormatter(null, 'Y-m-d'); $formatter->includeStacktraces(); $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => new \RuntimeException('Foo')], @@ -146,7 +146,7 @@ public function testDefFormatWithPreviousException() $formatter = new LineFormatter(null, 'Y-m-d'); $previous = new \LogicException('Wut?'); $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => new \RuntimeException('Foo', 0, $previous)], @@ -165,7 +165,7 @@ public function testDefFormatWithSoapFaultException() $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => new \SoapFault('foo', 'bar', 'hello', 'world')], @@ -176,7 +176,7 @@ public function testDefFormatWithSoapFaultException() $this->assertEquals('['.date('Y-m-d').'] core.CRITICAL: foobar {"exception":"[object] (SoapFault(code: 0 faultcode: foo faultactor: hello detail: world): bar at '.substr($path, 1, -1).':'.(__LINE__ - 5).')"} []'."\n", $message); $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => new \SoapFault('foo', 'bar', 'hello', (object) ['bar' => (object) ['biz' => 'baz'], 'foo' => 'world'])], @@ -192,12 +192,12 @@ public function testBatchFormat() $formatter = new LineFormatter(null, 'Y-m-d'); $message = $formatter->formatBatch([ $this->getRecord( - Logger::CRITICAL, + Level::Critical, 'bar', channel: 'test', ), $this->getRecord( - Logger::WARNING, + Level::Warning, 'foo', channel: 'log', ), diff --git a/tests/Monolog/Formatter/LogstashFormatterTest.php b/tests/Monolog/Formatter/LogstashFormatterTest.php index f2d134225..81683e73f 100644 --- a/tests/Monolog/Formatter/LogstashFormatterTest.php +++ b/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -11,7 +11,8 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Test\TestCase; class LogstashFormatterTest extends TestCase @@ -23,7 +24,7 @@ public function testDefaultFormatterV1() { $formatter = new LogstashFormatter('test', 'hostname'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', datetime: new \DateTimeImmutable("@0"), @@ -35,8 +36,8 @@ public function testDefaultFormatterV1() $this->assertEquals("1", $message['@version']); $this->assertEquals('log', $message['message']); $this->assertEquals('meh', $message['channel']); - $this->assertEquals('ERROR', $message['level']); - $this->assertEquals(Logger::ERROR, $message['monolog_level']); + $this->assertEquals(LevelName::Error->value, $message['level']); + $this->assertEquals(Level::Error->value, $message['monolog_level']); $this->assertEquals('test', $message['type']); $this->assertEquals('hostname', $message['host']); @@ -54,7 +55,7 @@ public function testFormatWithFileAndLineV1() { $formatter = new LogstashFormatter('test'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -75,7 +76,7 @@ public function testFormatWithContextV1() { $formatter = new LogstashFormatter('test'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -105,7 +106,7 @@ public function testFormatWithExtraV1() { $formatter = new LogstashFormatter('test'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -132,7 +133,7 @@ public function testFormatWithApplicationNameV1() { $formatter = new LogstashFormatter('app', 'test'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -150,7 +151,7 @@ public function testFormatWithLatin9Data() { $formatter = new LogstashFormatter('test', 'hostname'); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: '¯\_(ツ)_/¯', datetime: new \DateTimeImmutable("@0"), diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 4874755fa..73d7ea992 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -14,7 +14,8 @@ use MongoDB\BSON\ObjectId; use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Test\TestCase; /** @@ -62,7 +63,7 @@ public function testSimpleFormat() { $record = $this->getRecord( message: 'some log message', - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); @@ -73,8 +74,8 @@ public function testSimpleFormat() $this->assertCount(7, $formattedRecord); $this->assertEquals('some log message', $formattedRecord['message']); $this->assertEquals([], $formattedRecord['context']); - $this->assertEquals(Logger::WARNING, $formattedRecord['level']); - $this->assertEquals(Logger::getLevelName(Logger::WARNING), $formattedRecord['level_name']); + $this->assertEquals(Level::Warning->value, $formattedRecord['level']); + $this->assertEquals(LevelName::Warning->value, $formattedRecord['level_name']); $this->assertEquals('test', $formattedRecord['channel']); $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $formattedRecord['datetime']); $this->assertEquals('1453410690123', $formattedRecord['datetime']->__toString()); @@ -96,7 +97,7 @@ public function testRecursiveFormat() 'context_int' => 123456, 'except' => new \Exception('exception message', 987), ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.213000+00:00'), ); @@ -140,7 +141,7 @@ public function testFormatDepthArray() ], ], ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); @@ -174,7 +175,7 @@ public function testFormatDepthArrayInfiniteNesting() ], ], ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); @@ -211,7 +212,7 @@ public function testFormatDepthObjects() context: [ 'nest2' => $someObject, ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); @@ -238,7 +239,7 @@ public function testFormatDepthException() context: [ 'nest2' => new \Exception('exception message', 987), ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); @@ -262,7 +263,7 @@ public function testBsonTypes() 'regex' => new Regex('pattern'), ], ], - level: Logger::WARNING, + level: Level::Warning, channel: 'test', datetime: new \DateTimeImmutable('2016-01-21T21:11:30.123456+00:00'), ); diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index ab8d7b172..e13bb2ce3 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -11,8 +11,9 @@ namespace Monolog\Formatter; +use Monolog\LevelName; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Formatter\NormalizerFormatter @@ -23,7 +24,7 @@ public function testFormat() { $formatter = new NormalizerFormatter('Y-m-d'); $formatted = $formatter->format($this->getRecord( - Logger::ERROR, + Level::Error, 'foo', channel: 'meh', extra: ['foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => [], 'res' => fopen('php://memory', 'rb')], @@ -37,8 +38,8 @@ public function testFormat() )); $this->assertEquals([ - 'level_name' => 'ERROR', - 'level' => Logger::ERROR, + 'level_name' => LevelName::Error->value, + 'level' => Level::Error->value, 'channel' => 'meh', 'message' => 'foo', 'datetime' => date('Y-m-d'), @@ -142,13 +143,13 @@ public function testBatchFormat() { $formatter = new NormalizerFormatter('Y-m-d'); $formatted = $formatter->formatBatch([ - $this->getRecord(Logger::CRITICAL, 'bar', channel: 'test'), - $this->getRecord(Logger::WARNING, 'foo', channel: 'log'), + $this->getRecord(Level::Critical, 'bar', channel: 'test'), + $this->getRecord(Level::Warning, 'foo', channel: 'log'), ]); $this->assertEquals([ [ - 'level_name' => 'CRITICAL', - 'level' => Logger::CRITICAL, + 'level_name' => LevelName::Critical->value, + 'level' => Level::Critical->value, 'channel' => 'test', 'message' => 'bar', 'context' => [], @@ -156,8 +157,8 @@ public function testBatchFormat() 'extra' => [], ], [ - 'level_name' => 'WARNING', - 'level' => Logger::WARNING, + 'level_name' => LevelName::Warning->value, + 'level' => Level::Warning->value, 'channel' => 'log', 'message' => 'foo', 'context' => [], @@ -241,7 +242,7 @@ public function testNormalizeHandleLargeArraysWithExactly1000Items() $largeArray = range(1, 1000); $res = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'bar', channel: 'test', context: [$largeArray], @@ -257,7 +258,7 @@ public function testNormalizeHandleLargeArrays() $largeArray = range(1, 2000); $res = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'bar', channel: 'test', context: [$largeArray], @@ -379,7 +380,7 @@ public function testExceptionTraceWithArgs() private function formatRecordWithExceptionInContext(NormalizerFormatter $formatter, \Throwable $exception) { $message = $formatter->format($this->getRecord( - Logger::CRITICAL, + Level::Critical, 'foobar', channel: 'core', context: ['exception' => $exception], diff --git a/tests/Monolog/Formatter/WildfireFormatterTest.php b/tests/Monolog/Formatter/WildfireFormatterTest.php index a3babee0d..06a0fa70f 100644 --- a/tests/Monolog/Formatter/WildfireFormatterTest.php +++ b/tests/Monolog/Formatter/WildfireFormatterTest.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class WildfireFormatterTest extends TestCase @@ -23,7 +23,7 @@ public function testDefaultFormat() { $wildfire = new WildfireFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -46,7 +46,7 @@ public function testFormatWithFileAndLine() { $wildfire = new WildfireFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', context: ['from' => 'logger'], @@ -69,7 +69,7 @@ public function testFormatWithoutContext() { $wildfire = new WildfireFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', ); @@ -91,7 +91,7 @@ public function testBatchFormatThrowException() $wildfire = new WildfireFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'log', channel: 'meh', ); @@ -106,7 +106,7 @@ public function testTableFormat() { $wildfire = new WildfireFormatter(); $record = $this->getRecord( - Logger::ERROR, + Level::Error, 'table-message', channel: 'table-channel', context: [ diff --git a/tests/Monolog/Handler/AbstractHandlerTest.php b/tests/Monolog/Handler/AbstractHandlerTest.php index b7451a73e..58de1dd9f 100644 --- a/tests/Monolog/Handler/AbstractHandlerTest.php +++ b/tests/Monolog/Handler/AbstractHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; class AbstractHandlerTest extends TestCase { @@ -25,13 +25,13 @@ class AbstractHandlerTest extends TestCase */ public function testConstructAndGetSet() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', [Logger::WARNING, false]); - $this->assertEquals(Logger::WARNING, $handler->getLevel()); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', [Level::Warning, false]); + $this->assertEquals(Level::Warning, $handler->getLevel()); $this->assertEquals(false, $handler->getBubble()); - $handler->setLevel(Logger::ERROR); + $handler->setLevel(Level::Error); $handler->setBubble(true); - $this->assertEquals(Logger::ERROR, $handler->getLevel()); + $this->assertEquals(Level::Error, $handler->getLevel()); $this->assertEquals(true, $handler->getBubble()); } @@ -51,9 +51,9 @@ public function testHandleBatch() */ public function testIsHandling() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', [Logger::WARNING, false]); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', [Level::Warning, false]); $this->assertTrue($handler->isHandling($this->getRecord())); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); } /** @@ -62,8 +62,8 @@ public function testIsHandling() public function testHandlesPsrStyleLevels() { $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractHandler', ['warning', false]); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); $handler->setLevel('debug'); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Debug))); } } diff --git a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php index 7d732b39d..6fc3c38b8 100644 --- a/tests/Monolog/Handler/AbstractProcessingHandlerTest.php +++ b/tests/Monolog/Handler/AbstractProcessingHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Processor\WebProcessor; use Monolog\Formatter\LineFormatter; @@ -24,7 +24,7 @@ class AbstractProcessingHandlerTest extends TestCase */ public function testConstructAndGetSet() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Logger::WARNING, false]); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Level::Warning, false]); $handler->setFormatter($formatter = new LineFormatter); $this->assertSame($formatter, $handler->getFormatter()); } @@ -34,8 +34,8 @@ public function testConstructAndGetSet() */ public function testHandleLowerLevelMessage() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Logger::WARNING, true]); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Level::Warning, true]); + $this->assertFalse($handler->handle($this->getRecord(Level::Debug))); } /** @@ -43,7 +43,7 @@ public function testHandleLowerLevelMessage() */ public function testHandleBubbling() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Logger::DEBUG, true]); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Level::Debug, true]); $this->assertFalse($handler->handle($this->getRecord())); } @@ -52,7 +52,7 @@ public function testHandleBubbling() */ public function testHandleNotBubbling() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Logger::DEBUG, false]); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Level::Debug, false]); $this->assertTrue($handler->handle($this->getRecord())); } @@ -61,9 +61,9 @@ public function testHandleNotBubbling() */ public function testHandleIsFalseWhenNotHandled() { - $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Logger::WARNING, false]); + $handler = $this->getMockForAbstractClass('Monolog\Handler\AbstractProcessingHandler', [Level::Warning, false]); $this->assertTrue($handler->handle($this->getRecord())); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + $this->assertFalse($handler->handle($this->getRecord(Level::Debug))); } /** diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index c2de874c6..321727050 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use PhpAmqpLib\Message\AMQPMessage; /** @@ -46,7 +46,7 @@ public function testHandleAmqpExt() $handler = new AmqpHandler($exchange); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $expected = [ [ @@ -103,7 +103,7 @@ public function testHandlePhpAmqpLib() $handler = new AmqpHandler($exchange, 'log'); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $expected = [ [ diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index 5bda6b00c..1628a4b61 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Handler\BrowserConsoleHandlerTest @@ -37,7 +37,7 @@ public function testStyling() $handler = new BrowserConsoleHandler(); $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}')); + $handler->handle($this->getRecord(Level::Debug, 'foo[[bar]]{color: red}')); $expected = <<setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, 'foo[[bar]]{color: red}[[baz]]{color: blue}')); + $handler->handle($this->getRecord(Level::Debug, 'foo[[bar]]{color: red}[[baz]]{color: blue}')); $expected = <<setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, "[foo] [[\"bar\n[baz]\"]]{color: red}")); + $handler->handle($this->getRecord(Level::Debug, "[foo] [[\"bar\n[baz]\"]]{color: red}")); $expected = <<setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); - $handler->handle($this->getRecord(Logger::DEBUG, '[[bar]]{macro: autolabel}')); - $handler->handle($this->getRecord(Logger::DEBUG, '[[foo]]{macro: autolabel}')); + $handler->handle($this->getRecord(Level::Debug, '[[foo]]{macro: autolabel}')); + $handler->handle($this->getRecord(Level::Debug, '[[bar]]{macro: autolabel}')); + $handler->handle($this->getRecord(Level::Debug, '[[foo]]{macro: autolabel}')); $expected = <<setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG, 'test', ['foo' => 'bar', 0 => 'oop'])); + $handler->handle($this->getRecord(Level::Debug, 'test', ['foo' => 'bar', 0 => 'oop'])); $expected = <<setFormatter($this->getIdentityFormatter()); - $handler1->handle($this->getRecord(Logger::DEBUG, 'test1')); - $handler2->handle($this->getRecord(Logger::DEBUG, 'test2')); - $handler1->handle($this->getRecord(Logger::DEBUG, 'test3')); - $handler2->handle($this->getRecord(Logger::DEBUG, 'test4')); + $handler1->handle($this->getRecord(Level::Debug, 'test1')); + $handler2->handle($this->getRecord(Level::Debug, 'test2')); + $handler1->handle($this->getRecord(Level::Debug, 'test3')); + $handler2->handle($this->getRecord(Level::Debug, 'test4')); $expected = <<handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertFalse($test->hasDebugRecords()); $this->assertFalse($test->hasInfoRecords()); $handler->close(); @@ -44,8 +44,8 @@ public function testPropagatesRecordsAtEndOfRequest() { $test = new TestHandler(); $handler = new BufferHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Warning)); + $handler->handle($this->getRecord(Level::Debug)); $this->shutdownCheckHandler = $test; register_shutdown_function([$this, 'checkPropagation']); } @@ -65,10 +65,10 @@ public function testHandleBufferLimit() { $test = new TestHandler(); $handler = new BufferHandler($test, 2); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); + $handler->handle($this->getRecord(Level::Warning)); $handler->close(); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -81,22 +81,22 @@ public function testHandleBufferLimit() public function testHandleBufferLimitWithFlushOnOverflow() { $test = new TestHandler(); - $handler = new BufferHandler($test, 3, Logger::DEBUG, true, true); + $handler = new BufferHandler($test, 3, Level::Debug, true, true); // send two records - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); $this->assertCount(0, $test->getRecords()); // overflow - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $this->assertTrue($test->hasDebugRecords()); $this->assertCount(3, $test->getRecords()); // should buffer again - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertCount(3, $test->getRecords()); $handler->close(); @@ -111,11 +111,11 @@ public function testHandleBufferLimitWithFlushOnOverflow() public function testHandleLevel() { $test = new TestHandler(); - $handler = new BufferHandler($test, 0, Logger::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler = new BufferHandler($test, 0, Level::Info); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); + $handler->handle($this->getRecord(Level::Warning)); + $handler->handle($this->getRecord(Level::Debug)); $handler->close(); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -129,8 +129,8 @@ public function testFlush() { $test = new TestHandler(); $handler = new BufferHandler($test, 0); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $handler->flush(); $this->assertTrue($test->hasInfoRecords()); $this->assertTrue($test->hasDebugRecords()); @@ -149,7 +149,7 @@ public function testHandleUsesProcessors() return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $handler->flush(); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 1ee581959..5600cd288 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Handler\ChromePHPHandler @@ -34,8 +34,8 @@ public function testHeaders($agent) $handler = new TestChromePHPHandler(); $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning)); $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ @@ -65,11 +65,11 @@ public static function agentsProvider() public function testHeadersOverflow() { $handler = new TestChromePHPHandler(); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('a', 2 * 1024))); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning, str_repeat('a', 2 * 1024))); // overflow chrome headers limit - $handler->handle($this->getRecord(Logger::WARNING, str_repeat('b', 2 * 1024))); + $handler->handle($this->getRecord(Level::Warning, str_repeat('b', 2 * 1024))); $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ @@ -106,13 +106,13 @@ public function testConcurrentHandlers() { $handler = new TestChromePHPHandler(); $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning)); $handler2 = new TestChromePHPHandler(); $handler2->setFormatter($this->getIdentityFormatter()); - $handler2->handle($this->getRecord(Logger::DEBUG)); - $handler2->handle($this->getRecord(Logger::WARNING)); + $handler2->handle($this->getRecord(Level::Debug)); + $handler2->handle($this->getRecord(Level::Warning)); $expected = [ 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ diff --git a/tests/Monolog/Handler/CouchDBHandlerTest.php b/tests/Monolog/Handler/CouchDBHandlerTest.php index f89a130b5..289bcf5ab 100644 --- a/tests/Monolog/Handler/CouchDBHandlerTest.php +++ b/tests/Monolog/Handler/CouchDBHandlerTest.php @@ -12,13 +12,13 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class CouchDBHandlerTest extends TestCase { public function testHandle() { - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $handler = new CouchDBHandler(); diff --git a/tests/Monolog/Handler/DeduplicationHandlerTest.php b/tests/Monolog/Handler/DeduplicationHandlerTest.php index 86c7c8a5d..f617e019f 100644 --- a/tests/Monolog/Handler/DeduplicationHandlerTest.php +++ b/tests/Monolog/Handler/DeduplicationHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; class DeduplicationHandlerTest extends TestCase { @@ -23,10 +23,10 @@ public function testFlushPassthruIfAllRecordsUnderTrigger() { $test = new TestHandler(); @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); + $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', Level::Debug); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $handler->flush(); @@ -43,10 +43,10 @@ public function testFlushPassthruIfEmptyLog() { $test = new TestHandler(); @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); + $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', Level::Debug); - $handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar')); - $handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar")); + $handler->handle($this->getRecord(Level::Error, 'Foo:bar')); + $handler->handle($this->getRecord(Level::Critical, "Foo\nbar")); $handler->flush(); @@ -64,10 +64,10 @@ public function testFlushPassthruIfEmptyLog() public function testFlushSkipsIfLogExists() { $test = new TestHandler(); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); + $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', Level::Debug); - $handler->handle($this->getRecord(Logger::ERROR, 'Foo:bar')); - $handler->handle($this->getRecord(Logger::CRITICAL, "Foo\nbar")); + $handler->handle($this->getRecord(Level::Error, 'Foo:bar')); + $handler->handle($this->getRecord(Level::Critical, "Foo\nbar")); $handler->flush(); @@ -85,11 +85,11 @@ public function testFlushSkipsIfLogExists() public function testFlushPassthruIfLogTooOld() { $test = new TestHandler(); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); + $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', Level::Debug); - $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable('+62seconds')); + $record = $this->getRecord(Level::Error, datetime: new \DateTimeImmutable('+62seconds')); $handler->handle($record); - $record = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('+62seconds')); + $record = $this->getRecord(Level::Critical, datetime: new \DateTimeImmutable('+62seconds')); $handler->handle($record); $handler->flush(); @@ -109,14 +109,14 @@ public function testGcOldLogs() { $test = new TestHandler(); @unlink(sys_get_temp_dir().'/monolog_dedup.log'); - $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', 0); + $handler = new DeduplicationHandler($test, sys_get_temp_dir().'/monolog_dedup.log', Level::Debug); // handle two records from yesterday, and one recent - $record = $this->getRecord(Logger::ERROR, datetime: new \DateTimeImmutable('-1day -10seconds')); + $record = $this->getRecord(Level::Error, datetime: new \DateTimeImmutable('-1day -10seconds')); $handler->handle($record); - $record2 = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('-1day -10seconds')); + $record2 = $this->getRecord(Level::Critical, datetime: new \DateTimeImmutable('-1day -10seconds')); $handler->handle($record2); - $record3 = $this->getRecord(Logger::CRITICAL, datetime: new \DateTimeImmutable('-30seconds')); + $record3 = $this->getRecord(Level::Critical, datetime: new \DateTimeImmutable('-30seconds')); $handler->handle($record3); // log is written as none of them are duplicate @@ -137,8 +137,8 @@ public function testGcOldLogs() $this->assertFalse($test->hasCriticalRecords()); // log new records, duplicate log gets GC'd at the end of this flush call - $handler->handle($record = $this->getRecord(Logger::ERROR)); - $handler->handle($record2 = $this->getRecord(Logger::CRITICAL)); + $handler->handle($record = $this->getRecord(Level::Error)); + $handler->handle($record2 = $this->getRecord(Level::Critical)); $handler->flush(); // log should now contain the new errors and the previous one that was recent enough diff --git a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php index 35330681e..1f6f2ffb8 100644 --- a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php +++ b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class DoctrineCouchDBHandlerTest extends TestCase { @@ -30,12 +30,12 @@ public function testHandle() ->disableOriginalConstructor() ->getMock(); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $expected = [ 'message' => 'test', 'context' => ['data' => ['stdClass' => []], 'foo' => 34], - 'level' => Logger::WARNING, + 'level' => Level::Warning->value, 'level_name' => 'WARNING', 'channel' => 'test', 'datetime' => (string) $record->datetime, diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 1fa3be3b4..706e417f3 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -14,7 +14,7 @@ use Monolog\Formatter\ElasticaFormatter; use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\LogRecord; use Elastica\Client; use Elastica\Request; @@ -58,7 +58,7 @@ public function setUp(): void public function testHandle() { // log message - $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); + $msg = $this->getRecord(Level::Error, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); // format expected result $formatter = new ElasticaFormatter($this->options['index'], $this->options['type']); @@ -158,7 +158,7 @@ public function providerTestConnectionErrors() */ public function testHandleIntegration() { - $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); + $msg = $this->getRecord(Level::Error, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); $expected = $msg->toArray(); $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); @@ -204,7 +204,7 @@ public function testHandleIntegration() */ public function testHandleIntegrationNewESVersion() { - $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); + $msg = $this->getRecord(Level::Error, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); $expected = (array) $msg; $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index ba4de76bb..9009b71d4 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -15,7 +15,7 @@ use Monolog\Formatter\ElasticsearchFormatter; use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Elasticsearch\Client; class ElasticsearchHandlerTest extends TestCase @@ -56,7 +56,7 @@ public function setUp(): void public function testHandle() { // log message - $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); + $msg = $this->getRecord(Level::Error, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); // format expected result $formatter = new ElasticsearchFormatter($this->options['index'], $this->options['type']); @@ -172,7 +172,7 @@ public function providerTestConnectionErrors() */ public function testHandleIntegration() { - $msg = $this->getRecord(Logger::ERROR, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); + $msg = $this->getRecord(Level::Error, 'log', context: ['foo' => 7, 'bar', 'class' => new \stdClass], datetime: new \DateTimeImmutable("@0")); $expected = $msg->toArray(); $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); diff --git a/tests/Monolog/Handler/ErrorLogHandlerTest.php b/tests/Monolog/Handler/ErrorLogHandlerTest.php index 10e8ec206..37bf58c56 100644 --- a/tests/Monolog/Handler/ErrorLogHandlerTest.php +++ b/tests/Monolog/Handler/ErrorLogHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; function error_log() @@ -46,14 +46,14 @@ public function testShouldLogMessagesUsingErrorLogFunction() $type = ErrorLogHandler::OPERATING_SYSTEM; $handler = new ErrorLogHandler($type); $handler->setFormatter(new LineFormatter('%channel%.%level_name%: %message% %context% %extra%', null, true)); - $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + $handler->handle($this->getRecord(Level::Error, "Foo\nBar\r\n\r\nBaz")); $this->assertSame("test.ERROR: Foo\nBar\r\n\r\nBaz [] []", $GLOBALS['error_log'][0][0]); $this->assertSame($GLOBALS['error_log'][0][1], $type); - $handler = new ErrorLogHandler($type, Logger::DEBUG, true, true); + $handler = new ErrorLogHandler($type, Level::Debug, true, true); $handler->setFormatter(new LineFormatter(null, null, true)); - $handler->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + $handler->handle($this->getRecord(Level::Error, "Foo\nBar\r\n\r\nBaz")); $this->assertStringMatchesFormat('[%s] test.ERROR: Foo', $GLOBALS['error_log'][1][0]); $this->assertSame($GLOBALS['error_log'][1][1], $type); diff --git a/tests/Monolog/Handler/FallbackGroupHandlerTest.php b/tests/Monolog/Handler/FallbackGroupHandlerTest.php index 0cb149bcb..b364c0ff3 100644 --- a/tests/Monolog/Handler/FallbackGroupHandlerTest.php +++ b/tests/Monolog/Handler/FallbackGroupHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class FallbackGroupHandlerTest extends TestCase @@ -26,8 +26,8 @@ public function testHandle() $testHandlerTwo = new TestHandler(); $testHandlers = [$testHandlerOne, $testHandlerTwo]; $handler = new FallbackGroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertCount(2, $testHandlerOne->getRecords()); $this->assertCount(0, $testHandlerTwo->getRecords()); @@ -43,8 +43,8 @@ public function testHandleExceptionThrown() $testHandlerTwo = new TestHandler(); $testHandlers = [$testHandlerOne, $testHandlerTwo]; $handler = new FallbackGroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertCount(0, $testHandlerOne->getRecords()); $this->assertCount(2, $testHandlerTwo->getRecords()); @@ -59,7 +59,7 @@ public function testHandleBatch() $testHandlerTwo = new TestHandler(); $testHandlers = [$testHandlerOne, $testHandlerTwo]; $handler = new FallbackGroupHandler($testHandlers); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); $this->assertCount(2, $testHandlerOne->getRecords()); $this->assertCount(0, $testHandlerTwo->getRecords()); } @@ -73,7 +73,7 @@ public function testHandleBatchExceptionThrown() $testHandlerTwo = new TestHandler(); $testHandlers = [$testHandlerOne, $testHandlerTwo]; $handler = new FallbackGroupHandler($testHandlers); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); $this->assertCount(0, $testHandlerOne->getRecords()); $this->assertCount(2, $testHandlerTwo->getRecords()); } @@ -83,11 +83,11 @@ public function testHandleBatchExceptionThrown() */ public function testIsHandling() { - $testHandlers = [new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)]; + $testHandlers = [new TestHandler(Level::Error), new TestHandler(Level::Warning)]; $handler = new FallbackGroupHandler($testHandlers); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Error))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Warning))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); } /** @@ -102,7 +102,7 @@ public function testHandleUsesProcessors() return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); @@ -127,7 +127,7 @@ public function testHandleBatchUsesProcessors() return $record; }); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); $this->assertEmpty($testHandlerOne->getRecords()); $this->assertTrue($testHandlerTwo->hasDebugRecords()); $this->assertTrue($testHandlerTwo->hasInfoRecords()); diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index 49ecb12b8..4fa2eb79e 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class FilterHandlerTest extends TestCase @@ -22,15 +22,15 @@ class FilterHandlerTest extends TestCase public function testIsHandling() { $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::INFO))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::NOTICE))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::CRITICAL))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::ALERT))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::EMERGENCY))); + $handler = new FilterHandler($test, Level::Info, Level::Notice); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Info))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Notice))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Warning))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Error))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Critical))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Alert))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Emergency))); } /** @@ -41,39 +41,39 @@ public function testIsHandling() public function testHandleProcessOnlyNeededLevels() { $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE); + $handler = new FilterHandler($test, Level::Info, Level::Notice); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $this->assertTrue($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::NOTICE)); + $handler->handle($this->getRecord(Level::Notice)); $this->assertTrue($test->hasNoticeRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertFalse($test->hasWarningRecords()); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); $this->assertFalse($test->hasErrorRecords()); - $handler->handle($this->getRecord(Logger::CRITICAL)); + $handler->handle($this->getRecord(Level::Critical)); $this->assertFalse($test->hasCriticalRecords()); - $handler->handle($this->getRecord(Logger::ALERT)); + $handler->handle($this->getRecord(Level::Alert)); $this->assertFalse($test->hasAlertRecords()); - $handler->handle($this->getRecord(Logger::EMERGENCY)); + $handler->handle($this->getRecord(Level::Emergency)); $this->assertFalse($test->hasEmergencyRecords()); $test = new TestHandler(); - $handler = new FilterHandler($test, [Logger::INFO, Logger::ERROR]); + $handler = new FilterHandler($test, [Level::Info, Level::Error]); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $this->assertTrue($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::NOTICE)); + $handler->handle($this->getRecord(Level::Notice)); $this->assertFalse($test->hasNoticeRecords()); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); $this->assertTrue($test->hasErrorRecords()); - $handler->handle($this->getRecord(Logger::CRITICAL)); + $handler->handle($this->getRecord(Level::Critical)); $this->assertFalse($test->hasCriticalRecords()); } @@ -86,15 +86,16 @@ public function testAcceptedLevelApi() $test = new TestHandler(); $handler = new FilterHandler($test); - $levels = [Logger::INFO, Logger::ERROR]; + $levels = [Level::Info, Level::Error]; + $levelsExpect = [Level::Info, Level::Error]; $handler->setAcceptedLevels($levels); - $this->assertSame($levels, $handler->getAcceptedLevels()); + $this->assertSame($levelsExpect, $handler->getAcceptedLevels()); $handler->setAcceptedLevels(['info', 'error']); - $this->assertSame($levels, $handler->getAcceptedLevels()); + $this->assertSame($levelsExpect, $handler->getAcceptedLevels()); - $levels = [Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY]; - $handler->setAcceptedLevels(Logger::CRITICAL, Logger::EMERGENCY); + $levels = [Level::Critical, Level::Alert, Level::Emergency]; + $handler->setAcceptedLevels(Level::Critical, Level::Emergency); $this->assertSame($levels, $handler->getAcceptedLevels()); $handler->setAcceptedLevels('critical', 'emergency'); @@ -107,7 +108,7 @@ public function testAcceptedLevelApi() public function testHandleUsesProcessors() { $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::DEBUG, Logger::EMERGENCY); + $handler = new FilterHandler($test, Level::Debug, Level::Emergency); $handler->pushProcessor( function ($record) { $record->extra['foo'] = true; @@ -115,7 +116,7 @@ function ($record) { return $record; } ); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); @@ -128,13 +129,13 @@ public function testHandleRespectsBubble() { $test = new TestHandler(); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, false); - $this->assertTrue($handler->handle($this->getRecord(Logger::INFO))); - $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); + $handler = new FilterHandler($test, Level::Info, Level::Notice, false); + $this->assertTrue($handler->handle($this->getRecord(Level::Info))); + $this->assertFalse($handler->handle($this->getRecord(Level::Warning))); - $handler = new FilterHandler($test, Logger::INFO, Logger::NOTICE, true); - $this->assertFalse($handler->handle($this->getRecord(Logger::INFO))); - $this->assertFalse($handler->handle($this->getRecord(Logger::WARNING))); + $handler = new FilterHandler($test, Level::Info, Level::Notice, true); + $this->assertFalse($handler->handle($this->getRecord(Level::Info))); + $this->assertFalse($handler->handle($this->getRecord(Level::Warning))); } /** @@ -147,12 +148,12 @@ public function testHandleWithCallback() function ($record, $handler) use ($test) { return $test; }, - Logger::INFO, - Logger::NOTICE, + Level::Info, + Level::Notice, false ); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertFalse($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); } @@ -170,7 +171,7 @@ function ($record, $handler) { $this->expectException(\RuntimeException::class); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); } public function testHandleEmptyBatch() @@ -188,12 +189,12 @@ public function testHandleEmptyBatch() public function testResetTestHandler() { $test = new TestHandler(); - $handler = new FilterHandler($test, [Logger::INFO, Logger::ERROR]); + $handler = new FilterHandler($test, [Level::Info, Level::Error]); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $this->assertTrue($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); $this->assertTrue($test->hasErrorRecords()); $handler->reset(); diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php index 8847a16d8..702a5f081 100644 --- a/tests/Monolog/Handler/FingersCrossedHandlerTest.php +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ChannelLevelActivationStrategy; use Psr\Log\LogLevel; @@ -28,11 +28,11 @@ public function testHandleBuffers() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertFalse($test->hasDebugRecords()); $this->assertFalse($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $handler->close(); $this->assertTrue($test->hasInfoRecords()); $this->assertCount(3, $test->getRecords()); @@ -46,8 +46,8 @@ public function testHandleStopsBufferingAfterTrigger() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Warning)); + $handler->handle($this->getRecord(Level::Debug)); $handler->close(); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasDebugRecords()); @@ -63,10 +63,10 @@ public function testHandleResetBufferingAfterReset() $test = new TestHandler(); $test->setSkipReset(true); $handler = new FingersCrossedHandler($test); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Warning)); + $handler->handle($this->getRecord(Level::Debug)); $handler->reset(); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $handler->close(); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasDebugRecords()); @@ -80,10 +80,10 @@ public function testHandleResetBufferingAfterReset() public function testHandleResetBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler = new FingersCrossedHandler($test, Level::Warning, 0, false, false); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning)); + $handler->handle($this->getRecord(Level::Info)); $handler->close(); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasDebugRecords()); @@ -97,11 +97,11 @@ public function testHandleResetBufferingAfterBeingTriggeredWhenStopBufferingIsDi public function testHandleBufferLimit() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::WARNING, 2); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler = new FingersCrossedHandler($test, Level::Warning, 2); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $this->assertTrue($test->hasInfoRecords()); $this->assertFalse($test->hasDebugRecords()); @@ -117,11 +117,11 @@ public function testHandleWithCallback() $handler = new FingersCrossedHandler(function ($record, $handler) use ($test) { return $test; }); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $this->assertFalse($test->hasDebugRecords()); $this->assertFalse($test->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasInfoRecords()); $this->assertCount(3, $test->getRecords()); } @@ -138,7 +138,7 @@ public function testHandleWithBadCallbackThrowsException() $this->expectException(\RuntimeException::class); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); } /** @@ -147,8 +147,8 @@ public function testHandleWithBadCallbackThrowsException() public function testIsHandlingAlways() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::ERROR); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::DEBUG))); + $handler = new FingersCrossedHandler($test, Level::Error); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Debug))); } /** @@ -159,10 +159,10 @@ public function testIsHandlingAlways() public function testErrorLevelActivationStrategy() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING)); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Level::Warning)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); } @@ -176,9 +176,9 @@ public function testErrorLevelActivationStrategyWithPsrLevel() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning')); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); } @@ -191,11 +191,11 @@ public function testOverrideActivationStrategy() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy('warning')); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($test->hasDebugRecords()); $handler->activate(); $this->assertTrue($test->hasDebugRecords()); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Info)); $this->assertTrue($test->hasInfoRecords()); } @@ -206,10 +206,10 @@ public function testOverrideActivationStrategy() public function testChannelLevelActivationStrategy() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Logger::ERROR, ['othertest' => Logger::DEBUG])); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy(Level::Error, ['othertest' => Level::Debug])); + $handler->handle($this->getRecord(Level::Warning)); $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG, channel: 'othertest'); + $record = $this->getRecord(Level::Debug, channel: 'othertest'); $handler->handle($record); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); @@ -223,9 +223,9 @@ public function testChannelLevelActivationStrategyWithPsrLevels() { $test = new TestHandler(); $handler = new FingersCrossedHandler($test, new ChannelLevelActivationStrategy('error', ['othertest' => 'debug'])); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertFalse($test->hasWarningRecords()); - $record = $this->getRecord(Logger::DEBUG, channel: 'othertest'); + $record = $this->getRecord(Level::Debug, channel: 'othertest'); $handler->handle($record); $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasWarningRecords()); @@ -238,13 +238,13 @@ public function testChannelLevelActivationStrategyWithPsrLevels() public function testHandleUsesProcessors() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, Logger::INFO); + $handler = new FingersCrossedHandler($test, Level::Info); $handler->pushProcessor(function ($record) { $record->extra['foo'] = true; return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); @@ -256,9 +256,9 @@ public function testHandleUsesProcessors() public function testPassthruOnClose() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, Logger::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Level::Warning), 0, true, true, Level::Info); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $handler->close(); $this->assertFalse($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -270,9 +270,9 @@ public function testPassthruOnClose() public function testPsrLevelPassthruOnClose() { $test = new TestHandler(); - $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Logger::WARNING), 0, true, true, LogLevel::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler = new FingersCrossedHandler($test, new ErrorLevelActivationStrategy(Level::Warning), 0, true, true, LogLevel::INFO); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); $handler->close(); $this->assertFalse($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); diff --git a/tests/Monolog/Handler/FirePHPHandlerTest.php b/tests/Monolog/Handler/FirePHPHandlerTest.php index cd8fa1bec..fd28b95a8 100644 --- a/tests/Monolog/Handler/FirePHPHandlerTest.php +++ b/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Handler\FirePHPHandler @@ -29,8 +29,8 @@ public function testHeaders() { $handler = new TestFirePHPHandler; $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning)); $expected = [ 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', @@ -47,13 +47,13 @@ public function testConcurrentHandlers() { $handler = new TestFirePHPHandler; $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Warning)); $handler2 = new TestFirePHPHandler; $handler2->setFormatter($this->getIdentityFormatter()); - $handler2->handle($this->getRecord(Logger::DEBUG)); - $handler2->handle($this->getRecord(Logger::WARNING)); + $handler2->handle($this->getRecord(Level::Debug)); + $handler2->handle($this->getRecord(Level::Warning)); $expected = [ 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2', diff --git a/tests/Monolog/Handler/FleepHookHandlerTest.php b/tests/Monolog/Handler/FleepHookHandlerTest.php index 029d05081..4f865526a 100644 --- a/tests/Monolog/Handler/FleepHookHandlerTest.php +++ b/tests/Monolog/Handler/FleepHookHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; /** @@ -47,7 +47,7 @@ public function setUp(): void */ public function testConstructorSetsExpectedDefaults() { - $this->assertEquals(Logger::DEBUG, $this->handler->getLevel()); + $this->assertEquals(Level::Debug, $this->handler->getLevel()); $this->assertEquals(true, $this->handler->getBubble()); } @@ -56,7 +56,7 @@ public function testConstructorSetsExpectedDefaults() */ public function testHandlerUsesLineFormatterWhichIgnoresEmptyArrays() { - $record = $this->getRecord(Logger::DEBUG, 'msg'); + $record = $this->getRecord(Level::Debug, 'msg'); $expectedFormatter = new LineFormatter(null, null, true, true); $expected = $expectedFormatter->format($record); diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index c7612e331..102430988 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -13,7 +13,7 @@ use Monolog\Formatter\FlowdockFormatter; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @author Dominik Liebler @@ -41,7 +41,7 @@ public function setUp(): void public function testWriteHeader() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -61,7 +61,7 @@ public function testWriteContent($content) private function createHandler($token = 'myToken') { - $constructorArgs = [$token, Logger::DEBUG]; + $constructorArgs = [$token, Level::Debug]; $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\FlowdockHandler') ->setConstructorArgs($constructorArgs) diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 931171402..918f53248 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -13,7 +13,7 @@ use Gelf\Message; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\GelfMessageFormatter; class GelfHandlerTest extends TestCase @@ -51,7 +51,7 @@ protected function getMessagePublisher() public function testDebug() { - $record = $this->getRecord(Logger::DEBUG, "A test debug message"); + $record = $this->getRecord(Level::Debug, "A test debug message"); $expectedMessage = new Message(); $expectedMessage ->setLevel(7) @@ -72,7 +72,7 @@ public function testDebug() public function testWarning() { - $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $record = $this->getRecord(Level::Warning, "A test warning message"); $expectedMessage = new Message(); $expectedMessage ->setLevel(4) @@ -94,7 +94,7 @@ public function testWarning() public function testInjectedGelfMessageFormatter() { $record = $this->getRecord( - Logger::WARNING, + Level::Warning, "A test warning message", extra: ['blarg' => 'yep'], context: ['from' => 'logger'], diff --git a/tests/Monolog/Handler/GroupHandlerTest.php b/tests/Monolog/Handler/GroupHandlerTest.php index 97680db30..0c734dee0 100644 --- a/tests/Monolog/Handler/GroupHandlerTest.php +++ b/tests/Monolog/Handler/GroupHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class GroupHandlerTest extends TestCase { @@ -34,8 +34,8 @@ public function testHandle() { $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new GroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -50,7 +50,7 @@ public function testHandleBatch() { $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new GroupHandler($testHandlers); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -63,11 +63,11 @@ public function testHandleBatch() */ public function testIsHandling() { - $testHandlers = [new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)]; + $testHandlers = [new TestHandler(Level::Error), new TestHandler(Level::Warning)]; $handler = new GroupHandler($testHandlers); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Error))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Warning))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); } /** @@ -82,7 +82,7 @@ public function testHandleUsesProcessors() return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); @@ -105,7 +105,7 @@ public function testHandleBatchUsesProcessors() return $record; }); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index bbb1ff474..8663d7779 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @author Robert Kaufmann III @@ -33,7 +33,7 @@ class InsightOpsHandlerTest extends TestCase public function testWriteContent() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); + $this->handler->handle($this->getRecord(Level::Critical, 'Critical write test')); fseek($this->resource, 0); $content = fread($this->resource, 1024); @@ -55,7 +55,7 @@ public function testWriteBatchContent() private function createHandler() { $useSSL = extension_loaded('openssl'); - $args = array('testToken', 'us', $useSSL, Logger::DEBUG, true); + $args = array('testToken', 'us', $useSSL, Level::Debug, true); $this->resource = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder(InsightOpsHandler::class) ->onlyMethods(array('fsockopen', 'streamSetTimeout', 'closeSocket')) diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 1dcd64529..2f49fa912 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @author Robert Kaufmann III @@ -32,7 +32,7 @@ class LogEntriesHandlerTest extends TestCase public function testWriteContent() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); + $this->handler->handle($this->getRecord(Level::Critical, 'Critical write test')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -59,7 +59,7 @@ public function testWriteBatchContent() private function createHandler() { $useSSL = extension_loaded('openssl'); - $args = ['testToken', $useSSL, Logger::DEBUG, true]; + $args = ['testToken', $useSSL, Level::Debug, true]; $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\LogEntriesHandler') ->setConstructorArgs($args) diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index d6c781343..953ca14b8 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @author Julien Breux @@ -32,7 +32,7 @@ class LogmaticHandlerTest extends TestCase public function testWriteContent() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); + $this->handler->handle($this->getRecord(Level::Critical, 'Critical write test')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -59,7 +59,7 @@ public function testWriteBatchContent() private function createHandler() { $useSSL = extension_loaded('openssl'); - $args = ['testToken', 'testHostname', 'testAppname', $useSSL, Logger::DEBUG, true]; + $args = ['testToken', 'testHostname', 'testAppname', $useSSL, Level::Debug, true]; $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\LogmaticHandler') ->setConstructorArgs($args) diff --git a/tests/Monolog/Handler/MailHandlerTest.php b/tests/Monolog/Handler/MailHandlerTest.php index d85a70771..3c4a5805a 100644 --- a/tests/Monolog/Handler/MailHandlerTest.php +++ b/tests/Monolog/Handler/MailHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; class MailHandlerTest extends TestCase @@ -42,15 +42,15 @@ public function testHandleBatch() public function testHandleBatchNotSendsMailIfMessagesAreBelowLevel() { $records = [ - $this->getRecord(Logger::DEBUG, 'debug message 1'), - $this->getRecord(Logger::DEBUG, 'debug message 2'), - $this->getRecord(Logger::INFO, 'information'), + $this->getRecord(Level::Debug, 'debug message 1'), + $this->getRecord(Level::Debug, 'debug message 2'), + $this->getRecord(Level::Info, 'information'), ]; $handler = $this->getMockForAbstractClass('Monolog\\Handler\\MailHandler'); $handler->expects($this->never()) ->method('send'); - $handler->setLevel(Logger::ERROR); + $handler->setLevel(Level::Error); $handler->handleBatch($records); } diff --git a/tests/Monolog/Handler/NativeMailerHandlerTest.php b/tests/Monolog/Handler/NativeMailerHandlerTest.php index 62f79b20e..25564e9f1 100644 --- a/tests/Monolog/Handler/NativeMailerHandlerTest.php +++ b/tests/Monolog/Handler/NativeMailerHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; function mail($to, $subject, $message, $additional_headers = null, $additional_parameters = null) { @@ -79,7 +79,7 @@ public function testSend() $this->assertEmpty($GLOBALS['mail']); // non-empty batch - $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + $mailer->handle($this->getRecord(Level::Error, "Foo\nBar\r\n\r\nBaz")); $this->assertNotEmpty($GLOBALS['mail']); $this->assertIsArray($GLOBALS['mail']); $this->assertArrayHasKey('0', $GLOBALS['mail']); @@ -95,7 +95,7 @@ public function testSend() public function testMessageSubjectFormatting() { $mailer = new NativeMailerHandler('to@example.org', 'Alert: %level_name% %message%', 'from@example.org'); - $mailer->handle($this->getRecord(Logger::ERROR, "Foo\nBar\r\n\r\nBaz")); + $mailer->handle($this->getRecord(Level::Error, "Foo\nBar\r\n\r\nBaz")); $this->assertNotEmpty($GLOBALS['mail']); $this->assertIsArray($GLOBALS['mail']); $this->assertArrayHasKey('0', $GLOBALS['mail']); diff --git a/tests/Monolog/Handler/NewRelicHandlerTest.php b/tests/Monolog/Handler/NewRelicHandlerTest.php index b60f0b781..17d7e833d 100644 --- a/tests/Monolog/Handler/NewRelicHandlerTest.php +++ b/tests/Monolog/Handler/NewRelicHandlerTest.php @@ -13,7 +13,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class NewRelicHandlerTest extends TestCase { @@ -34,27 +34,27 @@ public function testThehandlerThrowsAnExceptionIfTheNRExtensionIsNotLoaded() $this->expectException(MissingExtensionException::class); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); } public function testThehandlerCanHandleTheRecord() { $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); } public function testThehandlerCanAddContextParamsToTheNewRelicTrace() { $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', ['a' => 'b'])); + $handler->handle($this->getRecord(Level::Error, 'log message', ['a' => 'b'])); $this->assertEquals(['context_a' => 'b'], self::$customParameters); } public function testThehandlerCanAddExplodedContextParamsToTheNewRelicTrace() { - $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true); + $handler = new StubNewRelicHandler(Level::Error, true, self::$appname, true); $handler->handle($this->getRecord( - Logger::ERROR, + Level::Error, 'log message', ['a' => ['key1' => 'value1', 'key2' => 'value2']] )); @@ -66,7 +66,7 @@ public function testThehandlerCanAddExplodedContextParamsToTheNewRelicTrace() public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() { - $record = $this->getRecord(Logger::ERROR, 'log message'); + $record = $this->getRecord(Level::Error, 'log message'); $record->extra = ['c' => 'd']; $handler = new StubNewRelicHandler(); @@ -77,10 +77,10 @@ public function testThehandlerCanAddExtraParamsToTheNewRelicTrace() public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace() { - $record = $this->getRecord(Logger::ERROR, 'log message'); + $record = $this->getRecord(Level::Error, 'log message'); $record->extra = ['c' => ['key1' => 'value1', 'key2' => 'value2']]; - $handler = new StubNewRelicHandler(Logger::ERROR, true, self::$appname, true); + $handler = new StubNewRelicHandler(Level::Error, true, self::$appname, true); $handler->handle($record); $this->assertEquals( @@ -91,7 +91,7 @@ public function testThehandlerCanAddExplodedExtraParamsToTheNewRelicTrace() public function testThehandlerCanAddExtraContextAndParamsToTheNewRelicTrace() { - $record = $this->getRecord(Logger::ERROR, 'log message', ['a' => 'b']); + $record = $this->getRecord(Level::Error, 'log message', ['a' => 'b']); $record->extra = ['c' => 'd']; $handler = new StubNewRelicHandler(); @@ -109,29 +109,29 @@ public function testThehandlerCanHandleTheRecordsFormattedUsingTheLineFormatter( { $handler = new StubNewRelicHandler(); $handler->setFormatter(new LineFormatter()); - $handler->handle($this->getRecord(Logger::ERROR)); + $handler->handle($this->getRecord(Level::Error)); } public function testTheAppNameIsNullByDefault() { $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + $handler->handle($this->getRecord(Level::Error, 'log message')); $this->assertEquals(null, self::$appname); } public function testTheAppNameCanBeInjectedFromtheConstructor() { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + $handler = new StubNewRelicHandler(Level::Debug, false, 'myAppName'); + $handler->handle($this->getRecord(Level::Error, 'log message')); $this->assertEquals('myAppName', self::$appname); } public function testTheAppNameCanBeOverriddenFromEachLog() { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, 'myAppName'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', ['appname' => 'logAppName'])); + $handler = new StubNewRelicHandler(Level::Debug, false, 'myAppName'); + $handler->handle($this->getRecord(Level::Error, 'log message', ['appname' => 'logAppName'])); $this->assertEquals('logAppName', self::$appname); } @@ -139,23 +139,23 @@ public function testTheAppNameCanBeOverriddenFromEachLog() public function testTheTransactionNameIsNullByDefault() { $handler = new StubNewRelicHandler(); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + $handler->handle($this->getRecord(Level::Error, 'log message')); $this->assertEquals(null, self::$transactionName); } public function testTheTransactionNameCanBeInjectedFromTheConstructor() { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message')); + $handler = new StubNewRelicHandler(Level::Debug, false, null, false, 'myTransaction'); + $handler->handle($this->getRecord(Level::Error, 'log message')); $this->assertEquals('myTransaction', self::$transactionName); } public function testTheTransactionNameCanBeOverriddenFromEachLog() { - $handler = new StubNewRelicHandler(Logger::DEBUG, false, null, false, 'myTransaction'); - $handler->handle($this->getRecord(Logger::ERROR, 'log message', ['transaction_name' => 'logTransactName'])); + $handler = new StubNewRelicHandler(Level::Debug, false, null, false, 'myTransaction'); + $handler->handle($this->getRecord(Level::Error, 'log message', ['transaction_name' => 'logTransactName'])); $this->assertEquals('logTransactName', self::$transactionName); } diff --git a/tests/Monolog/Handler/NoopHandlerTest.php b/tests/Monolog/Handler/NoopHandlerTest.php index 768f5e30a..83cb6a2a7 100644 --- a/tests/Monolog/Handler/NoopHandlerTest.php +++ b/tests/Monolog/Handler/NoopHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; /** * @covers Monolog\Handler\NoopHandler::handle @@ -22,7 +22,7 @@ class NoopHandlerTest extends TestCase /** * @dataProvider logLevelsProvider */ - public function testIsHandling($level) + public function testIsHandling(Level $level) { $handler = new NoopHandler(); $this->assertTrue($handler->isHandling($this->getRecord($level))); @@ -31,7 +31,7 @@ public function testIsHandling($level) /** * @dataProvider logLevelsProvider */ - public function testHandle($level) + public function testHandle(Level $level) { $handler = new NoopHandler(); $this->assertFalse($handler->handle($this->getRecord($level))); @@ -40,10 +40,8 @@ public function testHandle($level) public function logLevelsProvider() { return array_map( - function ($level) { - return [$level]; - }, - array_values(Logger::getLevels()) + fn ($level) => [$level], + Level::cases() ); } } diff --git a/tests/Monolog/Handler/NullHandlerTest.php b/tests/Monolog/Handler/NullHandlerTest.php index b7e482bac..d6a80074a 100644 --- a/tests/Monolog/Handler/NullHandlerTest.php +++ b/tests/Monolog/Handler/NullHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * @covers Monolog\Handler\NullHandler::handle @@ -27,7 +27,7 @@ public function testHandle() public function testHandleLowerLevelRecord() { - $handler = new NullHandler(Logger::WARNING); - $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + $handler = new NullHandler(Level::Warning); + $this->assertFalse($handler->handle($this->getRecord(Level::Debug))); } } diff --git a/tests/Monolog/Handler/OverflowHandlerTest.php b/tests/Monolog/Handler/OverflowHandlerTest.php index c62f441ae..e50966f9d 100644 --- a/tests/Monolog/Handler/OverflowHandlerTest.php +++ b/tests/Monolog/Handler/OverflowHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; /** @@ -23,19 +23,19 @@ class OverflowHandlerTest extends TestCase public function testNotPassingRecordsBeneathLogLevel() { $testHandler = new TestHandler(); - $handler = new OverflowHandler($testHandler, [], Logger::INFO); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler = new OverflowHandler($testHandler, [], Level::Info); + $handler->handle($this->getRecord(Level::Debug)); $this->assertFalse($testHandler->hasDebugRecords()); } public function testPassThroughWithoutThreshold() { $testHandler = new TestHandler(); - $handler = new OverflowHandler($testHandler, [], Logger::INFO); + $handler = new OverflowHandler($testHandler, [], Level::Info); - $handler->handle($this->getRecord(Logger::INFO, 'Info 1')); - $handler->handle($this->getRecord(Logger::INFO, 'Info 2')); - $handler->handle($this->getRecord(Logger::WARNING, 'Warning 1')); + $handler->handle($this->getRecord(Level::Info, 'Info 1')); + $handler->handle($this->getRecord(Level::Info, 'Info 2')); + $handler->handle($this->getRecord(Level::Warning, 'Warning 1')); $this->assertTrue($testHandler->hasInfoThatContains('Info 1')); $this->assertTrue($testHandler->hasInfoThatContains('Info 2')); @@ -48,20 +48,20 @@ public function testPassThroughWithoutThreshold() public function testHoldingMessagesBeneathThreshold() { $testHandler = new TestHandler(); - $handler = new OverflowHandler($testHandler, [Logger::INFO => 3]); + $handler = new OverflowHandler($testHandler, [Level::Info->value => 3]); - $handler->handle($this->getRecord(Logger::DEBUG, 'debug 1')); - $handler->handle($this->getRecord(Logger::DEBUG, 'debug 2')); + $handler->handle($this->getRecord(Level::Debug, 'debug 1')); + $handler->handle($this->getRecord(Level::Debug, 'debug 2')); foreach (range(1, 3) as $i) { - $handler->handle($this->getRecord(Logger::INFO, 'info ' . $i)); + $handler->handle($this->getRecord(Level::Info, 'info ' . $i)); } $this->assertTrue($testHandler->hasDebugThatContains('debug 1')); $this->assertTrue($testHandler->hasDebugThatContains('debug 2')); $this->assertFalse($testHandler->hasInfoRecords()); - $handler->handle($this->getRecord(Logger::INFO, 'info 4')); + $handler->handle($this->getRecord(Level::Info, 'info 4')); foreach (range(1, 4) as $i) { $this->assertTrue($testHandler->hasInfoThatContains('info ' . $i)); @@ -74,33 +74,33 @@ public function testHoldingMessagesBeneathThreshold() public function testCombinedThresholds() { $testHandler = new TestHandler(); - $handler = new OverflowHandler($testHandler, [Logger::INFO => 5, Logger::WARNING => 10]); + $handler = new OverflowHandler($testHandler, [Level::Info->value => 5, Level::Warning->value => 10]); - $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Level::Debug)); foreach (range(1, 5) as $i) { - $handler->handle($this->getRecord(Logger::INFO, 'info ' . $i)); + $handler->handle($this->getRecord(Level::Info, 'info ' . $i)); } foreach (range(1, 10) as $i) { - $handler->handle($this->getRecord(Logger::WARNING, 'warning ' . $i)); + $handler->handle($this->getRecord(Level::Warning, 'warning ' . $i)); } // Only 1 DEBUG records $this->assertCount(1, $testHandler->getRecords()); - $handler->handle($this->getRecord(Logger::INFO, 'info final')); + $handler->handle($this->getRecord(Level::Info, 'info final')); // 1 DEBUG + 5 buffered INFO + 1 new INFO $this->assertCount(7, $testHandler->getRecords()); - $handler->handle($this->getRecord(Logger::WARNING, 'warning final')); + $handler->handle($this->getRecord(Level::Warning, 'warning final')); // 1 DEBUG + 6 INFO + 10 buffered WARNING + 1 new WARNING $this->assertCount(18, $testHandler->getRecords()); - $handler->handle($this->getRecord(Logger::INFO, 'Another info')); - $handler->handle($this->getRecord(Logger::WARNING, 'Anther warning')); + $handler->handle($this->getRecord(Level::Info, 'Another info')); + $handler->handle($this->getRecord(Level::Warning, 'Anther warning')); // 1 DEBUG + 6 INFO + 11 WARNING + 1 new INFO + 1 new WARNING $this->assertCount(20, $testHandler->getRecords()); diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 98d8a4b2b..84dc911a5 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -13,6 +13,7 @@ use Exception; use Monolog\ErrorHandler; +use Monolog\Level; use Monolog\Logger; use Monolog\Test\TestCase; use PhpConsole\Connector; @@ -107,7 +108,7 @@ protected function getHandlerDefaultOption($name) return $options[$name]; } - protected function initLogger($handlerOptions = [], $level = Logger::DEBUG) + protected function initLogger($handlerOptions = [], $level = Level::Debug) { return new Logger('test', [ new PHPConsoleHandler($handlerOptions, $this->connector, $level), diff --git a/tests/Monolog/Handler/ProcessHandlerTest.php b/tests/Monolog/Handler/ProcessHandlerTest.php index 7a71c4d22..daa4ae55b 100644 --- a/tests/Monolog/Handler/ProcessHandlerTest.php +++ b/tests/Monolog/Handler/ProcessHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class ProcessHandlerTest extends TestCase { @@ -51,8 +51,8 @@ public function testWriteOpensProcessAndWritesToStdInOfProcess() ->withConsecutive([$this->stringContains($fixtures[0])], [$this->stringContains($fixtures[1])]); /** @var ProcessHandler $handler */ - $handler->handle($this->getRecord(Logger::WARNING, $fixtures[0])); - $handler->handle($this->getRecord(Logger::ERROR, $fixtures[1])); + $handler->handle($this->getRecord(Level::Warning, $fixtures[0])); + $handler->handle($this->getRecord(Level::Error, $fixtures[1])); } /** @@ -78,7 +78,7 @@ public function invalidCommandProvider() public function testConstructWithInvalidCommandThrowsInvalidArgumentException($invalidCommand, $expectedExcep) { $this->expectException($expectedExcep); - new ProcessHandler($invalidCommand, Logger::DEBUG); + new ProcessHandler($invalidCommand, Level::Debug); } /** @@ -103,7 +103,7 @@ public function invalidCwdProvider() public function testConstructWithInvalidCwdThrowsInvalidArgumentException($invalidCwd, $expectedExcep) { $this->expectException($expectedExcep); - new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, $invalidCwd); + new ProcessHandler(self::DUMMY_COMMAND, Level::Debug, true, $invalidCwd); } /** @@ -112,7 +112,7 @@ public function testConstructWithInvalidCwdThrowsInvalidArgumentException($inval */ public function testConstructWithValidCwdWorks() { - $handler = new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, sys_get_temp_dir()); + $handler = new ProcessHandler(self::DUMMY_COMMAND, Level::Debug, true, sys_get_temp_dir()); $this->assertInstanceOf( 'Monolog\Handler\ProcessHandler', $handler, @@ -137,7 +137,7 @@ public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueEx $this->expectException(\UnexpectedValueException::class); /** @var ProcessHandler $handler */ - $handler->handle($this->getRecord(Logger::WARNING, 'stream failing, whoops')); + $handler->handle($this->getRecord(Level::Warning, 'stream failing, whoops')); } /** @@ -150,7 +150,7 @@ public function testStartupWithErrorsThrowsUnexpectedValueException() $this->expectException(\UnexpectedValueException::class); - $handler->handle($this->getRecord(Logger::WARNING, 'some warning in the house')); + $handler->handle($this->getRecord(Level::Warning, 'some warning in the house')); } /** @@ -171,7 +171,7 @@ public function testWritingWithErrorsOnStdOutOfProcessThrowsInvalidArgumentExcep $this->expectException(\UnexpectedValueException::class); /** @var ProcessHandler $handler */ - $handler->handle($this->getRecord(Logger::WARNING, 'some test stuff')); + $handler->handle($this->getRecord(Level::Warning, 'some test stuff')); } /** @@ -184,7 +184,7 @@ public function testCloseClosesProcess() $property->setAccessible(true); $handler = new ProcessHandler(self::DUMMY_COMMAND); - $handler->handle($this->getRecord(Logger::WARNING, '21 is only the half truth')); + $handler->handle($this->getRecord(Level::Warning, '21 is only the half truth')); $process = $property->getValue($handler); $this->assertTrue(is_resource($process), 'Process is not running although it should.'); diff --git a/tests/Monolog/Handler/PsrHandlerTest.php b/tests/Monolog/Handler/PsrHandlerTest.php index e3f30bfaa..e06aa20e9 100644 --- a/tests/Monolog/Handler/PsrHandlerTest.php +++ b/tests/Monolog/Handler/PsrHandlerTest.php @@ -11,8 +11,9 @@ namespace Monolog\Handler; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Test\TestCase; -use Monolog\Logger; use Monolog\Formatter\LineFormatter; /** @@ -22,28 +23,24 @@ class PsrHandlerTest extends TestCase { public function logLevelProvider() { - $levels = []; - $monologLogger = new Logger(''); - - foreach ($monologLogger->getLevels() as $levelName => $level) { - $levels[] = [$levelName, $level]; - } - - return $levels; + return array_map( + fn(Level $level) => [$level->toLevelName(), $level], + Level::cases() + ); } /** * @dataProvider logLevelProvider */ - public function testHandlesAllLevels($levelName, $level) + public function testHandlesAllLevels(LevelName $levelName, Level $level) { - $message = 'Hello, world! ' . $level; - $context = ['foo' => 'bar', 'level' => $level]; + $message = 'Hello, world! ' . $level->value; + $context = ['foo' => 'bar', 'level' => $level->value]; $psrLogger = $this->createMock('Psr\Log\NullLogger'); $psrLogger->expects($this->once()) ->method('log') - ->with(strtolower($levelName), $message, $context); + ->with(strtolower($levelName->value), $message, $context); $handler = new PsrHandler($psrLogger); $handler->handle($this->getRecord($level, $message, context: $context)); @@ -53,13 +50,13 @@ public function testFormatter() { $message = 'Hello, world!'; $context = ['foo' => 'bar']; - $level = Logger::ERROR; - $levelName = 'error'; + $level = Level::Error; + $levelName = LevelName::Error; $psrLogger = $this->createMock('Psr\Log\NullLogger'); $psrLogger->expects($this->once()) ->method('log') - ->with(strtolower($levelName), 'dummy', $context); + ->with(strtolower($levelName->value), 'dummy', $context); $handler = new PsrHandler($psrLogger); $handler->setFormatter(new LineFormatter('dummy')); diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index b41ead546..7db7098e9 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; /** * Almost all examples (expected header, titles, messages) taken from @@ -28,8 +28,8 @@ class PushoverHandlerTest extends TestCase public function testWriteHeader() { $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->setHighPriorityLevel(Level::Emergency); // skip priority notifications + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -49,7 +49,7 @@ public function testWriteContent($content) public function testWriteWithComplexTitle() { $this->createHandler('myToken', 'myUser', 'Backup finished - SQL1'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -59,8 +59,8 @@ public function testWriteWithComplexTitle() public function testWriteWithComplexMessage() { $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); + $this->handler->setHighPriorityLevel(Level::Emergency); // skip priority notifications + $this->handler->handle($this->getRecord(Level::Critical, 'Backup of database "example" finished in 16 minutes.')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -71,8 +71,8 @@ public function testWriteWithTooLongMessage() { $message = str_pad('test', 520, 'a'); $this->createHandler(); - $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications - $this->handler->handle($this->getRecord(Logger::CRITICAL, $message)); + $this->handler->setHighPriorityLevel(Level::Emergency); // skip priority notifications + $this->handler->handle($this->getRecord(Level::Critical, $message)); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -84,7 +84,7 @@ public function testWriteWithTooLongMessage() public function testWriteWithHighPriority() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -94,7 +94,7 @@ public function testWriteWithHighPriority() public function testWriteWithEmergencyPriority() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); + $this->handler->handle($this->getRecord(Level::Emergency, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -104,7 +104,7 @@ public function testWriteWithEmergencyPriority() public function testWriteToMultipleUsers() { $this->createHandler('myToken', ['userA', 'userB']); - $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); + $this->handler->handle($this->getRecord(Level::Emergency, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index 7ee409a16..c65885c71 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; class RedisHandlerTest extends TestCase @@ -46,7 +46,7 @@ public function testPredisHandle() $redis->rpush('key', 'test')->shouldBeCalled(); $redis = $redis->reveal(); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $handler = new RedisHandler($redis, 'key'); $handler->setFormatter(new LineFormatter("%message%")); @@ -66,7 +66,7 @@ public function testRedisHandle() ->method('rPush') ->with('key', 'test'); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); $handler = new RedisHandler($redis, 'key'); $handler->setFormatter(new LineFormatter("%message%")); @@ -98,9 +98,9 @@ public function testRedisHandleCapped() ->method('exec') ->will($this->returnSelf()); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); - $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); + $handler = new RedisHandler($redis, 'key', Level::Debug, true, 10); $handler->setFormatter(new LineFormatter("%message%")); $handler->handle($record); } @@ -129,9 +129,9 @@ public function testPredisHandleCapped() $cb($redisTransaction); })); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); - $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); + $handler = new RedisHandler($redis, 'key', Level::Debug, true, 10); $handler->setFormatter(new LineFormatter("%message%")); $handler->handle($record); } diff --git a/tests/Monolog/Handler/RedisPubSubHandlerTest.php b/tests/Monolog/Handler/RedisPubSubHandlerTest.php index 5a37d4100..f3e9f6e69 100644 --- a/tests/Monolog/Handler/RedisPubSubHandlerTest.php +++ b/tests/Monolog/Handler/RedisPubSubHandlerTest.php @@ -14,7 +14,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; class RedisPubSubHandlerTest extends TestCase @@ -48,7 +48,7 @@ public function testPredisHandle() $redis->publish('key', 'test')->shouldBeCalled(); $redis = $redis->reveal(); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass(), 'foo' => 34]); $handler = new RedisPubSubHandler($redis, 'key'); $handler->setFormatter(new LineFormatter("%message%")); @@ -67,7 +67,7 @@ public function testRedisHandle() ->method('publish') ->with('key', 'test'); - $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]); + $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass(), 'foo' => 34]); $handler = new RedisPubSubHandler($redis, 'key'); $handler->setFormatter(new LineFormatter("%message%")); diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 0aa7cbff0..da267a879 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -13,7 +13,7 @@ use Exception; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use PHPUnit\Framework\MockObject\MockObject; use Rollbar\RollbarLogger; @@ -52,7 +52,7 @@ public function testExceptionLogLevel() { $handler = $this->createHandler(); - $handler->handle($this->createExceptionRecord(Logger::DEBUG)); + $handler->handle($this->createExceptionRecord(Level::Debug)); $this->assertEquals('debug', $this->reportedExceptionArguments['payload']['level']); } @@ -79,10 +79,10 @@ private function setupRollbarLoggerMock() private function createHandler(): RollbarHandler { - return new RollbarHandler($this->rollbarLogger, Logger::DEBUG); + return new RollbarHandler($this->rollbarLogger, Level::Debug); } - private function createExceptionRecord($level = Logger::DEBUG, $message = 'test', $exception = null): array + private function createExceptionRecord($level = Level::Debug, $message = 'test', $exception = null): array { return $this->getRecord($level, $message, [ 'exception' => $exception ?: new Exception(), diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index 563bec728..e6c88fe03 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -11,7 +11,8 @@ namespace Monolog\Handler\Slack; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LevelName; use Monolog\Test\TestCase; /** @@ -22,24 +23,22 @@ class SlackRecordTest extends TestCase public function dataGetAttachmentColor() { return array( - array(Logger::DEBUG, SlackRecord::COLOR_DEFAULT), - array(Logger::INFO, SlackRecord::COLOR_GOOD), - array(Logger::NOTICE, SlackRecord::COLOR_GOOD), - array(Logger::WARNING, SlackRecord::COLOR_WARNING), - array(Logger::ERROR, SlackRecord::COLOR_DANGER), - array(Logger::CRITICAL, SlackRecord::COLOR_DANGER), - array(Logger::ALERT, SlackRecord::COLOR_DANGER), - array(Logger::EMERGENCY, SlackRecord::COLOR_DANGER), + array(Level::Debug, SlackRecord::COLOR_DEFAULT), + array(Level::Info, SlackRecord::COLOR_GOOD), + array(Level::Notice, SlackRecord::COLOR_GOOD), + array(Level::Warning, SlackRecord::COLOR_WARNING), + array(Level::Error, SlackRecord::COLOR_DANGER), + array(Level::Critical, SlackRecord::COLOR_DANGER), + array(Level::Alert, SlackRecord::COLOR_DANGER), + array(Level::Emergency, SlackRecord::COLOR_DANGER), ); } /** * @dataProvider dataGetAttachmentColor - * @param int $logLevel - * @param string $expectedColour RGB hex color or name of Slack color * @covers ::getAttachmentColor */ - public function testGetAttachmentColor($logLevel, $expectedColour) + public function testGetAttachmentColor(Level $logLevel, string $expectedColour) { $slackRecord = new SlackRecord(); $this->assertSame( @@ -155,7 +154,7 @@ public function testTextEqualsMessageIfNoAttachment() { $message = 'Test message'; $record = new SlackRecord(null, null, false); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); + $data = $record->getSlackData($this->getRecord(Level::Warning, $message)); $this->assertArrayHasKey('text', $data); $this->assertSame($message, $data['text']); @@ -181,13 +180,13 @@ public function testTextEqualsFormatterOutput() $message = 'Test message'; $record = new SlackRecord(null, null, false, null, false, false, array(), $formatter); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); + $data = $record->getSlackData($this->getRecord(Level::Warning, $message)); $this->assertArrayHasKey('text', $data); $this->assertSame($message . 'test', $data['text']); $record->setFormatter($formatter2); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); + $data = $record->getSlackData($this->getRecord(Level::Warning, $message)); $this->assertArrayHasKey('text', $data); $this->assertSame($message . 'test1', $data['text']); @@ -197,7 +196,7 @@ public function testAddsFallbackAndTextToAttachment() { $message = 'Test message'; $record = new SlackRecord(null); - $data = $record->getSlackData($this->getRecord(Logger::WARNING, $message)); + $data = $record->getSlackData($this->getRecord(Level::Warning, $message)); $this->assertSame($message, $data['attachments'][0]['text']); $this->assertSame($message, $data['attachments'][0]['fallback']); @@ -206,11 +205,11 @@ public function testAddsFallbackAndTextToAttachment() public function testMapsLevelToColorAttachmentColor() { $record = new SlackRecord(null); - $errorLoggerRecord = $this->getRecord(Logger::ERROR); - $emergencyLoggerRecord = $this->getRecord(Logger::EMERGENCY); - $warningLoggerRecord = $this->getRecord(Logger::WARNING); - $infoLoggerRecord = $this->getRecord(Logger::INFO); - $debugLoggerRecord = $this->getRecord(Logger::DEBUG); + $errorLoggerRecord = $this->getRecord(Level::Error); + $emergencyLoggerRecord = $this->getRecord(Level::Emergency); + $warningLoggerRecord = $this->getRecord(Level::Warning); + $infoLoggerRecord = $this->getRecord(Level::Info); + $debugLoggerRecord = $this->getRecord(Level::Debug); $data = $record->getSlackData($errorLoggerRecord); $this->assertSame(SlackRecord::COLOR_DANGER, $data['attachments'][0]['color']); @@ -230,8 +229,8 @@ public function testMapsLevelToColorAttachmentColor() public function testAddsShortAttachmentWithoutContextAndExtra() { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); + $level = Level::Error; + $levelName = LevelName::fromLevel($level)->value; $record = new SlackRecord(null, null, true, null, true); $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); @@ -244,8 +243,8 @@ public function testAddsShortAttachmentWithoutContextAndExtra() public function testAddsShortAttachmentWithContextAndExtra() { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); + $level = Level::Error; + $levelName = LevelName::fromLevel($level)->value; $context = array('test' => 1); $extra = array('tags' => array('web')); $record = new SlackRecord(null, null, true, null, true, true); @@ -277,8 +276,8 @@ public function testAddsShortAttachmentWithContextAndExtra() public function testAddsLongAttachmentWithoutContextAndExtra() { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); + $level = Level::Error; + $levelName = LevelName::fromLevel($level)->value; $record = new SlackRecord(null, null, true, null); $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); @@ -299,8 +298,8 @@ public function testAddsLongAttachmentWithoutContextAndExtra() public function testAddsLongAttachmentWithContextAndExtra() { - $level = Logger::ERROR; - $levelName = Logger::getLevelName($level); + $level = Level::Error; + $levelName = LevelName::fromLevel($level)->value; $context = array('test' => 1); $extra = array('tags' => array('web')); $record = new SlackRecord(null, null, true, null, false, true); @@ -350,7 +349,7 @@ public function testAddsTimestampToAttachment() public function testContextHasException() { - $record = $this->getRecord(Logger::CRITICAL, 'This is a critical message.', array('exception' => new \Exception())); + $record = $this->getRecord(Level::Critical, 'This is a critical message.', array('exception' => new \Exception())); $slackRecord = new SlackRecord(null, null, true, null, false, true); $data = $slackRecord->getSlackData($record); $this->assertIsString($data['attachments'][0]['fields'][1]['value']); @@ -359,7 +358,7 @@ public function testContextHasException() public function testExcludeExtraAndContextFields() { $record = $this->getRecord( - Logger::WARNING, + Level::Warning, 'test', context: array('info' => array('library' => 'monolog', 'author' => 'Jordi')), extra: array('tags' => array('web', 'cli')), diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index c6252513c..45b439dd9 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; use Monolog\Handler\Slack\SlackRecord; @@ -42,7 +42,7 @@ public function setUp(): void public function testWriteHeader() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -52,7 +52,7 @@ public function testWriteHeader() public function testWriteContent() { $this->createHandler(); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -65,13 +65,13 @@ public function testWriteContent() public function testWriteContentUsesFormatterIfProvided() { $this->createHandler('myToken', 'channel1', 'Monolog', false); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); $this->createHandler('myToken', 'channel1', 'Monolog', false); $this->handler->setFormatter(new LineFormatter('foo--%message%')); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test2')); + $this->handler->handle($this->getRecord(Level::Critical, 'test2')); fseek($this->res, 0); $content2 = fread($this->res, 1024); @@ -82,7 +82,7 @@ public function testWriteContentUsesFormatterIfProvided() public function testWriteContentWithEmoji() { $this->createHandler('myToken', 'channel1', 'Monolog', true, 'alien'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -105,7 +105,7 @@ public function testWriteContentWithColors($level, $expectedColor) public function testWriteContentWithPlainTextMessage() { $this->createHandler('myToken', 'channel1', 'Monolog', false); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + $this->handler->handle($this->getRecord(Level::Critical, 'test1')); fseek($this->res, 0); $content = fread($this->res, 1024); @@ -115,20 +115,20 @@ public function testWriteContentWithPlainTextMessage() public function provideLevelColors() { return array( - array(Logger::DEBUG, urlencode(SlackRecord::COLOR_DEFAULT)), - array(Logger::INFO, SlackRecord::COLOR_GOOD), - array(Logger::NOTICE, SlackRecord::COLOR_GOOD), - array(Logger::WARNING, SlackRecord::COLOR_WARNING), - array(Logger::ERROR, SlackRecord::COLOR_DANGER), - array(Logger::CRITICAL, SlackRecord::COLOR_DANGER), - array(Logger::ALERT, SlackRecord::COLOR_DANGER), - array(Logger::EMERGENCY,SlackRecord::COLOR_DANGER), + array(Level::Debug, urlencode(SlackRecord::COLOR_DEFAULT)), + array(Level::Info, SlackRecord::COLOR_GOOD), + array(Level::Notice, SlackRecord::COLOR_GOOD), + array(Level::Warning, SlackRecord::COLOR_WARNING), + array(Level::Error, SlackRecord::COLOR_DANGER), + array(Level::Critical, SlackRecord::COLOR_DANGER), + array(Level::Alert, SlackRecord::COLOR_DANGER), + array(Level::Emergency,SlackRecord::COLOR_DANGER), ); } private function createHandler($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false) { - $constructorArgs = [$token, $channel, $username, $useAttachment, $iconEmoji, Logger::DEBUG, true, $useShortAttachment, $includeExtra]; + $constructorArgs = [$token, $channel, $username, $useAttachment, $iconEmoji, Level::Debug, true, $useShortAttachment, $includeExtra]; $this->res = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder('Monolog\Handler\SlackHandler') ->setConstructorArgs($constructorArgs) diff --git a/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/tests/Monolog/Handler/SlackWebhookHandlerTest.php index 5ff262254..2dfb5444b 100644 --- a/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ b/tests/Monolog/Handler/SlackWebhookHandlerTest.php @@ -11,8 +11,9 @@ namespace Monolog\Handler; +use Monolog\LevelName; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use Monolog\Formatter\LineFormatter; use Monolog\Handler\Slack\SlackRecord; @@ -72,7 +73,7 @@ public function testConstructorFull() ':ghost:', false, false, - Logger::DEBUG, + Level::Debug, false ); @@ -100,7 +101,7 @@ public function testConstructorFullWithAttachment() 'https://www.example.com/example.png', false, false, - Logger::DEBUG, + Level::Debug, false ); @@ -118,7 +119,7 @@ public function testConstructorFullWithAttachment() 'fields' => array( array( 'title' => 'Level', - 'value' => Logger::getLevelName(Logger::WARNING), + 'value' => LevelName::Warning->value, 'short' => false, ), ), diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 272dd704a..ddc7597a5 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; use PHPUnit\Framework\MockObject\MockObject; /** @@ -285,7 +285,7 @@ private function createHandler($connectionString) private function writeRecord($string) { - $this->handler->handle($this->getRecord(Logger::WARNING, $string)); + $this->handler->handle($this->getRecord(Level::Warning, $string)); } private function setMockHandler(array $methods = []) diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 97d56b8cf..c0f4979fa 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -13,7 +13,7 @@ use Monolog\Handler\StreamHandler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class StreamHandlerTest extends TestCase { @@ -26,9 +26,9 @@ public function testWrite() $handle = fopen('php://memory', 'a+'); $handler = new StreamHandler($handle); $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::WARNING, 'test')); - $handler->handle($this->getRecord(Logger::WARNING, 'test2')); - $handler->handle($this->getRecord(Logger::WARNING, 'test3')); + $handler->handle($this->getRecord(Level::Warning, 'test')); + $handler->handle($this->getRecord(Level::Warning, 'test2')); + $handler->handle($this->getRecord(Level::Warning, 'test3')); fseek($handle, 0); $this->assertEquals('testtest2test3', fread($handle, 100)); } @@ -51,7 +51,7 @@ public function testCloseKeepsExternalHandlersOpen() public function testClose() { $handler = new StreamHandler('php://memory'); - $handler->handle($this->getRecord(Logger::WARNING, 'test')); + $handler->handle($this->getRecord(Level::Warning, 'test')); $stream = $handler->getStream(); $this->assertTrue(is_resource($stream)); @@ -66,7 +66,7 @@ public function testClose() public function testSerialization() { $handler = new StreamHandler('php://memory'); - $handler->handle($this->getRecord(Logger::WARNING, 'testfoo')); + $handler->handle($this->getRecord(Level::Warning, 'testfoo')); $stream = $handler->getStream(); $this->assertTrue(is_resource($stream)); @@ -76,7 +76,7 @@ public function testSerialization() $this->assertFalse(is_resource($stream)); $handler = unserialize($serialized); - $handler->handle($this->getRecord(Logger::WARNING, 'testbar')); + $handler->handle($this->getRecord(Level::Warning, 'testbar')); $stream = $handler->getStream(); $this->assertTrue(is_resource($stream)); @@ -102,7 +102,7 @@ public function testWriteCreatesTheStreamResource() public function testWriteLocking() { $temp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'monolog_locked_log'; - $handler = new StreamHandler($temp, Logger::DEBUG, true, null, true); + $handler = new StreamHandler($temp, Level::Debug, true, null, true); $handler->handle($this->getRecord()); } diff --git a/tests/Monolog/Handler/SyslogHandlerTest.php b/tests/Monolog/Handler/SyslogHandlerTest.php index 5479d547a..18fb2bcb8 100644 --- a/tests/Monolog/Handler/SyslogHandlerTest.php +++ b/tests/Monolog/Handler/SyslogHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; class SyslogHandlerTest extends \PHPUnit\Framework\TestCase { @@ -29,7 +29,7 @@ public function testConstruct() $handler = new SyslogHandler('test', 'user'); $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); - $handler = new SyslogHandler('test', LOG_USER, Logger::DEBUG, true, LOG_PERROR); + $handler = new SyslogHandler('test', LOG_USER, Level::Debug, true, LOG_PERROR); $this->assertInstanceOf('Monolog\Handler\SyslogHandler', $handler); } diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 7cb832542..530a9d53c 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; /** @@ -98,6 +99,6 @@ public function testRfc() protected function getRecordWithMessage($msg) { - return $this->getRecord(message: $msg, level: \Monolog\Logger::WARNING, channel: 'lol', datetime: new \DateTimeImmutable('2014-01-07 12:34:56')); + return $this->getRecord(message: $msg, level: Level::Warning, channel: 'lol', datetime: new \DateTimeImmutable('2014-01-07 12:34:56')); } } diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 6cb3c7d96..754af3335 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -11,7 +11,7 @@ namespace Monolog\Handler; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; /** @@ -42,7 +42,7 @@ private function createHandler( bool $disableWebPagePreview = false, bool $disableNotification = true ): void { - $constructorArgs = [$apiKey, $channel, Logger::DEBUG, true, $parseMode, $disableWebPagePreview, $disableNotification]; + $constructorArgs = [$apiKey, $channel, Level::Debug, true, $parseMode, $disableWebPagePreview, $disableNotification]; $this->handler = $this->getMockBuilder(TelegramBotHandler::class) ->setConstructorArgs($constructorArgs) diff --git a/tests/Monolog/Handler/TestHandlerTest.php b/tests/Monolog/Handler/TestHandlerTest.php index b4609c92c..218d111ce 100644 --- a/tests/Monolog/Handler/TestHandlerTest.php +++ b/tests/Monolog/Handler/TestHandlerTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Level; use Monolog\Test\TestCase; -use Monolog\Logger; /** * @covers Monolog\Handler\TestHandler @@ -22,7 +22,7 @@ class TestHandlerTest extends TestCase /** * @dataProvider methodProvider */ - public function testHandler($method, $level) + public function testHandler($method, Level $level) { $handler = new TestHandler; $record = $this->getRecord($level, 'test'.$method); @@ -57,7 +57,7 @@ public function testHandler($method, $level) public function testHandlerAssertEmptyContext() { $handler = new TestHandler; - $record = $this->getRecord(Logger::WARNING, 'test', []); + $record = $this->getRecord(Level::Warning, 'test', []); $this->assertFalse($handler->hasWarning([ 'message' => 'test', 'context' => [], @@ -80,7 +80,7 @@ public function testHandlerAssertEmptyContext() public function testHandlerAssertNonEmptyContext() { $handler = new TestHandler; - $record = $this->getRecord(Logger::WARNING, 'test', ['foo' => 'bar']); + $record = $this->getRecord(Level::Warning, 'test', ['foo' => 'bar']); $this->assertFalse($handler->hasWarning([ 'message' => 'test', 'context' => [ @@ -105,14 +105,14 @@ public function testHandlerAssertNonEmptyContext() public function methodProvider() { return [ - ['Emergency', Logger::EMERGENCY], - ['Alert' , Logger::ALERT], - ['Critical' , Logger::CRITICAL], - ['Error' , Logger::ERROR], - ['Warning' , Logger::WARNING], - ['Info' , Logger::INFO], - ['Notice' , Logger::NOTICE], - ['Debug' , Logger::DEBUG], + ['Emergency', Level::Emergency], + ['Alert' , Level::Alert], + ['Critical' , Level::Critical], + ['Error' , Level::Error], + ['Warning' , Level::Warning], + ['Info' , Level::Info], + ['Notice' , Level::Notice], + ['Debug' , Level::Debug], ]; } } diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 3d0d3b128..77bc932b7 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class WhatFailureGroupHandlerTest extends TestCase { @@ -34,8 +34,8 @@ public function testHandle() { $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new WhatFailureGroupHandler($testHandlers); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::INFO)); + $handler->handle($this->getRecord(Level::Debug)); + $handler->handle($this->getRecord(Level::Info)); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -50,7 +50,7 @@ public function testHandleBatch() { $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new WhatFailureGroupHandler($testHandlers); - $handler->handleBatch([$this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)]); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -63,11 +63,11 @@ public function testHandleBatch() */ public function testIsHandling() { - $testHandlers = [new TestHandler(Logger::ERROR), new TestHandler(Logger::WARNING)]; + $testHandlers = [new TestHandler(Level::Error), new TestHandler(Level::Warning)]; $handler = new WhatFailureGroupHandler($testHandlers); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::ERROR))); - $this->assertTrue($handler->isHandling($this->getRecord(Logger::WARNING))); - $this->assertFalse($handler->isHandling($this->getRecord(Logger::DEBUG))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Error))); + $this->assertTrue($handler->isHandling($this->getRecord(Level::Warning))); + $this->assertFalse($handler->isHandling($this->getRecord(Level::Debug))); } /** @@ -82,7 +82,7 @@ public function testHandleUsesProcessors() return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); @@ -105,7 +105,7 @@ public function testHandleBatchUsesProcessors() return $record; }); - $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); + $handler->handleBatch(array($this->getRecord(Level::Debug), $this->getRecord(Level::Info))); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); @@ -131,7 +131,7 @@ public function testHandleException() return $record; }); - $handler->handle($this->getRecord(Logger::WARNING)); + $handler->handle($this->getRecord(Level::Warning)); $this->assertTrue($test->hasWarningRecords()); $records = $test->getRecords(); $this->assertTrue($records[0]['extra']['foo']); diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 42622ffbb..217a6e552 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Logger; +use Monolog\Level; class ZendMonitorHandlerTest extends TestCase { @@ -51,15 +51,13 @@ public function testWrite() ->method('getDefaultFormatter') ->will($this->returnValue($formatterMock)); - $levelMap = $zendMonitor->getLevelMap(); - $zendMonitor->expects($this->once()) ->method('writeZendMonitorCustomEvent') ->with( - Logger::getLevelName($record->level), + $record->levelName->value, $record->message, $formatterResult, - $levelMap[$record->level] + \ZEND_MONITOR_EVENT_SEVERITY_WARNING ); $zendMonitor->handle($record); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 9ba62f749..70b4a9ff2 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -18,7 +18,7 @@ class LoggerTest extends TestCase { /** - * @covers Monolog\Logger::getName + * @covers Logger::getName */ public function testGetName() { @@ -27,15 +27,7 @@ public function testGetName() } /** - * @covers Monolog\Logger::getLevelName - */ - public function testGetLevelName() - { - $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR)); - } - - /** - * @covers Monolog\Logger::withName + * @covers Logger::withName */ public function testWithName() { @@ -48,32 +40,22 @@ public function testWithName() } /** - * @covers Monolog\Logger::toMonologLevel + * @covers Logger::toMonologLevel */ public function testConvertPSR3ToMonologLevel() { - $this->assertEquals(Logger::toMonologLevel('debug'), 100); - $this->assertEquals(Logger::toMonologLevel('info'), 200); - $this->assertEquals(Logger::toMonologLevel('notice'), 250); - $this->assertEquals(Logger::toMonologLevel('warning'), 300); - $this->assertEquals(Logger::toMonologLevel('error'), 400); - $this->assertEquals(Logger::toMonologLevel('critical'), 500); - $this->assertEquals(Logger::toMonologLevel('alert'), 550); - $this->assertEquals(Logger::toMonologLevel('emergency'), 600); - } - - /** - * @covers Monolog\Logger::getLevelName - */ - public function testGetLevelNameThrows() - { - $this->expectException(\InvalidArgumentException::class); - - Logger::getLevelName(5); + $this->assertEquals(Logger::toMonologLevel('debug'), Level::Debug); + $this->assertEquals(Logger::toMonologLevel('info'), Level::Info); + $this->assertEquals(Logger::toMonologLevel('notice'), Level::Notice); + $this->assertEquals(Logger::toMonologLevel('warning'), Level::Warning); + $this->assertEquals(Logger::toMonologLevel('error'), Level::Error); + $this->assertEquals(Logger::toMonologLevel('critical'), Level::Critical); + $this->assertEquals(Logger::toMonologLevel('alert'), Level::Alert); + $this->assertEquals(Logger::toMonologLevel('emergency'), Level::Emergency); } /** - * @covers Monolog\Logger::__construct + * @covers Logger::__construct */ public function testChannel() { @@ -86,7 +68,7 @@ public function testChannel() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testLog() { @@ -98,11 +80,11 @@ public function testLog() $logger->pushHandler($handler); - $this->assertTrue($logger->addRecord(Logger::WARNING, 'test')); + $this->assertTrue($logger->addRecord(Level::Warning, 'test')); } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testLogAlwaysHandledIfNoProcessorsArePresent() { @@ -114,11 +96,11 @@ public function testLogAlwaysHandledIfNoProcessorsArePresent() $logger->pushHandler($handler); - $this->assertTrue($logger->addRecord(Logger::WARNING, 'test')); + $this->assertTrue($logger->addRecord(Level::Warning, 'test')); } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testLogNotHandledIfProcessorsArePresent() { @@ -131,7 +113,7 @@ public function testLogNotHandledIfProcessorsArePresent() $logger->pushProcessor(fn (LogRecord $record) => $record); $logger->pushHandler($handler); - $this->assertFalse($logger->addRecord(Logger::WARNING, 'test')); + $this->assertFalse($logger->addRecord(Level::Warning, 'test')); } public function testHandlersInCtor() @@ -155,8 +137,8 @@ public function testProcessorsInCtor() } /** - * @covers Monolog\Logger::pushHandler - * @covers Monolog\Logger::popHandler + * @covers Logger::pushHandler + * @covers Logger::popHandler */ public function testPushPopHandler() { @@ -176,7 +158,7 @@ public function testPushPopHandler() } /** - * @covers Monolog\Logger::setHandlers + * @covers Logger::setHandlers */ public function testSetHandlers() { @@ -200,8 +182,8 @@ public function testSetHandlers() } /** - * @covers Monolog\Logger::pushProcessor - * @covers Monolog\Logger::popProcessor + * @covers Logger::pushProcessor + * @covers Logger::popProcessor */ public function testPushPopProcessor() { @@ -221,7 +203,7 @@ public function testPushPopProcessor() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testProcessorsAreExecuted() { @@ -239,7 +221,7 @@ public function testProcessorsAreExecuted() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testProcessorsAreCalledOnlyOnce() { @@ -270,7 +252,7 @@ public function testProcessorsAreCalledOnlyOnce() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testProcessorsNotCalledWhenNotHandled() { @@ -289,7 +271,7 @@ public function testProcessorsNotCalledWhenNotHandled() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresent() { @@ -332,7 +314,7 @@ public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresent() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresentWithAssocArray() { @@ -372,7 +354,7 @@ public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresentWit } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testBubblingWhenTheHandlerReturnsFalse() { @@ -404,7 +386,7 @@ public function testBubblingWhenTheHandlerReturnsFalse() } /** - * @covers Monolog\Logger::addRecord + * @covers Logger::addRecord */ public function testNotBubblingWhenTheHandlerReturnsTrue() { @@ -435,7 +417,7 @@ public function testNotBubblingWhenTheHandlerReturnsTrue() } /** - * @covers Monolog\Logger::isHandling + * @covers Logger::isHandling */ public function testIsHandling() { @@ -448,7 +430,7 @@ public function testIsHandling() ; $logger->pushHandler($handler1); - $this->assertFalse($logger->isHandling(Logger::DEBUG)); + $this->assertFalse($logger->isHandling(Level::Debug)); $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->any()) @@ -457,21 +439,21 @@ public function testIsHandling() ; $logger->pushHandler($handler2); - $this->assertTrue($logger->isHandling(Logger::DEBUG)); + $this->assertTrue($logger->isHandling(Level::Debug)); } /** * @dataProvider logMethodProvider - * @covers Monolog\Logger::debug - * @covers Monolog\Logger::info - * @covers Monolog\Logger::notice - * @covers Monolog\Logger::warning - * @covers Monolog\Logger::error - * @covers Monolog\Logger::critical - * @covers Monolog\Logger::alert - * @covers Monolog\Logger::emergency + * @covers Level::Debug + * @covers Level::Info + * @covers Level::Notice + * @covers Level::Warning + * @covers Level::Error + * @covers Level::Critical + * @covers Level::Alert + * @covers Level::Emergency */ - public function testLogMethods($method, $expectedLevel) + public function testLogMethods(string $method, Level $expectedLevel) { $logger = new Logger('foo'); $handler = new TestHandler; @@ -485,20 +467,20 @@ public function logMethodProvider() { return [ // PSR-3 methods - ['debug', Logger::DEBUG], - ['info', Logger::INFO], - ['notice', Logger::NOTICE], - ['warning', Logger::WARNING], - ['error', Logger::ERROR], - ['critical', Logger::CRITICAL], - ['alert', Logger::ALERT], - ['emergency', Logger::EMERGENCY], + ['debug', Level::Debug], + ['info', Level::Info], + ['notice', Level::Notice], + ['warning', Level::Warning], + ['error', Level::Error], + ['critical', Level::Critical], + ['alert', Level::Alert], + ['emergency', Level::Emergency], ]; } /** * @dataProvider setTimezoneProvider - * @covers Monolog\Logger::setTimezone + * @covers Logger::setTimezone */ public function testSetTimezone($tz) { @@ -522,8 +504,8 @@ function ($tz) { } /** - * @covers Monolog\Logger::setTimezone - * @covers Monolog\DateTimeImmutable::__construct + * @covers Logger::setTimezone + * @covers DateTimeImmutable::__construct */ public function testTimezoneIsRespectedInUTC() { @@ -544,8 +526,8 @@ public function testTimezoneIsRespectedInUTC() } /** - * @covers Monolog\Logger::setTimezone - * @covers Monolog\DateTimeImmutable::__construct + * @covers Logger::setTimezone + * @covers DateTimeImmutable::__construct */ public function testTimezoneIsRespectedInOtherTimezone() { @@ -573,8 +555,8 @@ public function tearDown(): void /** * @dataProvider useMicrosecondTimestampsProvider - * @covers Monolog\Logger::useMicrosecondTimestamps - * @covers Monolog\Logger::addRecord + * @covers Logger::useMicrosecondTimestamps + * @covers Logger::addRecord */ public function testUseMicrosecondTimestamps($micro, $assert, $assertFormat) { @@ -603,7 +585,7 @@ public function useMicrosecondTimestampsProvider() } /** - * @covers Monolog\Logger::setExceptionHandler + * @covers Logger::setExceptionHandler */ public function testSetExceptionHandler() { @@ -616,7 +598,7 @@ public function testSetExceptionHandler() } /** - * @covers Monolog\Logger::handleException + * @covers Logger::handleException */ public function testDefaultHandleException() { @@ -638,8 +620,8 @@ public function testDefaultHandleException() } /** - * @covers Monolog\Logger::handleException - * @covers Monolog\Logger::addRecord + * @covers Logger::handleException + * @covers Logger::addRecord */ public function testCustomHandleException() { @@ -689,13 +671,12 @@ public function testReset() return $reflectionProperty->getValue($object); }; - $that = $this; - $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) { - $that->assertEmpty($getProperty($bufferHandler, 'buffer')); + $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler) { + self::assertEmpty($getProperty($bufferHandler, 'buffer')); }; - $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) { + $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler) { $assertBufferOfBufferHandlerEmpty(); - $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); + self::assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); }; $logger->debug('debug1'); @@ -710,8 +691,8 @@ public function testReset() $logger->error('error2'); $logger->reset(); $assertBuffersEmpty(); - $this->assertTrue($testHandler->hasRecordThatContains('debug2', Logger::DEBUG)); - $this->assertTrue($testHandler->hasRecordThatContains('error2', Logger::ERROR)); + $this->assertTrue($testHandler->hasRecordThatContains('debug2', Level::Debug)); + $this->assertTrue($testHandler->hasRecordThatContains('error2', Level::Error)); $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); @@ -731,8 +712,8 @@ public function testReset() $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); - $this->assertTrue($testHandler->hasRecordThatContains('notice4', Logger::NOTICE)); - $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Logger::EMERGENCY)); + $this->assertTrue($testHandler->hasRecordThatContains('notice4', Level::Notice)); + $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Level::Emergency)); $this->assertNotSame($uid1, $processorUid1->getUid()); $this->assertNotSame($uid2, $processorUid2->getUid()); } diff --git a/tests/Monolog/Processor/IntrospectionProcessorTest.php b/tests/Monolog/Processor/IntrospectionProcessorTest.php index ac5b523d0..d18dbd00a 100644 --- a/tests/Monolog/Processor/IntrospectionProcessorTest.php +++ b/tests/Monolog/Processor/IntrospectionProcessorTest.php @@ -26,7 +26,7 @@ function tester($handler, $record) namespace Monolog\Processor; -use Monolog\Logger; +use Monolog\Level; use Monolog\Test\TestCase; use Monolog\Handler\TestHandler; @@ -66,11 +66,11 @@ public function testProcessorFromFunc() public function testLevelTooLow() { - $input = $this->getRecord(Logger::DEBUG); + $input = $this->getRecord(Level::Debug); $expected = $input; - $processor = new IntrospectionProcessor(Logger::CRITICAL); + $processor = new IntrospectionProcessor(Level::Critical); $actual = $processor($input); $this->assertEquals($expected, $actual); @@ -78,7 +78,7 @@ public function testLevelTooLow() public function testLevelEqual() { - $input = $this->getRecord(Logger::CRITICAL); + $input = $this->getRecord(Level::Critical); $expected = $input; $expected['extra'] = [ @@ -89,7 +89,7 @@ public function testLevelEqual() 'callType' => '->', ]; - $processor = new IntrospectionProcessor(Logger::CRITICAL); + $processor = new IntrospectionProcessor(Level::Critical); $actual = $processor($input); $this->assertEquals($expected, $actual); @@ -97,7 +97,7 @@ public function testLevelEqual() public function testLevelHigher() { - $input = $this->getRecord(Logger::EMERGENCY); + $input = $this->getRecord(Level::Emergency); $expected = $input; $expected['extra'] = [ @@ -108,7 +108,7 @@ public function testLevelHigher() 'callType' => '->', ]; - $processor = new IntrospectionProcessor(Logger::CRITICAL); + $processor = new IntrospectionProcessor(Level::Critical); $actual = $processor($input); $this->assertEquals($expected, $actual); From 14f39fe0cefc7d7683791533fa46b28d6cd235d4 Mon Sep 17 00:00:00 2001 From: Dan Hemberger <846186+hemberger@users.noreply.github.com> Date: Tue, 19 Apr 2022 12:50:32 -0700 Subject: [PATCH 422/498] Use never return typehint (#1654) The `never` return typehint was added in PHP 8.1 and can be used to indicate that a function will never return. RFC: https://wiki.php.net/rfc/noreturn_type --- src/Monolog/ErrorHandler.php | 5 +---- src/Monolog/Utils.php | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 16794be65..3fb86bce3 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -175,10 +175,7 @@ protected function defaultErrorLevelMap(): array ]; } - /** - * @phpstan-return never - */ - private function handleException(\Throwable $e): void + private function handleException(\Throwable $e): never { $level = LogLevel::ERROR; foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index e8c9d8930..9ad8ceccc 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -165,10 +165,8 @@ public static function pcreLastErrorMessage(int $code): string * @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): void + private static function throwEncodeError(int $code, $data): never { switch ($code) { case JSON_ERROR_DEPTH: From e4bb5c5cf33ba0152fde723ca94f194f9cd517fc Mon Sep 17 00:00:00 2001 From: Dan Hemberger <846186+hemberger@users.noreply.github.com> Date: Tue, 19 Apr 2022 12:51:29 -0700 Subject: [PATCH 423/498] Replace switch with match (#1655) The `match` expression is available as of PHP 8.0 and provides a more intuitive interface than `switch` when a single value is returned. Note that it performs an identity check (===) between the value and case instead of a weak equality check (==). https://www.php.net/manual/en/control-structures.match.php --- src/Monolog/ErrorHandler.php | 52 +++++++++---------------- src/Monolog/Formatter/JsonFormatter.php | 12 ++---- src/Monolog/Utils.php | 23 ++++------- 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 3fb86bce3..aecef20b7 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -260,39 +260,23 @@ public function handleFatalError(): void */ private static function codeToString($code): string { - 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'; + 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', + }; } } diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index d56185916..13bb1943f 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -98,14 +98,10 @@ public function format(LogRecord $record): string */ public function formatBatch(array $records): string { - switch ($this->batchMode) { - case static::BATCH_MODE_NEWLINES: - return $this->formatBatchNewlines($records); - - case static::BATCH_MODE_JSON: - default: - return $this->formatBatchJson($records); - } + return match ($this->batchMode) { + static::BATCH_MODE_NEWLINES => $this->formatBatchNewlines($records), + default => $this->formatBatchJson($records), + }; } /** diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 9ad8ceccc..1df3a355e 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -168,22 +168,13 @@ public static function pcreLastErrorMessage(int $code): string */ private static function throwEncodeError(int $code, $data): never { - 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'; - } + $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', + }; throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true)); } From 2695fa86cdb5236532f88207485be0474d965a71 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Apr 2022 22:10:02 +0200 Subject: [PATCH 424/498] CI fixes --- .php-cs-fixer.php | 7 +- src/Monolog/Attribute/AsMonologProcessor.php | 12 +- src/Monolog/ErrorHandler.php | 1 - src/Monolog/Formatter/ChromePHPFormatter.php | 1 - .../Formatter/ElasticsearchFormatter.php | 4 - src/Monolog/Formatter/FormatterInterface.php | 4 +- .../Formatter/GelfMessageFormatter.php | 1 - src/Monolog/Formatter/HtmlFormatter.php | 4 +- src/Monolog/Formatter/JsonFormatter.php | 5 - src/Monolog/Formatter/LineFormatter.php | 10 +- src/Monolog/Formatter/NormalizerFormatter.php | 1 - src/Monolog/Formatter/WildfireFormatter.php | 3 - src/Monolog/Handler/AbstractHandler.php | 10 +- src/Monolog/Handler/BrowserConsoleHandler.php | 4 +- src/Monolog/Handler/Curl/Util.php | 6 +- src/Monolog/Handler/DeduplicationHandler.php | 8 +- src/Monolog/Handler/ErrorLogHandler.php | 1 + src/Monolog/Handler/FilterHandler.php | 10 +- .../ChannelLevelActivationStrategy.php | 2 +- src/Monolog/Handler/FleepHookHandler.php | 2 +- .../Handler/FormattableHandlerInterface.php | 5 +- src/Monolog/Handler/HandlerInterface.php | 6 +- src/Monolog/Handler/InsightOpsHandler.php | 6 +- src/Monolog/Handler/LogEntriesHandler.php | 6 +- src/Monolog/Handler/LogglyHandler.php | 2 - src/Monolog/Handler/LogmaticHandler.php | 8 +- src/Monolog/Handler/MailHandler.php | 2 - src/Monolog/Handler/NewRelicHandler.php | 9 +- src/Monolog/Handler/OverflowHandler.php | 3 +- src/Monolog/Handler/PsrHandler.php | 4 - src/Monolog/Handler/PushoverHandler.php | 18 +-- src/Monolog/Handler/RedisHandler.php | 4 +- src/Monolog/Handler/RedisPubSubHandler.php | 2 +- src/Monolog/Handler/RollbarHandler.php | 2 +- src/Monolog/Handler/RotatingFileHandler.php | 7 +- src/Monolog/Handler/Slack/SlackRecord.php | 22 ++-- src/Monolog/Handler/SlackHandler.php | 2 +- src/Monolog/Handler/SlackWebhookHandler.php | 8 +- src/Monolog/Handler/SocketHandler.php | 4 +- src/Monolog/Handler/StreamHandler.php | 3 - src/Monolog/Handler/SyslogHandler.php | 1 - src/Monolog/Handler/SyslogUdpHandler.php | 17 +-- src/Monolog/Handler/TelegramBotHandler.php | 19 ++- src/Monolog/Handler/TestHandler.php | 1 + .../Handler/WebRequestRecognizerTrait.php | 1 - .../Handler/WhatFailureGroupHandler.php | 2 +- src/Monolog/Handler/ZendMonitorHandler.php | 7 +- src/Monolog/Level.php | 12 +- src/Monolog/LevelName.php | 11 +- src/Monolog/LogRecord.php | 2 + src/Monolog/Logger.php | 3 +- .../Processor/IntrospectionProcessor.php | 2 +- src/Monolog/Processor/MemoryProcessor.php | 1 - src/Monolog/Processor/UidProcessor.php | 2 +- src/Monolog/SignalHandler.php | 5 +- src/Monolog/Utils.php | 10 +- .../Attribute/AsMonologProcessorTest.php | 2 +- .../Formatter/ElasticaFormatterTest.php | 1 - .../Formatter/GelfMessageFormatterTest.php | 2 +- tests/Monolog/Formatter/JsonFormatterTest.php | 7 +- .../Formatter/MongoDBFormatterTest.php | 1 - .../Formatter/NormalizerFormatterTest.php | 7 +- .../Monolog/Formatter/ScalarFormatterTest.php | 2 +- .../Monolog/Handler/ChromePHPHandlerTest.php | 12 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 2 +- tests/Monolog/Handler/ElasticaHandlerTest.php | 1 - tests/Monolog/Handler/FilterHandlerTest.php | 6 +- .../Monolog/Handler/InsightOpsHandlerTest.php | 4 +- tests/Monolog/Handler/PsrHandlerTest.php | 2 +- tests/Monolog/Handler/RollbarHandlerTest.php | 8 +- .../Handler/RotatingFileHandlerTest.php | 10 +- .../Monolog/Handler/Slack/SlackRecordTest.php | 112 +++++++++--------- tests/Monolog/Handler/SlackHandlerTest.php | 20 ++-- .../Handler/SlackWebhookHandlerTest.php | 48 ++++---- tests/Monolog/Handler/SocketHandlerTest.php | 2 +- tests/Monolog/Handler/StreamHandlerTest.php | 1 - .../Monolog/Handler/SyslogUdpHandlerTest.php | 6 +- .../Handler/TelegramBotHandlerTest.php | 2 - .../Handler/WhatFailureGroupHandlerTest.php | 4 +- .../Handler/ZendMonitorHandlerTest.php | 1 - tests/Monolog/LoggerTest.php | 6 +- tests/Monolog/Processor/WebProcessorTest.php | 8 +- tests/Monolog/PsrLogCompatTest.php | 57 +++++---- tests/Monolog/SignalHandlerTest.php | 72 +++++------ tests/Monolog/UtilsTest.php | 29 +++-- 85 files changed, 351 insertions(+), 399 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 2638adc7a..839368490 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -21,9 +21,10 @@ return $config->setRules(array( '@PSR2' => true, // some rules disabled as long as 1.x branch is maintained - 'binary_operator_spaces' => array( + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => [ 'default' => null, - ), + ], 'blank_line_before_statement' => ['statements' => ['continue', 'declare', 'return', 'throw', 'try']], 'cast_spaces' => ['space' => 'single'], 'header_comment' => ['header' => $header], @@ -35,6 +36,7 @@ 'no_extra_blank_lines' => true, 'no_leading_import_slash' => true, 'no_leading_namespace_whitespace' => true, + 'no_superfluous_phpdoc_tags' => ['allow_mixed' => true], 'no_trailing_comma_in_singleline_array' => true, 'no_unused_imports' => true, 'no_whitespace_in_blank_line' => true, @@ -48,7 +50,6 @@ 'phpdoc_trim' => true, //'phpdoc_types' => true, 'psr_autoloading' => ['dir' => 'src'], - //'array_syntax' => array('syntax' => 'short'), 'declare_strict_types' => true, 'single_blank_line_before_namespace' => true, 'standardize_not_equals' => true, diff --git a/src/Monolog/Attribute/AsMonologProcessor.php b/src/Monolog/Attribute/AsMonologProcessor.php index b52d07761..9781efe06 100644 --- a/src/Monolog/Attribute/AsMonologProcessor.php +++ b/src/Monolog/Attribute/AsMonologProcessor.php @@ -13,9 +13,9 @@ /** * 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. */ @@ -23,9 +23,9 @@ class AsMonologProcessor { /** - * @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 ?string $channel = null, @@ -33,4 +33,4 @@ public function __construct( public ?string $method = null, ) { } -} \ No newline at end of file +} diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index aecef20b7..78c363423 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -61,7 +61,6 @@ public function __construct(LoggerInterface $logger) * * By default it will handle errors, exceptions and fatal errors * - * @param LoggerInterface $logger * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling * @param array|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 diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 0551e1a29..8cc5abc8a 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\Logger; use Monolog\LogRecord; /** diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 67d03f090..0709a8fe5 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -56,8 +56,6 @@ public function format(LogRecord $record) /** * Getter index - * - * @return string */ public function getIndex(): string { @@ -66,8 +64,6 @@ public function getIndex(): string /** * Getter type - * - * @return string */ public function getType(): string { diff --git a/src/Monolog/Formatter/FormatterInterface.php b/src/Monolog/Formatter/FormatterInterface.php index d65ae3653..3413a4b05 100644 --- a/src/Monolog/Formatter/FormatterInterface.php +++ b/src/Monolog/Formatter/FormatterInterface.php @@ -24,7 +24,7 @@ interface FormatterInterface * Formats a log record. * * @param LogRecord $record A record to format - * @return mixed The formatted record + * @return mixed The formatted record */ public function format(LogRecord $record); @@ -32,7 +32,7 @@ public function format(LogRecord $record); * Formats a set of log records. * * @param array $records A set of records to format - * @return mixed The formatted set of records + * @return mixed The formatted set of records */ public function formatBatch(array $records); } diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 5d2d9de89..d6c5d6738 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\Logger; use Gelf\Message; use Monolog\Utils; use Monolog\LogRecord; diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 2841a38ec..8a8c2ccb4 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\Logger; use Monolog\Utils; use Monolog\LogRecord; @@ -70,8 +69,7 @@ protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): /** * Create a HTML h1 tag * - * @param string $title Text to be in the h1 - * @return string + * @param string $title Text to be in the h1 */ protected function addTitle(string $title, Level $level): string { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 13bb1943f..8f8fd7e72 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -105,7 +105,6 @@ public function formatBatch(array $records): string } /** - * @return self */ public function includeStacktraces(bool $include = true): self { @@ -142,10 +141,6 @@ protected function formatBatchNewlines(array $records): string /** * Normalizes given $data. - * - * @param mixed $data - * - * @return mixed */ protected function normalize(mixed $data, int $depth = 0): mixed { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 713071838..99cd60377 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -36,10 +36,9 @@ class LineFormatter extends NormalizerFormatter protected $includeStacktraces; /** - * @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 + * @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 */ public function __construct(?string $format = null, ?string $dateFormat = null, bool $allowInlineLineBreaks = false, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = false) { @@ -119,6 +118,7 @@ public function format(LogRecord $record): string $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)); } } @@ -177,7 +177,7 @@ protected function replaceNewlines(string $str): string { if ($this->allowInlineLineBreaks) { if (0 === strpos($str, '{')) { - return str_replace(array('\r', '\n'), array("\r", "\n"), $str); + return str_replace(['\r', '\n'], ["\r", "\n"], $str); } return $str; diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index cc45fe50b..2a92221e4 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -149,7 +149,6 @@ protected function normalizeRecord(LogRecord $record): array } /** - * @param mixed $data * @return null|scalar|array */ protected function normalize(mixed $data, int $depth = 0): mixed diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 7badab35a..ae2b85ee7 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\Logger; use Monolog\LogRecord; /** @@ -56,8 +55,6 @@ private function toWildfireLevel(Level $level): string /** * {@inheritDoc} - * - * @return string */ public function format(LogRecord $record): string { diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 8d2486939..53b9600c5 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -31,7 +31,7 @@ abstract class AbstractHandler extends Handler implements ResettableInterface /** * @param int|string|Level|LevelName|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 bool $bubble Whether the messages that are handled can bubble up the stack or not * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ @@ -52,8 +52,7 @@ public function isHandling(LogRecord $record): bool /** * Sets minimum logging level at which this handler will be triggered. * - * @param Level|LevelName|LogLevel::* $level Level or level name - * @return self + * @param Level|LevelName|LogLevel::* $level Level or level name * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ @@ -75,9 +74,8 @@ public function getLevel(): Level /** * Sets the bubbling behavior. * - * @param bool $bubble true means that this handler allows bubbling. - * false means that bubbling is not permitted. - * @return self + * @param bool $bubble true means that this handler allows bubbling. + * false means that bubbling is not permitted. */ public function setBubble(bool $bubble): self { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 7c560de8c..e75e3650a 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -19,9 +19,6 @@ 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 @@ -235,6 +232,7 @@ private static function handleCustomStyles(string $style, string $string): strin if (null === $style) { $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); } diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 73a7660bd..a8c02da97 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -34,10 +34,8 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param CurlHandle $ch curl handler - * @param int $retries - * @param bool $closeAfterDone - * @return bool|string @see curl_exec + * @param CurlHandle $ch curl handler + * @return bool|string @see curl_exec */ public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) { diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index f1f01e3b4..e8c171ccb 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -60,11 +60,11 @@ class DeduplicationHandler extends BufferHandler private $gc = false; /** - * @param HandlerInterface $handler Handler. - * @param string $deduplicationStore The file/path where the deduplication log should be kept + * @param HandlerInterface $handler Handler. + * @param string $deduplicationStore The file/path where the deduplication log should be kept * @param int|string|Level|LevelName|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 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|value-of|Level|LevelName|LogLevel::* $deduplicationLevel */ diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index a80b63adf..6847e690c 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -83,6 +83,7 @@ protected function write(LogRecord $record): void $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) { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index b5dec9380..908216a15 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -57,10 +57,10 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|string|Level|LevelName|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided - * @param int|string|Level|LevelName|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 int|string|Level|LevelName|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 * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel @@ -81,12 +81,12 @@ public function __construct($handler, int|string|Level|LevelName|array $minLevel */ public function getAcceptedLevels(): array { - return array_map(fn(int $level) => Level::from($level), array_keys($this->acceptedLevels)); + return array_map(fn (int $level) => Level::from($level), array_keys($this->acceptedLevels)); } /** * @param int|string|Level|LevelName|LogLevel::*|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided - * @param int|string|Level|LevelName|LogLevel::* $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array + * @param int|string|Level|LevelName|LogLevel::* $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 4da75dff7..0aafa7b21 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -47,7 +47,7 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private array $channelToActionLevel; /** - * @param int|string|Level|LevelName|LogLevel::* $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param int|string|Level|LevelName|LogLevel::* $defaultActionLevel The default action level to be used if the record's category doesn't match any * @param array $channelToActionLevel An array that maps channel names to action levels. * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $defaultActionLevel diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 9f84c5bb2..4b51b6a9a 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -41,7 +41,7 @@ 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( diff --git a/src/Monolog/Handler/FormattableHandlerInterface.php b/src/Monolog/Handler/FormattableHandlerInterface.php index fc1693cd0..72da59e1c 100644 --- a/src/Monolog/Handler/FormattableHandlerInterface.php +++ b/src/Monolog/Handler/FormattableHandlerInterface.php @@ -23,15 +23,12 @@ interface FormattableHandlerInterface /** * Sets the formatter. * - * @param FormatterInterface $formatter - * @return HandlerInterface self + * @return HandlerInterface self */ public function setFormatter(FormatterInterface $formatter): HandlerInterface; /** * Gets the formatter. - * - * @return FormatterInterface */ public function getFormatter(): FormatterInterface; } diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index 53bf28bf2..83905c323 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -30,8 +30,6 @@ interface HandlerInterface * for a given record. * * @param LogRecord $record Partial log record having only a level initialized - * - * @return bool */ public function isHandling(LogRecord $record): bool; @@ -46,8 +44,8 @@ public function isHandling(LogRecord $record): bool; * 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. + * @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. */ public function handle(LogRecord $record): bool; diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index f66321879..ca120e1e5 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -28,9 +28,9 @@ class InsightOpsHandler extends SocketHandler 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 */ diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index ffa2b0a94..5695f5244 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -25,9 +25,9 @@ class LogEntriesHandler extends SocketHandler 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 */ diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 07cad3914..e451ddf02 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -63,7 +63,6 @@ public function __construct(string $token, $level = Level::Debug, bool $bubble = /** * Loads and returns the shared curl handler for the given endpoint. * - * @param string $endpoint * * @return CurlHandle */ @@ -79,7 +78,6 @@ protected function getCurlHandler(string $endpoint) /** * Starts a fresh curl session for the given endpoint and returns its handler. * - * @param string $endpoint * * @return CurlHandle */ diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index b82bfbf19..453647268 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -37,10 +37,10 @@ class LogmaticHandler extends SocketHandler 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 */ diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index decd260cc..69808899e 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -83,8 +83,6 @@ protected function isHtmlBody(string $body): bool /** * Gets the default formatter. - * - * @return FormatterInterface */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 3b3ae7588..397606655 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -52,10 +52,6 @@ class NewRelicHandler extends AbstractProcessingHandler /** * {@inheritDoc} - * - * @param string|null $appName - * @param bool $explodeArrays - * @param string|null $transactionName */ public function __construct( $level = Level::Error, @@ -123,8 +119,6 @@ protected function write(LogRecord $record): void /** * Checks whether the NewRelic extension is enabled in the system. - * - * @return bool */ protected function isNewRelicEnabled(): bool { @@ -178,8 +172,7 @@ protected function setNewRelicTransactionName(string $transactionName): void } /** - * @param string $key - * @param mixed $value + * @param mixed $value */ protected function setNewRelicParameter(string $key, $value): void { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index d1f42781e..bd62316ec 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -51,8 +51,7 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter private $buffer = []; /** - * @param HandlerInterface $handler - * @param array $thresholdMap Dictionary of log level value => threshold + * @param array $thresholdMap Dictionary of log level value => threshold */ public function __construct( HandlerInterface $handler, diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 30369e27a..6b45c3d6f 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -70,8 +70,6 @@ public function handle(LogRecord $record): bool /** * Sets the formatter. - * - * @param FormatterInterface $formatter */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -82,8 +80,6 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface /** * Gets the formatter. - * - * @return FormatterInterface */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 0e3db9dce..c2a3129af 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -77,15 +77,15 @@ class PushoverHandler extends SocketHandler ]; /** - * @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 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|LevelName|LogLevel::* $highPriorityLevel The minimum logging level at which this handler will start * sending "high priority" requests to the Pushover API diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index eecbf837a..a559f5ffd 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -38,8 +38,8 @@ class RedisHandler extends AbstractProcessingHandler /** * @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 + * @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($redis, string $key, $level = Level::Debug, bool $bubble = true, int $capSize = 0) { diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 01138cc7c..004ca6058 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -36,7 +36,7 @@ class RedisPubSubHandler extends AbstractProcessingHandler /** * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance - * @param string $key The channel key to publish records to + * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true) { diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 1f082cd61..fd5d127d6 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -86,7 +86,7 @@ protected function write(LogRecord $record): void { if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors - register_shutdown_function(array($this, 'close')); + register_shutdown_function([$this, 'close']); $this->initialized = true; } diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index e7d27aace..c0d491db3 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -45,10 +45,9 @@ class RotatingFileHandler extends StreamHandler protected $dateFormat; /** - * @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 + * @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, $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 0a87babf6..141342bd1 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -97,7 +97,7 @@ public function __construct( ?string $userIcon = null, bool $useShortAttachment = false, bool $includeContextAndExtra = false, - array $excludeFields = array(), + array $excludeFields = [], FormatterInterface $formatter = null ) { $this @@ -123,7 +123,7 @@ public function __construct( */ public function getSlackData(LogRecord $record): array { - $dataArray = array(); + $dataArray = []; if ($this->username) { $dataArray['username'] = $this->username; @@ -142,16 +142,16 @@ public function getSlackData(LogRecord $record): array $recordData = $this->removeExcludedFields($record); if ($this->useAttachment) { - $attachment = array( + $attachment = [ 'fallback' => $message, 'text' => $message, 'color' => $this->getAttachmentColor($record->level), - 'fields' => array(), - 'mrkdwn_in' => array('fields'), + 'fields' => [], + 'mrkdwn_in' => ['fields'], 'ts' => $recordData['datetime']->getTimestamp(), 'footer' => $this->username, 'footer_icon' => $this->userIcon, - ); + ]; if ($this->useShortAttachment) { $attachment['title'] = $recordData['level_name']; @@ -161,7 +161,7 @@ public function getSlackData(LogRecord $record): array } if ($this->includeContextAndExtra) { - foreach (array('extra', 'context') as $key) { + foreach (['extra', 'context'] as $key) { if (empty($recordData[$key])) { continue; } @@ -181,7 +181,7 @@ public function getSlackData(LogRecord $record): array } } - $dataArray['attachments'] = array($attachment); + $dataArray['attachments'] = [$attachment]; } else { $dataArray['text'] = $message; } @@ -323,11 +323,11 @@ private function generateAttachmentField(string $title, $value): array ? sprintf('```%s```', substr($this->stringify($value), 0, 1990)) : $value; - return array( + return [ 'title' => ucfirst($title), 'value' => $value, 'short' => false, - ); + ]; } /** @@ -342,7 +342,7 @@ private function generateAttachmentFields(array $data): array /** @var array $normalized */ $normalized = $this->normalizerFormatter->normalizeValue($data); - $fields = array(); + $fields = []; foreach ($normalized as $key => $value) { $fields[] = $this->generateAttachmentField((string) $key, $value); } diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index fb85cd014..063606a4b 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -58,7 +58,7 @@ public function __construct( bool $bubble = true, bool $useShortAttachment = false, bool $includeContextAndExtra = false, - array $excludeFields = array(), + array $excludeFields = [], bool $persistent = false, float $timeout = 0.0, float $writingTimeout = 10.0, diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index c98c1c3d9..c0f2aaba0 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -57,7 +57,7 @@ public function __construct( bool $includeContextAndExtra = false, $level = Level::Critical, bool $bubble = true, - array $excludeFields = array() + array $excludeFields = [] ) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the SlackWebhookHandler'); @@ -97,13 +97,13 @@ protected function write(LogRecord $record): void $postString = Utils::jsonEncode($postData); $ch = curl_init(); - $options = array( + $options = [ CURLOPT_URL => $this->webhookUrl, CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => array('Content-type: application/json'), + CURLOPT_HTTPHEADER => ['Content-type: application/json'], CURLOPT_POSTFIELDS => $postString, - ); + ]; if (defined('CURLOPT_SAFE_UPLOAD')) { $options[CURLOPT_SAFE_UPLOAD] = true; } diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 727666c45..517c12f80 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -54,7 +54,7 @@ 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, @@ -211,8 +211,6 @@ public function getTimeout(): float /** * Get current local writing timeout - * - * @return float */ public function getWritingTimeout(): float { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 328c4ea65..a63d0140f 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -105,8 +105,6 @@ public function getStream() /** * Return the stream URL if it was configured with a URL and not an active resource - * - * @return string|null */ public function getUrl(): ?string { @@ -114,7 +112,6 @@ public function getUrl(): ?string } /** - * @return int */ public function getStreamChunkSize(): int { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 73d286811..04b3f07e6 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -36,7 +36,6 @@ class SyslogHandler extends AbstractSyslogHandler 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 */ diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 7fe92b149..3c0705213 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -30,11 +30,11 @@ class SyslogUdpHandler extends AbstractSyslogHandler const RFC5424e = 2; /** @var array */ - private $dateFormats = array( + private $dateFormats = [ self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, self::RFC5424e => \DateTime::RFC3339_EXTENDED, - ); + ]; /** @var UdpSocket */ protected $socket; @@ -44,12 +44,12 @@ class SyslogUdpHandler extends AbstractSyslogHandler 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 @@ -97,6 +97,7 @@ private function splitMessageIntoLines($message): array $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)); } diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 0d22455c3..3125e8e66 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -96,24 +96,23 @@ class TelegramBotHandler extends AbstractProcessingHandler 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 = Level::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'); } @@ -157,7 +156,6 @@ public function disableNotification(bool $disableNotification = null): self /** * 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 @@ -169,7 +167,6 @@ public function splitLongMessages(bool $splitLongMessages = false): self /** * 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 @@ -199,7 +196,7 @@ public function handleBatch(array $records): void } if (!empty($messages)) { - $this->send((string)$this->getFormatter()->formatBatch($messages)); + $this->send((string) $this->getFormatter()->formatBatch($messages)); } } @@ -213,7 +210,6 @@ protected function write(LogRecord $record): void /** * Send request to @link https://api.telegram.org/bot on SendMessage action. - * @param string $message */ protected function send(string $message): void { @@ -256,7 +252,6 @@ protected function sendCurl(string $message): void /** * Handle a message that is too long: truncates or splits into several - * @param string $message * @return string[] */ private function handleMessageLength(string $message): array diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 531435981..8c23d4161 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -198,6 +198,7 @@ public function __call($method, $args) $callback = [$this, $genericMethod]; if (is_callable($callback)) { $args[] = $level; + return call_user_func_array($callback, $args); } } diff --git a/src/Monolog/Handler/WebRequestRecognizerTrait.php b/src/Monolog/Handler/WebRequestRecognizerTrait.php index c81835288..9c12c3d56 100644 --- a/src/Monolog/Handler/WebRequestRecognizerTrait.php +++ b/src/Monolog/Handler/WebRequestRecognizerTrait.php @@ -15,7 +15,6 @@ trait WebRequestRecognizerTrait { /** * Checks if PHP's serving a web request - * @return bool */ protected function isWebRequest(): bool { diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index b26f21f6b..8d4dd2b8e 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -48,7 +48,7 @@ public function handle(LogRecord $record): bool public function handleBatch(array $records): void { if ($this->processors) { - $processed = array(); + $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 32f9c6112..e63356337 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -55,7 +55,6 @@ protected function toZendMonitorLevel(Level $level): int }; } - /** * {@inheritDoc} */ @@ -71,10 +70,10 @@ protected function write(LogRecord $record): void /** * Write to Zend Monitor Events - * @param string $type Text displayed in "Class Name (custom)" field - * @param string $message Text displayed in "Error String" + * @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) + * @param int $severity Set the event severity level (-1,0,1) */ protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void { diff --git a/src/Monolog/Level.php b/src/Monolog/Level.php index 70c394862..a4c295366 100644 --- a/src/Monolog/Level.php +++ b/src/Monolog/Level.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog; @@ -97,7 +106,6 @@ public function toLevelName(): LevelName } /** - * @return string * @phpstan-return \Psr\Log\LogLevel::* */ public function toPsrLogLevel(): string diff --git a/src/Monolog/LevelName.php b/src/Monolog/LevelName.php index 7d26d9f18..b7ff371ce 100644 --- a/src/Monolog/LevelName.php +++ b/src/Monolog/LevelName.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog; diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php index 47fc66c73..df6d0cf8d 100644 --- a/src/Monolog/LogRecord.php +++ b/src/Monolog/LogRecord.php @@ -50,11 +50,13 @@ public function offsetSet(mixed $offset, mixed $value): void } $this->extra = $value; + return; } if ($offset === 'formatted') { $this->formatted = $value; + return; } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index bf985d2c6..e38f87d1d 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -237,7 +237,6 @@ public function pushProcessor(callable $callback): self * Removes the processor on top of the stack and returns it. * * @throws \LogicException If empty processor stack - * @return callable */ public function popProcessor(): callable { @@ -379,7 +378,7 @@ public function reset(): void * Converts PSR-3 levels to Monolog ones if necessary * * @param int|string|Level|LevelName|LogLevel::* $level Level number (monolog) or name (PSR-3) - * @throws \Psr\Log\InvalidArgumentException If level is not defined + * @throws \Psr\Log\InvalidArgumentException If level is not defined * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 357bd71fe..8ff10818d 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -44,7 +44,7 @@ class IntrospectionProcessor implements ProcessorInterface /** * @param string|int|Level|LevelName $level The minimum logging level at which this Processor will be triggered - * @param string[] $skipClassesPartials + * @param string[] $skipClassesPartials * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level */ diff --git a/src/Monolog/Processor/MemoryProcessor.php b/src/Monolog/Processor/MemoryProcessor.php index 227deb7c8..89baadbf0 100644 --- a/src/Monolog/Processor/MemoryProcessor.php +++ b/src/Monolog/Processor/MemoryProcessor.php @@ -41,7 +41,6 @@ public function __construct(bool $realUsage = true, bool $useFormatting = true) /** * 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) diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 973b317e6..835307ef4 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -57,7 +57,7 @@ public function reset() } /** - * @param positive-int $length + * @param positive-int $length * @return non-empty-string */ private function generateUid(int $length): string diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index b9f92abd2..8c0227305 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -38,10 +38,7 @@ public function __construct(LoggerInterface $logger) } /** - * @param int|string|Level|LevelName $level Level or level name - * @param bool $callPrevious - * @param bool $restartSyscalls - * @param bool|null $async + * @param int|string|Level|LevelName $level Level or level name * @return $this * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 1df3a355e..4a1d9e98c 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -122,7 +122,7 @@ public static function handleJsonError(int $code, $data, ?int $encodeFlags = nul if (is_string($data)) { self::detectAndCleanUtf8($data); } elseif (is_array($data)) { - array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8')); + array_walk_recursive($data, ['Monolog\Utils', 'detectAndCleanUtf8']); } else { self::throwEncodeError($code, $data); } @@ -206,6 +206,7 @@ function ($m) { ); if (!is_string($data)) { $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode)); } $data = str_replace( @@ -219,8 +220,8 @@ function ($m) { /** * 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) { @@ -241,8 +242,10 @@ public static function expandIniShorthandBytes($val) switch (strtolower($match['unit'] ?? '')) { case 'g': $val *= 1024; + // no break case 'm': $val *= 1024; + // no break case 'k': $val *= 1024; } @@ -254,6 +257,7 @@ public static function getRecordMessageForException(LogRecord $record): string { $context = ''; $extra = ''; + try { if ($record->context) { $context = "\nContext: " . json_encode($record->context, JSON_THROW_ON_ERROR); diff --git a/tests/Monolog/Attribute/AsMonologProcessorTest.php b/tests/Monolog/Attribute/AsMonologProcessorTest.php index fe93d2801..b0af8f6fb 100644 --- a/tests/Monolog/Attribute/AsMonologProcessorTest.php +++ b/tests/Monolog/Attribute/AsMonologProcessorTest.php @@ -30,4 +30,4 @@ public function test(): void $this->assertNull($asMonologProcessor->handler); $this->assertNull($asMonologProcessor->method); } -} \ No newline at end of file +} diff --git a/tests/Monolog/Formatter/ElasticaFormatterTest.php b/tests/Monolog/Formatter/ElasticaFormatterTest.php index 64b642861..2698b60a4 100644 --- a/tests/Monolog/Formatter/ElasticaFormatterTest.php +++ b/tests/Monolog/Formatter/ElasticaFormatterTest.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\LogRecord; use Monolog\Test\TestCase; class ElasticaFormatterTest extends TestCase diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index b33687a68..eb72aa64c 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -219,7 +219,7 @@ public function testFormatWithUnlimitedLength() $length = 200; foreach ($messageArray as $key => $value) { - if (!in_array($key, array('level', 'timestamp'))) { + if (!in_array($key, ['level', 'timestamp'])) { $length += strlen($value); } } diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index cab71f936..d8334f138 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -205,9 +205,6 @@ private function assertContextContainsFormattedException($expected, $actual) } /** - * @param JsonFormatter $formatter - * @param \Throwable $exception - * * @return string */ private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \Throwable $exception) @@ -265,7 +262,7 @@ public function testNormalizeHandleLargeArraysWithExactly1000Items() Level::Critical, 'bar', channel: 'test', - context: array($largeArray), + context: [$largeArray], )); $this->assertCount(1000, $res['context'][0]); @@ -281,7 +278,7 @@ public function testNormalizeHandleLargeArrays() Level::Critical, 'bar', channel: 'test', - context: array($largeArray), + context: [$largeArray], )); $this->assertCount(1001, $res['context'][0]); diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 73d7ea992..2a58190d0 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -274,6 +274,5 @@ public function testBsonTypes() $this->assertInstanceOf(ObjectId::class, $formattedRecord['context']['objectid']); $this->assertInstanceOf(UTCDateTime::class, $formattedRecord['context']['nest']['timestamp']); $this->assertInstanceOf(Regex::class, $formattedRecord['context']['nest']['regex']); - } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index e13bb2ce3..0c61cf227 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -338,7 +338,7 @@ public function testMaxNormalizeItemCountWith2ItemsMax() 'message' => 'Foo', 'code' => 0, ]], - "..." => "Over 2 items (7 total), aborting normalization" + "..." => "Over 2 items (7 total), aborting normalization", ], $message ); @@ -372,9 +372,6 @@ public function testExceptionTraceWithArgs() } /** - * @param NormalizerFormatter $formatter - * @param \Throwable $exception - * * @return string */ private function formatRecordWithExceptionInContext(NormalizerFormatter $formatter, \Throwable $exception) @@ -393,7 +390,7 @@ public function testExceptionTraceDoesNotLeakCallUserFuncArgs() { try { $arg = new TestInfoLeak; - call_user_func(array($this, 'throwHelper'), $arg, $dt = new \DateTime()); + call_user_func([$this, 'throwHelper'], $arg, $dt = new \DateTime()); } catch (\Exception $e) { } diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index 21f9d6cd2..e75dd5d25 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -95,7 +95,7 @@ public function testFormatWithExceptionContext() 'code' => $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), 'trace' => $this->buildTrace($exception), - ] + ], ]), $formatted['context']); } } diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 5600cd288..722e0350c 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -54,12 +54,12 @@ public function testHeaders($agent) public static function agentsProvider() { - return array( - array('Monolog Test; Chrome/1.0'), - array('Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'), - array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36'), - array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36'), - ); + return [ + ['Monolog Test; Chrome/1.0'], + ['Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'], + ['Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/56.0.2924.76 Chrome/56.0.2924.76 Safari/537.36'], + ['Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome Safari/537.36'], + ]; } public function testHeadersOverflow() diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 2b237bfa5..b206ef845 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -70,7 +70,7 @@ public function testHandle() $handler->setFormatter($formatter); if ($this->isV3) { - $expFormatted = array('foo' => array('N' => 1), 'bar' => array('N' => 2)); + $expFormatted = ['foo' => ['N' => 1], 'bar' => ['N' => 2]]; } else { $expFormatted = $formatted; } diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 706e417f3..8791c7058 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -15,7 +15,6 @@ use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; use Monolog\Level; -use Monolog\LogRecord; use Elastica\Client; use Elastica\Request; use Elastica\Response; diff --git a/tests/Monolog/Handler/FilterHandlerTest.php b/tests/Monolog/Handler/FilterHandlerTest.php index 4fa2eb79e..799ee169b 100644 --- a/tests/Monolog/Handler/FilterHandlerTest.php +++ b/tests/Monolog/Handler/FilterHandlerTest.php @@ -178,8 +178,8 @@ public function testHandleEmptyBatch() { $test = new TestHandler(); $handler = new FilterHandler($test); - $handler->handleBatch(array()); - $this->assertSame(array(), $test->getRecords()); + $handler->handleBatch([]); + $this->assertSame([], $test->getRecords()); } /** @@ -202,6 +202,6 @@ public function testResetTestHandler() $this->assertFalse($test->hasInfoRecords()); $this->assertFalse($test->hasInfoRecords()); - $this->assertSame(array(), $test->getRecords()); + $this->assertSame([], $test->getRecords()); } } diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index 8663d7779..d7e884e0b 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -55,10 +55,10 @@ public function testWriteBatchContent() private function createHandler() { $useSSL = extension_loaded('openssl'); - $args = array('testToken', 'us', $useSSL, Level::Debug, true); + $args = ['testToken', 'us', $useSSL, Level::Debug, true]; $this->resource = fopen('php://memory', 'a'); $this->handler = $this->getMockBuilder(InsightOpsHandler::class) - ->onlyMethods(array('fsockopen', 'streamSetTimeout', 'closeSocket')) + ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->setConstructorArgs($args) ->getMock(); diff --git a/tests/Monolog/Handler/PsrHandlerTest.php b/tests/Monolog/Handler/PsrHandlerTest.php index e06aa20e9..919261e13 100644 --- a/tests/Monolog/Handler/PsrHandlerTest.php +++ b/tests/Monolog/Handler/PsrHandlerTest.php @@ -24,7 +24,7 @@ class PsrHandlerTest extends TestCase public function logLevelProvider() { return array_map( - fn(Level $level) => [$level->toLevelName(), $level], + fn (Level $level) => [$level->toLevelName(), $level], Level::cases() ); } diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index da267a879..2b252ef5b 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -59,14 +59,14 @@ public function testExceptionLogLevel() private function setupRollbarLoggerMock() { - $config = array( + $config = [ 'access_token' => 'ad865e76e7fb496fab096ac07b1dbabb', 'environment' => 'test', - ); + ]; $this->rollbarLogger = $this->getMockBuilder(RollbarLogger::class) - ->setConstructorArgs(array($config)) - ->onlyMethods(array('log')) + ->setConstructorArgs([$config]) + ->onlyMethods(['log']) ->getMock(); $this->rollbarLogger diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 5446f40e8..8e131cd6f 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -218,16 +218,16 @@ public function testRotationWhenSimilarFileNamesExist($dateFormat) public function rotationWhenSimilarFilesExistTests() { - return array( + return [ 'Rotation is triggered when the file of the current day is not present but similar exists' - => array(RotatingFileHandler::FILE_PER_DAY), + => [RotatingFileHandler::FILE_PER_DAY], 'Rotation is triggered when the file of the current month is not present but similar exists' - => array(RotatingFileHandler::FILE_PER_MONTH), + => [RotatingFileHandler::FILE_PER_MONTH], 'Rotation is triggered when the file of the current year is not present but similar exists' - => array(RotatingFileHandler::FILE_PER_YEAR), - ); + => [RotatingFileHandler::FILE_PER_YEAR], + ]; } public function testReuseCurrentFile() diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index e6c88fe03..eaa0ae5a2 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -22,16 +22,16 @@ class SlackRecordTest extends TestCase { public function dataGetAttachmentColor() { - return array( - array(Level::Debug, SlackRecord::COLOR_DEFAULT), - array(Level::Info, SlackRecord::COLOR_GOOD), - array(Level::Notice, SlackRecord::COLOR_GOOD), - array(Level::Warning, SlackRecord::COLOR_WARNING), - array(Level::Error, SlackRecord::COLOR_DANGER), - array(Level::Critical, SlackRecord::COLOR_DANGER), - array(Level::Alert, SlackRecord::COLOR_DANGER), - array(Level::Emergency, SlackRecord::COLOR_DANGER), - ); + return [ + [Level::Debug, SlackRecord::COLOR_DEFAULT], + [Level::Info, SlackRecord::COLOR_GOOD], + [Level::Notice, SlackRecord::COLOR_GOOD], + [Level::Warning, SlackRecord::COLOR_WARNING], + [Level::Error, SlackRecord::COLOR_DANGER], + [Level::Critical, SlackRecord::COLOR_DANGER], + [Level::Alert, SlackRecord::COLOR_DANGER], + [Level::Emergency, SlackRecord::COLOR_DANGER], + ]; } /** @@ -70,16 +70,16 @@ public function testNoUsernameByDefault() */ public function dataStringify() { - $multipleDimensions = array(array(1, 2)); - $numericKeys = array('library' => 'monolog'); - $singleDimension = array(1, 'Hello', 'Jordi'); - - return array( - array(array(), '[]'), - array($multipleDimensions, json_encode($multipleDimensions, JSON_PRETTY_PRINT)), - array($numericKeys, json_encode($numericKeys, JSON_PRETTY_PRINT)), - array($singleDimension, json_encode($singleDimension)), - ); + $multipleDimensions = [[1, 2]]; + $numericKeys = ['library' => 'monolog']; + $singleDimension = [1, 'Hello', 'Jordi']; + + return [ + [[], '[]'], + [$multipleDimensions, json_encode($multipleDimensions, JSON_PRETTY_PRINT)], + [$numericKeys, json_encode($numericKeys, JSON_PRETTY_PRINT)], + [$singleDimension, json_encode($singleDimension)], + ]; } /** @@ -179,7 +179,7 @@ public function testTextEqualsFormatterOutput() })); $message = 'Test message'; - $record = new SlackRecord(null, null, false, null, false, false, array(), $formatter); + $record = new SlackRecord(null, null, false, null, false, false, [], $formatter); $data = $record->getSlackData($this->getRecord(Level::Warning, $message)); $this->assertArrayHasKey('text', $data); @@ -232,21 +232,21 @@ public function testAddsShortAttachmentWithoutContextAndExtra() $level = Level::Error; $levelName = LevelName::fromLevel($level)->value; $record = new SlackRecord(null, null, true, null, true); - $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); + $data = $record->getSlackData($this->getRecord($level, 'test', ['test' => 1])); $attachment = $data['attachments'][0]; $this->assertArrayHasKey('title', $attachment); $this->assertArrayHasKey('fields', $attachment); $this->assertSame($levelName, $attachment['title']); - $this->assertSame(array(), $attachment['fields']); + $this->assertSame([], $attachment['fields']); } public function testAddsShortAttachmentWithContextAndExtra() { $level = Level::Error; $levelName = LevelName::fromLevel($level)->value; - $context = array('test' => 1); - $extra = array('tags' => array('web')); + $context = ['test' => 1]; + $extra = ['tags' => ['web']]; $record = new SlackRecord(null, null, true, null, true, true); $loggerRecord = $this->getRecord($level, 'test', $context); $loggerRecord['extra'] = $extra; @@ -258,18 +258,18 @@ public function testAddsShortAttachmentWithContextAndExtra() $this->assertCount(2, $attachment['fields']); $this->assertSame($levelName, $attachment['title']); $this->assertSame( - array( - array( + [ + [ 'title' => 'Extra', 'value' => sprintf('```%s```', json_encode($extra, JSON_PRETTY_PRINT)), 'short' => false, - ), - array( + ], + [ 'title' => 'Context', 'value' => sprintf('```%s```', json_encode($context, JSON_PRETTY_PRINT)), 'short' => false, - ), - ), + ], + ], $attachment['fields'] ); } @@ -279,7 +279,7 @@ public function testAddsLongAttachmentWithoutContextAndExtra() $level = Level::Error; $levelName = LevelName::fromLevel($level)->value; $record = new SlackRecord(null, null, true, null); - $data = $record->getSlackData($this->getRecord($level, 'test', array('test' => 1))); + $data = $record->getSlackData($this->getRecord($level, 'test', ['test' => 1])); $attachment = $data['attachments'][0]; $this->assertArrayHasKey('title', $attachment); @@ -287,11 +287,11 @@ public function testAddsLongAttachmentWithoutContextAndExtra() $this->assertCount(1, $attachment['fields']); $this->assertSame('Message', $attachment['title']); $this->assertSame( - array(array( + [[ 'title' => 'Level', 'value' => $levelName, 'short' => false, - )), + ]], $attachment['fields'] ); } @@ -300,30 +300,30 @@ public function testAddsLongAttachmentWithContextAndExtra() { $level = Level::Error; $levelName = LevelName::fromLevel($level)->value; - $context = array('test' => 1); - $extra = array('tags' => array('web')); + $context = ['test' => 1]; + $extra = ['tags' => ['web']]; $record = new SlackRecord(null, null, true, null, false, true); $loggerRecord = $this->getRecord($level, 'test', $context); $loggerRecord['extra'] = $extra; $data = $record->getSlackData($loggerRecord); - $expectedFields = array( - array( + $expectedFields = [ + [ 'title' => 'Level', 'value' => $levelName, 'short' => false, - ), - array( + ], + [ 'title' => 'Tags', 'value' => sprintf('```%s```', json_encode($extra['tags'])), 'short' => false, - ), - array( + ], + [ 'title' => 'Test', 'value' => $context['test'], 'short' => false, - ), - ); + ], + ]; $attachment = $data['attachments'][0]; $this->assertArrayHasKey('title', $attachment); @@ -349,7 +349,7 @@ public function testAddsTimestampToAttachment() public function testContextHasException() { - $record = $this->getRecord(Level::Critical, 'This is a critical message.', array('exception' => new \Exception())); + $record = $this->getRecord(Level::Critical, 'This is a critical message.', ['exception' => new \Exception()]); $slackRecord = new SlackRecord(null, null, true, null, false, true); $data = $slackRecord->getSlackData($record); $this->assertIsString($data['attachments'][0]['fields'][1]['value']); @@ -360,26 +360,26 @@ public function testExcludeExtraAndContextFields() $record = $this->getRecord( Level::Warning, 'test', - context: array('info' => array('library' => 'monolog', 'author' => 'Jordi')), - extra: array('tags' => array('web', 'cli')), + context: ['info' => ['library' => 'monolog', 'author' => 'Jordi']], + extra: ['tags' => ['web', 'cli']], ); - $slackRecord = new SlackRecord(null, null, true, null, false, true, array('context.info.library', 'extra.tags.1')); + $slackRecord = new SlackRecord(null, null, true, null, false, true, ['context.info.library', 'extra.tags.1']); $data = $slackRecord->getSlackData($record); $attachment = $data['attachments'][0]; - $expected = array( - array( + $expected = [ + [ 'title' => 'Info', - 'value' => sprintf('```%s```', json_encode(array('author' => 'Jordi'), JSON_PRETTY_PRINT)), + 'value' => sprintf('```%s```', json_encode(['author' => 'Jordi'], JSON_PRETTY_PRINT)), 'short' => false, - ), - array( + ], + [ 'title' => 'Tags', - 'value' => sprintf('```%s```', json_encode(array('web'))), + 'value' => sprintf('```%s```', json_encode(['web'])), 'short' => false, - ), - ); + ], + ]; foreach ($expected as $field) { $this->assertNotFalse(array_search($field, $attachment['fields'])); diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index 45b439dd9..dd63a4019 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -114,16 +114,16 @@ public function testWriteContentWithPlainTextMessage() public function provideLevelColors() { - return array( - array(Level::Debug, urlencode(SlackRecord::COLOR_DEFAULT)), - array(Level::Info, SlackRecord::COLOR_GOOD), - array(Level::Notice, SlackRecord::COLOR_GOOD), - array(Level::Warning, SlackRecord::COLOR_WARNING), - array(Level::Error, SlackRecord::COLOR_DANGER), - array(Level::Critical, SlackRecord::COLOR_DANGER), - array(Level::Alert, SlackRecord::COLOR_DANGER), - array(Level::Emergency,SlackRecord::COLOR_DANGER), - ); + return [ + [Level::Debug, urlencode(SlackRecord::COLOR_DEFAULT)], + [Level::Info, SlackRecord::COLOR_GOOD], + [Level::Notice, SlackRecord::COLOR_GOOD], + [Level::Warning, SlackRecord::COLOR_WARNING], + [Level::Error, SlackRecord::COLOR_DANGER], + [Level::Critical, SlackRecord::COLOR_DANGER], + [Level::Alert, SlackRecord::COLOR_DANGER], + [Level::Emergency,SlackRecord::COLOR_DANGER], + ]; } private function createHandler($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false) diff --git a/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/tests/Monolog/Handler/SlackWebhookHandlerTest.php index 2dfb5444b..31d23e548 100644 --- a/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ b/tests/Monolog/Handler/SlackWebhookHandlerTest.php @@ -36,27 +36,27 @@ public function testConstructorMinimal() $record = $this->getRecord(); $slackRecord = $handler->getSlackRecord(); $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); - $this->assertEquals(array( - 'attachments' => array( - array( + $this->assertEquals([ + 'attachments' => [ + [ 'fallback' => 'test', 'text' => 'test', 'color' => SlackRecord::COLOR_WARNING, - 'fields' => array( - array( + 'fields' => [ + [ 'title' => 'Level', 'value' => 'WARNING', 'short' => false, - ), - ), + ], + ], 'title' => 'Message', - 'mrkdwn_in' => array('fields'), + 'mrkdwn_in' => ['fields'], 'ts' => $record->datetime->getTimestamp(), 'footer' => null, 'footer_icon' => null, - ), - ), - ), $slackRecord->getSlackData($record)); + ], + ], + ], $slackRecord->getSlackData($record)); } /** @@ -79,12 +79,12 @@ public function testConstructorFull() $slackRecord = $handler->getSlackRecord(); $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); - $this->assertEquals(array( + $this->assertEquals([ 'username' => 'test-username', 'text' => 'test', 'channel' => 'test-channel', 'icon_emoji' => ':ghost:', - ), $slackRecord->getSlackData($this->getRecord())); + ], $slackRecord->getSlackData($this->getRecord())); } /** @@ -108,30 +108,30 @@ public function testConstructorFullWithAttachment() $record = $this->getRecord(); $slackRecord = $handler->getSlackRecord(); $this->assertInstanceOf('Monolog\Handler\Slack\SlackRecord', $slackRecord); - $this->assertEquals(array( + $this->assertEquals([ 'username' => 'test-username-with-attachment', 'channel' => 'test-channel-with-attachment', - 'attachments' => array( - array( + 'attachments' => [ + [ 'fallback' => 'test', 'text' => 'test', 'color' => SlackRecord::COLOR_WARNING, - 'fields' => array( - array( + 'fields' => [ + [ 'title' => 'Level', 'value' => LevelName::Warning->value, 'short' => false, - ), - ), - 'mrkdwn_in' => array('fields'), + ], + ], + 'mrkdwn_in' => ['fields'], 'ts' => $record['datetime']->getTimestamp(), 'footer' => 'test-username-with-attachment', 'footer_icon' => 'https://www.example.com/example.png', 'title' => 'Message', - ), - ), + ], + ], 'icon_url' => 'https://www.example.com/example.png', - ), $slackRecord->getSlackData($record)); + ], $slackRecord->getSlackData($record)); } /** diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index ddc7597a5..192cfbe00 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -128,7 +128,7 @@ public function testExceptionIsThrownIfCannotSetTimeout() public function testExceptionIsThrownIfCannotSetChunkSize() { - $this->setMockHandler(array('streamSetChunkSize')); + $this->setMockHandler(['streamSetChunkSize']); $this->handler->setChunkSize(8192); $this->handler->expects($this->once()) ->method('streamSetChunkSize') diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index c0f4979fa..a55981ea0 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -11,7 +11,6 @@ namespace Monolog\Handler; -use Monolog\Handler\StreamHandler; use Monolog\Test\TestCase; use Monolog\Level; diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 530a9d53c..f27d5ad57 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -75,15 +75,15 @@ public function testRfc() $host = gethostname(); $handler = $this->getMockBuilder('\Monolog\Handler\SyslogUdpHandler') - ->setConstructorArgs(array("127.0.0.1", 514, "authpriv", 'debug', true, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164)) + ->setConstructorArgs(["127.0.0.1", 514, "authpriv", 'debug', true, "php", \Monolog\Handler\SyslogUdpHandler::RFC3164]) ->onlyMethods([]) ->getMock(); $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') - ->setConstructorArgs(array('lol', 999)) - ->onlyMethods(array('write')) + ->setConstructorArgs(['lol', 999]) + ->onlyMethods(['write']) ->getMock(); $socket->expects($this->atLeast(2)) ->method('write') diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 754af3335..2a055bce7 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -32,8 +32,6 @@ public function testSendTelegramRequest(): void } /** - * @param string $apiKey - * @param string $channel */ private function createHandler( string $apiKey = 'testKey', diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 77bc932b7..e28403ae3 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -93,7 +93,7 @@ public function testHandleUsesProcessors() */ public function testHandleBatchUsesProcessors() { - $testHandlers = array(new TestHandler(), new TestHandler()); + $testHandlers = [new TestHandler(), new TestHandler()]; $handler = new WhatFailureGroupHandler($testHandlers); $handler->pushProcessor(function ($record) { $record->extra['foo'] = true; @@ -105,7 +105,7 @@ public function testHandleBatchUsesProcessors() return $record; }); - $handler->handleBatch(array($this->getRecord(Level::Debug), $this->getRecord(Level::Info))); + $handler->handleBatch([$this->getRecord(Level::Debug), $this->getRecord(Level::Info)]); foreach ($testHandlers as $test) { $this->assertTrue($test->hasDebugRecords()); $this->assertTrue($test->hasInfoRecords()); diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 217a6e552..446bedb58 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Level; class ZendMonitorHandlerTest extends TestCase { diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 70b4a9ff2..75fdb1f90 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -276,7 +276,7 @@ public function testProcessorsNotCalledWhenNotHandled() public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresent() { $logger = new Logger(__METHOD__); - $logger->pushProcessor(fn($record) => $record); + $logger->pushProcessor(fn ($record) => $record); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->never()) @@ -348,7 +348,7 @@ public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresentWit ; $logger = new Logger(__METHOD__, ['last' => $handler3, 'second' => $handler2, 'first' => $handler1]); - $logger->pushProcessor(fn($record) => $record); + $logger->pushProcessor(fn ($record) => $record); $logger->debug('test'); } @@ -652,7 +652,7 @@ public function testReset() $testHandler = new Handler\TestHandler(); $testHandler->setSkipReset(true); $bufferHandler = new Handler\BufferHandler($testHandler); - $groupHandler = new Handler\GroupHandler(array($bufferHandler)); + $groupHandler = new Handler\GroupHandler([$bufferHandler]); $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler); $logger->pushHandler($fingersCrossedHandler); diff --git a/tests/Monolog/Processor/WebProcessorTest.php b/tests/Monolog/Processor/WebProcessorTest.php index 5a7ac299f..59cc52e20 100644 --- a/tests/Monolog/Processor/WebProcessorTest.php +++ b/tests/Monolog/Processor/WebProcessorTest.php @@ -90,15 +90,15 @@ public function testProcessorAddsOnlyRequestedExtraFields() public function testProcessorAddsOnlyRequestedExtraFieldsIncludingOptionalFields() { - $server = array( + $server = [ 'REQUEST_URI' => 'A', 'UNIQUE_ID' => 'X', - ); + ]; - $processor = new WebProcessor($server, array('url')); + $processor = new WebProcessor($server, ['url']); $record = $processor($this->getRecord()); - $this->assertSame(array('url' => 'A'), $record->extra); + $this->assertSame(['url' => 'A'], $record->extra); } public function testProcessorConfiguringOfExtraFields() diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index 529b7d29f..c1b4a1e63 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -19,7 +19,6 @@ use Psr\Log\InvalidArgumentException; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Psr\Log\Test\LoggerInterfaceTest; class PsrLogCompatTest extends TestCase { @@ -61,28 +60,28 @@ public function testImplements() public function testLogsAtAllLevels($level, $message) { $logger = $this->getLogger(); - $logger->{$level}($message, array('user' => 'Bob')); - $logger->log($level, $message, array('user' => 'Bob')); + $logger->{$level}($message, ['user' => 'Bob']); + $logger->log($level, $message, ['user' => 'Bob']); - $expected = array( + $expected = [ "$level message of level $level with context: Bob", "$level message of level $level with context: Bob", - ); + ]; $this->assertEquals($expected, $this->getLogs()); } public function provideLevelsAndMessages() { - return array( - LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), - LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), - LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), - LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), - LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), - LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), - LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), - LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'), - ); + return [ + LogLevel::EMERGENCY => [LogLevel::EMERGENCY, 'message of level emergency with context: {user}'], + LogLevel::ALERT => [LogLevel::ALERT, 'message of level alert with context: {user}'], + LogLevel::CRITICAL => [LogLevel::CRITICAL, 'message of level critical with context: {user}'], + LogLevel::ERROR => [LogLevel::ERROR, 'message of level error with context: {user}'], + LogLevel::WARNING => [LogLevel::WARNING, 'message of level warning with context: {user}'], + LogLevel::NOTICE => [LogLevel::NOTICE, 'message of level notice with context: {user}'], + LogLevel::INFO => [LogLevel::INFO, 'message of level info with context: {user}'], + LogLevel::DEBUG => [LogLevel::DEBUG, 'message of level debug with context: {user}'], + ]; } public function testThrowsOnInvalidLevel() @@ -96,9 +95,9 @@ public function testThrowsOnInvalidLevel() public function testContextReplacement() { $logger = $this->getLogger(); - $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + $logger->info('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']); - $expected = array('info {Message {nothing} Bob Bar a}'); + $expected = ['info {Message {nothing} Bob Bar a}']; $this->assertEquals($expected, $this->getLogs()); } @@ -111,7 +110,7 @@ public function testObjectCastToString() $this->getLogger()->warning($dummy); - $expected = array("warning $string"); + $expected = ["warning $string"]; $this->assertEquals($expected, $this->getLogs()); } @@ -120,47 +119,47 @@ public function testContextCanContainAnything() $closed = fopen('php://memory', 'r'); fclose($closed); - $context = array( + $context = [ 'bool' => true, 'null' => null, 'string' => 'Foo', 'int' => 0, 'float' => 0.5, - 'nested' => array('with object' => $this->createStringable()), + 'nested' => ['with object' => $this->createStringable()], 'object' => new \DateTime('now', new DateTimeZone('Europe/London')), 'resource' => fopen('php://memory', 'r'), 'closed' => $closed, - ); + ]; $this->getLogger()->warning('Crazy context data', $context); - $expected = array('warning Crazy context data'); + $expected = ['warning Crazy context data']; $this->assertEquals($expected, $this->getLogs()); } public function testContextExceptionKeyCanBeExceptionOrOtherValues() { $logger = $this->getLogger(); - $logger->warning('Random message', array('exception' => 'oops')); - $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + $logger->warning('Random message', ['exception' => 'oops']); + $logger->critical('Uncaught Exception!', ['exception' => new \LogicException('Fail')]); - $expected = array( + $expected = [ 'warning Random message', - 'critical Uncaught Exception!' - ); + 'critical Uncaught Exception!', + ]; $this->assertEquals($expected, $this->getLogs()); } /** * Creates a mock of a `Stringable`. * - * @param string $string The string that must be represented by the stringable. + * @param string $string The string that must be represented by the stringable. * @return \PHPUnit_Framework_MockObject_MockObject A mock of an object that has a `__toString()` method. */ protected function createStringable($string = '') { $mock = $this->getMockBuilder('Stringable') - ->setMethods(array('__toString')) + ->setMethods(['__toString']) ->getMock(); $mock->method('__toString') diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index e73ad8fd3..0c406bb8c 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -28,13 +28,13 @@ class SignalHandlerTest extends TestCase protected function setUp(): void { - $this->signalHandlers = array(); + $this->signalHandlers = []; if (extension_loaded('pcntl')) { if (function_exists('pcntl_async_signals')) { $this->asyncSignalHandling = pcntl_async_signals(); } if (function_exists('pcntl_sigprocmask')) { - pcntl_sigprocmask(SIG_BLOCK, array(), $this->blockedSignals); + pcntl_sigprocmask(SIG_BLOCK, [], $this->blockedSignals); } } } @@ -67,10 +67,10 @@ private function setSignalHandler($signo, $handler = SIG_DFL) public function testHandleSignal() { - $logger = new Logger('test', array($handler = new TestHandler)); + $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new SignalHandler($logger); $signo = 2; // SIGINT. - $siginfo = array('signo' => $signo, 'errno' => 0, 'code' => 0); + $siginfo = ['signo' => $signo, 'errno' => 0, 'code' => 0]; $errHandler->handleSignal($signo, $siginfo); $this->assertCount(1, $handler->getRecords()); $this->assertTrue($handler->hasCriticalRecords()); @@ -97,7 +97,7 @@ public function testRegisterSignalHandler() $this->setSignalHandler(SIGCONT, SIG_IGN); $this->setSignalHandler(SIGURG, SIG_IGN); - $logger = new Logger('test', array($handler = new TestHandler)); + $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new SignalHandler($logger); $pid = posix_getpid(); @@ -135,14 +135,14 @@ public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, if ($pid === 0) { // Child. $streamHandler = new StreamHandler($path); $streamHandler->setFormatter($this->getIdentityFormatter()); - $logger = new Logger('test', array($streamHandler)); + $logger = new Logger('test', [$streamHandler]); $errHandler = new SignalHandler($logger); $errHandler->registerSignalHandler($signo, LogLevel::INFO, $callPrevious, false, false); - pcntl_sigprocmask(SIG_SETMASK, array(SIGCONT)); + pcntl_sigprocmask(SIG_SETMASK, [SIGCONT]); posix_kill(posix_getpid(), $signo); pcntl_signal_dispatch(); // If $callPrevious is true, SIGINT should terminate by this line. - pcntl_sigprocmask(SIG_BLOCK, array(), $oldset); + pcntl_sigprocmask(SIG_BLOCK, [], $oldset); file_put_contents($path, implode(' ', $oldset), FILE_APPEND); posix_kill(posix_getpid(), $signo); pcntl_signal_dispatch(); @@ -158,15 +158,15 @@ public function testRegisterDefaultPreviousSignalHandler($signo, $callPrevious, public function defaultPreviousProvider() { if (!defined('SIGCONT') || !defined('SIGINT') || !defined('SIGURG')) { - return array(); + return []; } - return array( - array(SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'), - array(SIGINT, true, 'Program received signal SIGINT'), - array(SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), - array(SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'), - ); + return [ + [SIGINT, false, 'Program received signal SIGINT'.SIGCONT.'Program received signal SIGINT'], + [SIGINT, true, 'Program received signal SIGINT'], + [SIGURG, false, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'], + [SIGURG, true, 'Program received signal SIGURG'.SIGCONT.'Program received signal SIGURG'], + ]; } /** @@ -178,7 +178,7 @@ public function testRegisterCallablePreviousSignalHandler($callPrevious) { $this->setSignalHandler(SIGURG, SIG_IGN); - $logger = new Logger('test', array($handler = new TestHandler)); + $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new SignalHandler($logger); $previousCalled = 0; pcntl_signal(SIGURG, function ($signo, array $siginfo = null) use (&$previousCalled) { @@ -194,10 +194,10 @@ public function testRegisterCallablePreviousSignalHandler($callPrevious) public function callablePreviousProvider() { - return array( - array(false), - array(true), - ); + return [ + [false], + [true], + ]; } /** @@ -222,7 +222,7 @@ public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) } $this->assertNotSame(-1, $pid); - $logger = new Logger('test', array($handler = new TestHandler)); + $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new SignalHandler($logger); $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, $restartSyscalls, false); if ($restartSyscalls) { @@ -246,12 +246,12 @@ public function testRegisterSyscallRestartingSignalHandler($restartSyscalls) public function restartSyscallsProvider() { - return array( - array(false), - array(true), - array(false), - array(true), - ); + return [ + [false], + [true], + [false], + [true], + ]; } /** @@ -264,7 +264,7 @@ public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $ex $this->setSignalHandler(SIGURG, SIG_IGN); pcntl_async_signals($initialAsync); - $logger = new Logger('test', array($handler = new TestHandler)); + $logger = new Logger('test', [$handler = new TestHandler]); $errHandler = new SignalHandler($logger); $errHandler->registerSignalHandler(SIGURG, LogLevel::INFO, false, false, $desiredAsync); $this->assertTrue(posix_kill(posix_getpid(), SIGURG)); @@ -275,13 +275,13 @@ public function testRegisterAsyncSignalHandler($initialAsync, $desiredAsync, $ex public function asyncProvider() { - return array( - array(false, false, 0, 1), - array(false, null, 0, 1), - array(false, true, 1, 1), - array(true, false, 0, 1), - array(true, null, 1, 1), - array(true, true, 1, 1), - ); + return [ + [false, false, 0, 1], + [false, null, 0, 1], + [false, true, 1, 1], + [true, false, 0, 1], + [true, null, 1, 1], + [true, true, 1, 1], + ]; } } diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index aced3baf3..08d127b15 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -27,8 +27,10 @@ public function provideObjects() { return [ ['stdClass', new \stdClass()], - ['class@anonymous', new class {}], - ['stdClass@anonymous', new class extends \stdClass {}], + ['class@anonymous', new class { + }], + ['stdClass@anonymous', new class extends \stdClass { + }], ]; } @@ -44,15 +46,15 @@ public function testCanonicalizePath($expected, $input) public function providePathsToCanonicalize() { - return array( - array('/foo/bar', '/foo/bar'), - array('file://'.getcwd().'/bla', 'file://bla'), - array(getcwd().'/bla', 'bla'), - array(getcwd().'/./bla', './bla'), - array('file:///foo/bar', 'file:///foo/bar'), - array('any://foo', 'any://foo'), - array('\\\\network\path', '\\\\network\path'), - ); + return [ + ['/foo/bar', '/foo/bar'], + ['file://'.getcwd().'/bla', 'file://bla'], + [getcwd().'/bla', 'bla'], + [getcwd().'/./bla', './bla'], + ['file:///foo/bar', 'file:///foo/bar'], + ['any://foo', 'any://foo'], + ['\\\\network\path', '\\\\network\path'], + ]; } /** @@ -112,13 +114,14 @@ public function providesDetectAndCleanUtf8() /** * @dataProvider providesPcreLastErrorMessage - * @param int $code + * @param int $code * @param string $msg */ public function testPcreLastErrorMessage($code, $msg) { if (PHP_VERSION_ID >= 80000) { $this->assertSame('No error', Utils::pcreLastErrorMessage($code)); + return; } @@ -178,7 +181,7 @@ public function provideIniValuesToConvertToBytes() /** * @dataProvider provideIniValuesToConvertToBytes - * @param mixed $input + * @param mixed $input * @param int|false $expected */ public function testExpandIniShorthandBytes($input, $expected) From 7952a83e0cd63394638aaeaeeab47d1ea049deb5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 20 Apr 2022 09:21:58 +0200 Subject: [PATCH 425/498] Move phpdoc to native types --- src/Monolog/DateTimeImmutable.php | 5 +-- src/Monolog/ErrorHandler.php | 43 ++++++++----------- src/Monolog/Formatter/ChromePHPFormatter.php | 4 +- src/Monolog/Formatter/ElasticaFormatter.php | 4 +- .../Formatter/ElasticsearchFormatter.php | 6 +-- src/Monolog/Formatter/FlowdockFormatter.php | 14 ++---- src/Monolog/Formatter/FluentdFormatter.php | 2 +- .../Formatter/GelfMessageFormatter.php | 10 ++--- src/Monolog/Formatter/JsonFormatter.php | 8 ++-- src/Monolog/Formatter/LineFormatter.php | 14 +++--- src/Monolog/Formatter/LogmaticFormatter.php | 10 +---- src/Monolog/Formatter/LogstashFormatter.php | 10 ++--- src/Monolog/Formatter/MongoDBFormatter.php | 13 +++--- src/Monolog/Formatter/NormalizerFormatter.php | 21 +++------ src/Monolog/Formatter/ScalarFormatter.php | 2 +- src/Monolog/Formatter/WildfireFormatter.php | 6 +-- src/Monolog/Handler/AbstractHandler.php | 9 ++-- .../Handler/AbstractProcessingHandler.php | 7 +-- src/Monolog/Handler/AbstractSyslogHandler.php | 7 ++- src/Monolog/Handler/AmqpHandler.php | 11 ++--- src/Monolog/Handler/BrowserConsoleHandler.php | 6 +-- src/Monolog/Handler/BufferHandler.php | 10 ++--- src/Monolog/Handler/ChromePHPHandler.php | 16 +++---- src/Monolog/Handler/CouchDBHandler.php | 6 +-- src/Monolog/Handler/CubeHandler.php | 19 +++----- src/Monolog/Handler/Curl/Util.php | 4 +- src/Monolog/Handler/DeduplicationHandler.php | 20 ++------- .../Handler/DoctrineCouchDBHandler.php | 5 +-- src/Monolog/Handler/DynamoDbHandler.php | 19 +++----- src/Monolog/Handler/ElasticaHandler.php | 15 +++---- src/Monolog/Handler/ElasticsearchHandler.php | 15 +++---- src/Monolog/Handler/ErrorLogHandler.php | 10 ++--- src/Monolog/Handler/FallbackGroupHandler.php | 4 +- src/Monolog/Handler/FilterHandler.php | 20 ++++----- src/Monolog/Handler/FingersCrossedHandler.php | 33 ++++++-------- src/Monolog/Handler/FirePHPHandler.php | 11 ++--- src/Monolog/Handler/FleepHookHandler.php | 4 +- src/Monolog/Handler/FlowdockHandler.php | 11 ++--- .../Handler/FormattableHandlerTrait.php | 4 +- src/Monolog/Handler/GelfHandler.php | 6 +-- src/Monolog/Handler/GroupHandler.php | 15 +++---- src/Monolog/Handler/Handler.php | 4 +- src/Monolog/Handler/HandlerWrapper.php | 23 +++++----- src/Monolog/Handler/IFTTTHandler.php | 8 ++-- src/Monolog/Handler/InsightOpsHandler.php | 7 +-- src/Monolog/Handler/LogEntriesHandler.php | 7 +-- src/Monolog/Handler/LogglyHandler.php | 17 +++----- src/Monolog/Handler/LogmaticHandler.php | 19 +++----- src/Monolog/Handler/MailHandler.php | 4 +- src/Monolog/Handler/MandrillHandler.php | 8 ++-- src/Monolog/Handler/MongoDBHandler.php | 2 +- src/Monolog/Handler/NativeMailerHandler.php | 20 ++++----- src/Monolog/Handler/NewRelicHandler.php | 10 ++--- src/Monolog/Handler/NoopHandler.php | 4 +- src/Monolog/Handler/NullHandler.php | 4 +- src/Monolog/Handler/OverflowHandler.php | 13 +++--- src/Monolog/Handler/PHPConsoleHandler.php | 7 ++- src/Monolog/Handler/ProcessHandler.php | 14 ++---- .../Handler/ProcessableHandlerTrait.php | 6 +-- src/Monolog/Handler/PsrHandler.php | 11 ++--- src/Monolog/Handler/PushoverHandler.php | 21 ++++----- src/Monolog/Handler/RedisHandler.php | 10 ++--- src/Monolog/Handler/RedisPubSubHandler.php | 7 ++- src/Monolog/Handler/RollbarHandler.php | 20 +++------ src/Monolog/Handler/RotatingFileHandler.php | 26 +++++------ src/Monolog/Handler/SamplingHandler.php | 13 ++---- src/Monolog/Handler/SendGridHandler.php | 16 +++---- src/Monolog/Handler/Slack/SlackRecord.php | 25 ++++------- src/Monolog/Handler/SlackHandler.php | 10 ++--- src/Monolog/Handler/SlackWebhookHandler.php | 8 ++-- src/Monolog/Handler/SocketHandler.php | 21 +++------ src/Monolog/Handler/SqsHandler.php | 8 ++-- src/Monolog/Handler/StreamHandler.php | 14 +++--- src/Monolog/Handler/SyslogHandler.php | 10 ++--- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 16 ++----- src/Monolog/Handler/SyslogUdpHandler.php | 8 ++-- src/Monolog/Handler/TelegramBotHandler.php | 14 +++--- src/Monolog/Handler/TestHandler.php | 30 ++++--------- .../Handler/WhatFailureGroupHandler.php | 4 +- src/Monolog/Handler/ZendMonitorHandler.php | 4 +- src/Monolog/Logger.php | 19 +++----- src/Monolog/Processor/GitProcessor.php | 2 +- src/Monolog/Processor/HostnameProcessor.php | 5 +-- .../Processor/IntrospectionProcessor.php | 2 +- .../Processor/MemoryPeakUsageProcessor.php | 2 +- src/Monolog/Processor/MemoryProcessor.php | 4 +- .../Processor/MemoryUsageProcessor.php | 2 +- src/Monolog/Processor/MercurialProcessor.php | 2 +- src/Monolog/Processor/ProcessIdProcessor.php | 2 +- src/Monolog/Processor/ProcessorInterface.php | 2 +- .../Processor/PsrLogMessageProcessor.php | 8 ++-- src/Monolog/Processor/TagProcessor.php | 4 +- src/Monolog/Processor/UidProcessor.php | 4 +- src/Monolog/Processor/WebProcessor.php | 4 +- src/Monolog/Registry.php | 9 ++-- src/Monolog/ResettableInterface.php | 5 +-- src/Monolog/SignalHandler.php | 9 ++-- tests/Monolog/ErrorHandlerTest.php | 1 - tests/Monolog/Formatter/JsonFormatterTest.php | 20 ++------- .../Formatter/NormalizerFormatterTest.php | 5 +-- tests/Monolog/Handler/ElasticaHandlerTest.php | 23 ++++------ .../Handler/ElasticsearchHandlerTest.php | 22 +++------- .../Monolog/Handler/ExceptionTestHandler.php | 2 +- .../Monolog/Handler/FleepHookHandlerTest.php | 5 +-- tests/Monolog/Handler/FlowdockHandlerTest.php | 5 +-- tests/Monolog/Handler/HandlerWrapperTest.php | 10 +---- .../Monolog/Handler/InsightOpsHandlerTest.php | 6 +-- .../Monolog/Handler/LogEntriesHandlerTest.php | 6 +-- tests/Monolog/Handler/LogmaticHandlerTest.php | 6 +-- tests/Monolog/Handler/ProcessHandlerTest.php | 8 +--- tests/Monolog/Handler/RollbarHandlerTest.php | 10 +---- .../Monolog/Handler/Slack/SlackRecordTest.php | 5 +-- tests/Monolog/Handler/SlackHandlerTest.php | 5 +-- tests/Monolog/Handler/StreamHandlerTest.php | 8 +--- .../Handler/TelegramBotHandlerTest.php | 8 +--- tests/Monolog/PsrLogCompatTest.php | 10 ++--- tests/Monolog/UtilsTest.php | 18 +++----- 117 files changed, 433 insertions(+), 767 deletions(-) diff --git a/src/Monolog/DateTimeImmutable.php b/src/Monolog/DateTimeImmutable.php index 6a1ba9b25..274b73ea1 100644 --- a/src/Monolog/DateTimeImmutable.php +++ b/src/Monolog/DateTimeImmutable.php @@ -21,10 +21,7 @@ */ class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable { - /** - * @var bool - */ - private $useMicroseconds; + private bool $useMicroseconds; public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null) { diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 78c363423..50e999c35 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -11,6 +11,7 @@ namespace Monolog; +use Closure; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; @@ -25,31 +26,24 @@ */ class ErrorHandler { - /** @var LoggerInterface */ - private $logger; + private LoggerInterface $logger; - /** @var ?callable */ - private $previousExceptionHandler = null; + private Closure|null $previousExceptionHandler = null; /** @var array an array of class name to LogLevel::* constant mapping */ - private $uncaughtExceptionLevelMap = []; + private array $uncaughtExceptionLevelMap = []; /** @var callable|true|null */ private $previousErrorHandler = null; /** @var array an array of E_* constant to LogLevel::* constant mapping */ - private $errorLevelMap = []; - /** @var bool */ - private $handleOnlyReportedErrors = true; - - /** @var bool */ - private $hasFatalErrorHandler = false; - /** @var LogLevel::* */ - private $fatalLevel = LogLevel::ALERT; - /** @var ?string */ - private $reservedMemory = null; - /** @var ?mixed */ - private $lastFatalTrace; - /** @var int[] */ - private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; + private array $errorLevelMap = []; + private bool $handleOnlyReportedErrors = true; + + private bool $hasFatalErrorHandler = false; + private string $fatalLevel = LogLevel::ALERT; + private string|null $reservedMemory = null; + /** @var mixed|null */ + private $lastFatalTrace = null; + private const FATAL_ERRORS = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; public function __construct(LoggerInterface $logger) { @@ -99,7 +93,7 @@ public function registerExceptionHandler(array $levelMap = [], bool $callPreviou } } if ($callPrevious && $prev) { - $this->previousExceptionHandler = $prev; + $this->previousExceptionHandler = $prev(...); } return $this; @@ -213,7 +207,7 @@ public function handleError(int $code, string $message, string $file = '', int $ } // 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::$fatalErrors, true)) { + if (!$this->hasFatalErrorHandler || !in_array($code, self::FATAL_ERRORS, true)) { $level = $this->errorLevelMap[$code] ?? LogLevel::CRITICAL; $this->logger->log($level, self::codeToString($code).': '.$message, ['code' => $code, 'message' => $message, 'file' => $file, 'line' => $line]); } else { @@ -239,7 +233,7 @@ public function handleFatalError(): void $this->reservedMemory = ''; $lastError = error_get_last(); - if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) { + if ($lastError && in_array($lastError['type'], self::FATAL_ERRORS, true)) { $this->logger->log( $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], @@ -254,10 +248,7 @@ public function handleFatalError(): void } } - /** - * @param int $code - */ - private static function codeToString($code): string + private static function codeToString(int $code): string { return match ($code) { E_ERROR => 'E_ERROR', diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 8cc5abc8a..540657ba1 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -41,7 +41,7 @@ private function toWildfireLevel(Level $level): string } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record) { @@ -72,7 +72,7 @@ public function format(LogRecord $record) } /** - * {@inheritDoc} + * @inheritDoc */ public function formatBatch(array $records) { diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 1ab14c5ee..750a66457 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -24,7 +24,7 @@ class ElasticaFormatter extends NormalizerFormatter /** * @var string Elastic search index name */ - protected $index; + protected string $index; /** * @var ?string Elastic search document type @@ -45,7 +45,7 @@ public function __construct(string $index, ?string $type) } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record) { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 0709a8fe5..6c3eb9b2a 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -24,12 +24,12 @@ class ElasticsearchFormatter extends NormalizerFormatter /** * @var string Elasticsearch index name */ - protected $index; + protected string $index; /** * @var string Elasticsearch record type */ - protected $type; + protected string $type; /** * @param string $index Elasticsearch index name @@ -45,7 +45,7 @@ public function __construct(string $index, string $type) } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record) { diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 83a73c815..8e66f2234 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -20,15 +20,9 @@ */ class FlowdockFormatter implements FormatterInterface { - /** - * @var string - */ - private $source; + private string $source; - /** - * @var string - */ - private $sourceEmail; + private string $sourceEmail; public function __construct(string $source, string $sourceEmail) { @@ -37,7 +31,7 @@ public function __construct(string $source, string $sourceEmail) } /** - * {@inheritDoc} + * @inheritDoc * * @return mixed[] */ @@ -71,7 +65,7 @@ public function format(LogRecord $record): array } /** - * {@inheritDoc} + * @inheritDoc * * @return mixed[][] */ diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index ce596df64..ddfd28fbd 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -40,7 +40,7 @@ class FluentdFormatter implements FormatterInterface /** * @var bool $levelTag should message level be a part of the fluentd tag */ - protected $levelTag = false; + protected bool $levelTag = false; public function __construct(bool $levelTag = false) { diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index d6c5d6738..488e2387f 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -29,22 +29,22 @@ class GelfMessageFormatter extends NormalizerFormatter /** * @var string the name of the system for the Gelf log message */ - protected $systemName; + protected string $systemName; /** * @var string a prefix for 'extra' fields from the Monolog record (optional) */ - protected $extraPrefix; + protected string $extraPrefix; /** * @var string a prefix for 'context' fields from the Monolog record (optional) */ - protected $contextPrefix; + protected string $contextPrefix; /** * @var int max length per field */ - protected $maxLength; + protected int $maxLength; /** * Translates Monolog log levels to Graylog2 log priorities. @@ -79,7 +79,7 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record): Message { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 8f8fd7e72..e77427db1 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -69,7 +69,7 @@ public function isAppendingNewlines(): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record): string { @@ -94,7 +94,7 @@ public function format(LogRecord $record): string } /** - * {@inheritDoc} + * @inheritDoc */ public function formatBatch(array $records): string { @@ -104,8 +104,6 @@ public function formatBatch(array $records): string }; } - /** - */ public function includeStacktraces(bool $include = true): self { $this->includeStacktraces = $include; @@ -183,7 +181,7 @@ protected function normalize(mixed $data, int $depth = 0): mixed * 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 { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 99cd60377..23a635216 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -26,14 +26,10 @@ class LineFormatter extends NormalizerFormatter { public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; - /** @var string */ - protected $format; - /** @var bool */ - protected $allowInlineLineBreaks; - /** @var bool */ - protected $ignoreEmptyContextAndExtra; - /** @var bool */ - protected $includeStacktraces; + protected string $format; + protected bool $allowInlineLineBreaks; + protected bool $ignoreEmptyContextAndExtra; + protected bool $includeStacktraces; /** * @param string|null $format The format of the message @@ -74,7 +70,7 @@ public function ignoreEmptyContextAndExtra(bool $ignore = true): self } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record): string { diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index 6fc7c2bdf..a20a85eef 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -22,15 +22,9 @@ class LogmaticFormatter extends JsonFormatter { protected const MARKERS = ["sourcecode", "php"]; - /** - * @var string - */ - protected $hostname = ''; + protected string $hostname = ''; - /** - * @var string - */ - protected $appname = ''; + protected string $appname = ''; public function setHostname(string $hostname): self { diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index b7b96cb4a..5e6951440 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -26,22 +26,22 @@ class LogstashFormatter extends NormalizerFormatter /** * @var string the name of the system for the Logstash log message, used to fill the @source field */ - protected $systemName; + protected string $systemName; /** * @var string an application name for the Logstash log message, used to fill the @type field */ - protected $applicationName; + protected string $applicationName; /** * @var string the key for 'extra' fields from the Monolog record */ - protected $extraKey; + protected string $extraKey; /** * @var string the key for 'context' fields from the Monolog record */ - protected $contextKey; + protected string $contextKey; /** * @param string $applicationName The application that sends the data, used as the "type" field of logstash @@ -61,7 +61,7 @@ public function __construct(string $applicationName, ?string $systemName = null, } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record): string { diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index f72072413..a3bdd4f87 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -23,12 +23,9 @@ */ class MongoDBFormatter implements FormatterInterface { - /** @var bool */ - private $exceptionTraceAsString; - /** @var int */ - private $maxNestingLevel; - /** @var bool */ - private $isLegacyMongoExt; + private bool $exceptionTraceAsString; + private int $maxNestingLevel; + private bool $isLegacyMongoExt; /** * @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record->context is 2 @@ -43,7 +40,7 @@ public function __construct(int $maxNestingLevel = 3, bool $exceptionTraceAsStri } /** - * {@inheritDoc} + * @inheritDoc * * @return mixed[] */ @@ -56,7 +53,7 @@ public function format(LogRecord $record): array } /** - * {@inheritDoc} + * @inheritDoc * * @return array */ diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 2a92221e4..0e195450f 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -25,15 +25,11 @@ class NormalizerFormatter implements FormatterInterface { public const SIMPLE_DATE = "Y-m-d\TH:i:sP"; - /** @var string */ - protected $dateFormat; - /** @var int */ - protected $maxNormalizeDepth = 9; - /** @var int */ - protected $maxNormalizeItemCount = 1000; + protected string $dateFormat; + protected int $maxNormalizeDepth = 9; + protected int $maxNormalizeItemCount = 1000; - /** @var int */ - private $jsonEncodeOptions = Utils::DEFAULT_JSON_FLAGS; + private int $jsonEncodeOptions = Utils::DEFAULT_JSON_FLAGS; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format @@ -47,7 +43,7 @@ public function __construct(?string $dateFormat = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record) { @@ -65,7 +61,7 @@ public function normalizeValue(mixed $data): mixed } /** - * {@inheritDoc} + * @inheritDoc */ public function formatBatch(array $records) { @@ -277,10 +273,7 @@ protected function toJson($data, bool $ignoreErrors = false): string return Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors); } - /** - * @return string - */ - protected function formatDate(\DateTimeInterface $date) + protected function formatDate(\DateTimeInterface $date): string { // 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 diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index e2db7e927..4bc20a08c 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -22,7 +22,7 @@ class ScalarFormatter extends NormalizerFormatter { /** - * {@inheritDoc} + * @inheritDoc * * @phpstan-return array $record */ diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index ae2b85ee7..8ef7b7d14 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -54,7 +54,7 @@ private function toWildfireLevel(Level $level): string } /** - * {@inheritDoc} + * @inheritDoc */ public function format(LogRecord $record): string { @@ -112,7 +112,7 @@ public function format(LogRecord $record): string } /** - * {@inheritDoc} + * @inheritDoc * * @phpstan-return never */ @@ -122,7 +122,7 @@ public function formatBatch(array $records) } /** - * {@inheritDoc} + * @inheritDoc * * @return null|scalar|array|object */ diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 53b9600c5..92344dd7c 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -26,8 +26,7 @@ abstract class AbstractHandler extends Handler implements ResettableInterface { protected Level $level = Level::Debug; - /** @var bool */ - protected $bubble = true; + protected bool $bubble = true; /** * @param int|string|Level|LevelName|LogLevel::* $level The minimum logging level at which this handler will be triggered @@ -42,7 +41,7 @@ public function __construct(int|string|Level|LevelName $level = Level::Debug, bo } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -96,9 +95,9 @@ public function getBubble(): bool } /** - * {@inheritDoc} + * @inheritDoc */ - public function reset() + public function reset(): void { } } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 56a83cc16..463f8dfe8 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -27,7 +27,7 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc use FormattableHandlerTrait; /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -51,10 +51,7 @@ public function handle(LogRecord $record): bool */ abstract protected function write(LogRecord $record): void; - /** - * @return void - */ - public function reset() + public function reset(): void { parent::reset(); diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 0cba315d8..8535ab84f 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -20,8 +20,7 @@ */ abstract class AbstractSyslogHandler extends AbstractProcessingHandler { - /** @var int */ - protected $facility; + protected int $facility; /** * Translates Monolog log levels to syslog log priorities. @@ -44,7 +43,7 @@ protected function toSyslogPriority(Level $level): int * List of valid log facility names. * @var array */ - protected $facilities = [ + protected array $facilities = [ 'auth' => \LOG_AUTH, 'authpriv' => \LOG_AUTHPRIV, 'cron' => \LOG_CRON, @@ -96,7 +95,7 @@ public function __construct($facility = \LOG_USER, $level = Level::Debug, bool $ } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 3500732a2..8fe564b9d 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -26,10 +26,7 @@ class AmqpHandler extends AbstractProcessingHandler */ protected $exchange; - /** - * @var string - */ - protected $exchangeName; + protected string $exchangeName; /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use @@ -50,7 +47,7 @@ public function __construct($exchange, ?string $exchangeName = null, $level = Le } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -77,7 +74,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -127,7 +124,7 @@ private function createAmqpMessage(string $data): AMQPMessage } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index e75e3650a..0f3587ee5 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -37,7 +37,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler 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,7 +51,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -91,7 +91,7 @@ public function close(): void self::resetStatic(); } - public function reset() + public function reset(): void { parent::reset(); diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 26b3e7c1d..2d0b4429d 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -56,7 +56,7 @@ public function __construct(HandlerInterface $handler, int $bufferLimit = 0, int } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -107,7 +107,7 @@ public function __destruct() } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -125,7 +125,7 @@ public function clear(): void $this->buffer = []; } - public function reset() + public function reset(): void { $this->flush(); @@ -139,7 +139,7 @@ public function reset() } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -153,7 +153,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index b08f004c2..96257c3c0 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -44,27 +44,23 @@ 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}'; - /** @var bool */ - protected static $initialized = false; + protected static bool $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 $overflowed = false; + protected static bool $overflowed = false; /** @var mixed[] */ - protected static $json = [ + protected static array $json = [ 'version' => self::VERSION, 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [], ]; - /** @var bool */ - protected static $sendHeaders = true; + protected static bool $sendHeaders = true; public function __construct($level = Level::Debug, bool $bubble = true) { @@ -75,7 +71,7 @@ public function __construct($level = Level::Debug, bool $bubble = true) } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -102,7 +98,7 @@ public function handleBatch(array $records): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index 0369ee89c..f92b1b139 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -24,7 +24,7 @@ class CouchDBHandler extends AbstractProcessingHandler { /** @var mixed[] */ - private $options; + private array $options; /** * @param mixed[] $options @@ -43,7 +43,7 @@ public function __construct(array $options = [], $level = Level::Debug, bool $bu } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -69,7 +69,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index d013671dd..50d2507fe 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -23,18 +23,13 @@ */ class CubeHandler extends AbstractProcessingHandler { - /** @var \Socket|null */ - private $udpConnection = null; - /** @var \CurlHandle|null */ - private $httpConnection = null; - /** @var string */ - private $scheme; - /** @var string */ - private $host; - /** @var int */ - private $port; + private ?\Socket $udpConnection = null; + private ?\CurlHandle $httpConnection = null; + private string $scheme; + private string $host; + private int $port; /** @var string[] */ - private $acceptedSchemes = ['http', 'udp']; + private array $acceptedSchemes = ['http', 'udp']; /** * Create a Cube handler @@ -111,7 +106,7 @@ protected function connectHttp(): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index a8c02da97..64981c980 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -21,7 +21,7 @@ final class Util { /** @var array */ - private static $retriableErrorCodes = [ + private static array $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, CURLE_HTTP_NOT_FOUND, @@ -37,7 +37,7 @@ final class Util * @param CurlHandle $ch curl handler * @return bool|string @see curl_exec */ - public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) + public static function execute(CurlHandle $ch, int $retries = 5, bool $closeAfterDone = true) { while ($retries--) { $curlResponse = curl_exec($ch); diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index e8c171ccb..a8ae211ac 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -39,25 +39,13 @@ */ class DeduplicationHandler extends BufferHandler { - /** - * @var string - */ - protected $deduplicationStore; + protected string $deduplicationStore; - /** - * @var Level - */ - protected $deduplicationLevel; + protected Level $deduplicationLevel; - /** - * @var int - */ - protected $time; + protected int $time; - /** - * @var bool - */ - private $gc = false; + private bool $gc = false; /** * @param HandlerInterface $handler Handler. diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index 0ce3ae9f4..44d2ff5c5 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -24,8 +24,7 @@ */ class DoctrineCouchDBHandler extends AbstractProcessingHandler { - /** @var CouchDBClient */ - private $client; + private CouchDBClient $client; public function __construct(CouchDBClient $client, $level = Level::Debug, bool $bubble = true) { @@ -34,7 +33,7 @@ public function __construct(CouchDBClient $client, $level = Level::Debug, bool $ } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index c9c469f0d..51994462e 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -29,20 +29,11 @@ class DynamoDbHandler extends AbstractProcessingHandler { public const DATE_FORMAT = 'Y-m-d\TH:i:s.uO'; - /** - * @var DynamoDbClient - */ - protected $client; + protected DynamoDbClient $client; - /** - * @var string - */ - protected $table; + protected string $table; - /** - * @var Marshaler - */ - protected $marshaler; + protected Marshaler $marshaler; public function __construct(DynamoDbClient $client, string $table, $level = Level::Debug, bool $bubble = true) { @@ -55,7 +46,7 @@ public function __construct(DynamoDbClient $client, string $table, $level = Leve } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -80,7 +71,7 @@ protected function filterEmptyFields(array $record): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 29dc74b1b..fff3417aa 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -37,15 +37,12 @@ */ class ElasticaHandler extends AbstractProcessingHandler { - /** - * @var Client - */ - protected $client; + protected Client $client; /** * @var mixed[] Handler config options */ - protected $options = []; + protected array $options = []; /** * @param Client $client Elastica Client object @@ -66,7 +63,7 @@ public function __construct(Client $client, array $options = [], $level = Level: } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -74,7 +71,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -94,7 +91,7 @@ public function getOptions(): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { @@ -102,7 +99,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index a669dde70..427c8f3a6 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -44,15 +44,12 @@ */ class ElasticsearchHandler extends AbstractProcessingHandler { - /** - * @var Client - */ - protected $client; + protected Client $client; /** * @var mixed[] Handler config options */ - protected $options = []; + protected array $options = []; /** * @param Client $client Elasticsearch Client object @@ -73,7 +70,7 @@ public function __construct(Client $client, array $options = [], $level = Level: } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -81,7 +78,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -103,7 +100,7 @@ public function getOptions(): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { @@ -111,7 +108,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 6847e690c..e19a129f7 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -27,10 +27,8 @@ class ErrorLogHandler extends AbstractProcessingHandler public const OPERATING_SYSTEM = 0; public const SAPI = 4; - /** @var int */ - protected $messageType; - /** @var bool */ - protected $expandNewlines; + protected int $messageType; + protected bool $expandNewlines; /** * @param int $messageType Says where the error should go. @@ -62,7 +60,7 @@ public static function getAvailableTypes(): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { @@ -70,7 +68,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index ac6e90424..4c10b2017 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -24,7 +24,7 @@ class FallbackGroupHandler extends GroupHandler { /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -44,7 +44,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 908216a15..631996199 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -49,10 +49,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * Whether the messages that are handled can bubble up the stack or not - * - * @var bool */ - protected $bubble; + protected bool $bubble; /** * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler @@ -109,7 +107,7 @@ public function setAcceptedLevels(int|string|Level|LevelName|array $minLevelOrLi } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -117,7 +115,7 @@ public function isHandling(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -135,7 +133,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -155,10 +153,8 @@ public function handleBatch(array $records): void * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. - * - * @return HandlerInterface */ - public function getHandler(LogRecord $record = null) + public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); @@ -171,7 +167,7 @@ public function getHandler(LogRecord $record = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -186,7 +182,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { @@ -198,7 +194,7 @@ public function getFormatter(): FormatterInterface throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } - public function reset() + public function reset(): void { $this->resetProcessors(); diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index fab57656c..c500d5b4a 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -46,19 +46,14 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ protected $handler; - /** @var ActivationStrategyInterface */ - protected $activationStrategy; - /** @var bool */ - protected $buffering = true; - /** @var int */ - protected $bufferSize; + protected ActivationStrategyInterface $activationStrategy; + protected bool $buffering = true; + protected int $bufferSize; /** @var LogRecord[] */ - protected $buffer = []; - /** @var bool */ - protected $stopBuffering; + protected array $buffer = []; + protected bool $stopBuffering; protected Level|null $passthruLevel = null; - /** @var bool */ - protected $bubble; + protected bool $bubble; /** * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler @@ -100,7 +95,7 @@ public function __construct($handler, int|string|Level|LevelName|ActivationStrat } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -121,7 +116,7 @@ public function activate(): void } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -145,7 +140,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -154,7 +149,7 @@ public function close(): void $this->getHandler()->close(); } - public function reset() + public function reset(): void { $this->flushBuffer(); @@ -199,10 +194,8 @@ private function flushBuffer(): void * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. - * - * @return HandlerInterface */ - public function getHandler(LogRecord $record = null) + public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); @@ -215,7 +208,7 @@ public function getHandler(LogRecord $record = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -230,7 +223,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 744963f15..1a6d3b952 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -46,18 +46,15 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet - * @var bool */ - protected static $initialized = false; + protected static bool $initialized = false; /** * Shared static message index between potentially multiple handlers - * @var int */ - protected static $messageIndex = 1; + protected static int $messageIndex = 1; - /** @var bool */ - protected static $sendHeaders = true; + protected static bool $sendHeaders = true; /** * Base header creation function used by init headers & record headers @@ -96,7 +93,7 @@ protected function createRecordHeader(LogRecord $record): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 4b51b6a9a..9f44ba719 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -33,7 +33,7 @@ class FleepHookHandler extends SocketHandler /** * @var string Webhook token (specifies the conversation where logs are sent) */ - protected $token; + protected string $token; /** * Construct a new Fleep.io Handler. @@ -95,7 +95,7 @@ public function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index dd3e61325..135815485 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -30,10 +30,7 @@ */ class FlowdockHandler extends SocketHandler { - /** - * @var string - */ - protected $apiToken; + protected string $apiToken; /** * @throws MissingExtensionException if OpenSSL is missing @@ -66,7 +63,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -86,7 +83,7 @@ protected function getDefaultFormatter(): FormatterInterface } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -96,7 +93,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index b60bdce0e..2bf924d2e 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -27,7 +27,7 @@ trait FormattableHandlerTrait protected $formatter; /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -37,7 +37,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 1b53dbdad..6ed79c386 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -28,7 +28,7 @@ class GelfHandler extends AbstractProcessingHandler /** * @var PublisherInterface the publisher object that sends the message to the server */ - protected $publisher; + protected PublisherInterface $publisher; /** * @param PublisherInterface $publisher a gelf publisher object @@ -41,7 +41,7 @@ public function __construct(PublisherInterface $publisher, $level = Level::Debug } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -49,7 +49,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index d32632759..16f3b6b71 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -25,9 +25,8 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset use ProcessableHandlerTrait; /** @var HandlerInterface[] */ - protected $handlers; - /** @var bool */ - protected $bubble; + protected array $handlers; + protected bool $bubble; /** * @param HandlerInterface[] $handlers Array of Handlers. @@ -46,7 +45,7 @@ public function __construct(array $handlers, bool $bubble = true) } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -60,7 +59,7 @@ public function isHandling(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -76,7 +75,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -93,7 +92,7 @@ public function handleBatch(array $records): void } } - public function reset() + public function reset(): void { $this->resetProcessors(); @@ -114,7 +113,7 @@ public function close(): void } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { diff --git a/src/Monolog/Handler/Handler.php b/src/Monolog/Handler/Handler.php index afef2fd74..dad3aac23 100644 --- a/src/Monolog/Handler/Handler.php +++ b/src/Monolog/Handler/Handler.php @@ -19,7 +19,7 @@ abstract class Handler implements HandlerInterface { /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -29,7 +29,7 @@ public function handleBatch(array $records): void } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index a045ccc75..541ec2541 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -34,10 +34,7 @@ */ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface { - /** - * @var HandlerInterface - */ - protected $handler; + protected HandlerInterface $handler; public function __construct(HandlerInterface $handler) { @@ -45,7 +42,7 @@ public function __construct(HandlerInterface $handler) } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -53,7 +50,7 @@ public function isHandling(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -61,7 +58,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -69,7 +66,7 @@ public function handleBatch(array $records): void } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -77,7 +74,7 @@ public function close(): void } /** - * {@inheritDoc} + * @inheritDoc */ public function pushProcessor(callable $callback): HandlerInterface { @@ -91,7 +88,7 @@ public function pushProcessor(callable $callback): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function popProcessor(): callable { @@ -103,7 +100,7 @@ public function popProcessor(): callable } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -117,7 +114,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { @@ -128,7 +125,7 @@ public function getFormatter(): FormatterInterface throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); } - public function reset() + public function reset(): void { if ($this->handler instanceof ResettableInterface) { $this->handler->reset(); diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index da50bdd5e..4bbd4d59f 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -28,10 +28,8 @@ */ class IFTTTHandler extends AbstractProcessingHandler { - /** @var string */ - private $eventName; - /** @var string */ - private $secretKey; + private string $eventName; + private string $secretKey; /** * @param string $eventName The name of the IFTTT Maker event that should be triggered @@ -50,7 +48,7 @@ public function __construct(string $eventName, string $secretKey, $level = Level } /** - * {@inheritDoc} + * @inheritDoc */ public function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php index ca120e1e5..abb2f88f7 100644 --- a/src/Monolog/Handler/InsightOpsHandler.php +++ b/src/Monolog/Handler/InsightOpsHandler.php @@ -22,10 +22,7 @@ */ class InsightOpsHandler extends SocketHandler { - /** - * @var string - */ - protected $logToken; + protected string $logToken; /** * @param string $token Log token supplied by InsightOps @@ -68,7 +65,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 5695f5244..00259834e 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -19,10 +19,7 @@ */ class LogEntriesHandler extends SocketHandler { - /** - * @var string - */ - protected $logToken; + protected string $logToken; /** * @param string $token Log token supplied by LogEntries @@ -62,7 +59,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index e451ddf02..e14223706 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -36,13 +36,12 @@ class LogglyHandler extends AbstractProcessingHandler * * @var CurlHandle[] */ - protected $curlHandlers = []; + protected array $curlHandlers = []; - /** @var string */ - protected $token; + protected string $token; /** @var string[] */ - protected $tag = []; + protected array $tag = []; /** * @param string $token API token supplied by Loggly @@ -62,11 +61,8 @@ public function __construct(string $token, $level = Level::Debug, bool $bubble = /** * Loads and returns the shared curl handler for the given endpoint. - * - * - * @return CurlHandle */ - protected function getCurlHandler(string $endpoint) + protected function getCurlHandler(string $endpoint): CurlHandle { if (!array_key_exists($endpoint, $this->curlHandlers)) { $this->curlHandlers[$endpoint] = $this->loadCurlHandle($endpoint); @@ -77,11 +73,8 @@ protected function getCurlHandler(string $endpoint) /** * Starts a fresh curl session for the given endpoint and returns its handler. - * - * - * @return CurlHandle */ - private function loadCurlHandle(string $endpoint) + private function loadCurlHandle(string $endpoint): CurlHandle { $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 453647268..98935f2c5 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -21,20 +21,11 @@ */ class LogmaticHandler extends SocketHandler { - /** - * @var string - */ - private $logToken; + private string $logToken; - /** - * @var string - */ - private $hostname; + private string $hostname; - /** - * @var string - */ - private $appname; + private string $appname; /** * @param string $token Log token supplied by Logmatic. @@ -81,7 +72,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { @@ -89,7 +80,7 @@ protected function generateDataStream(LogRecord $record): string } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 69808899e..c6488f1a3 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -23,7 +23,7 @@ abstract class MailHandler extends AbstractProcessingHandler { /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { @@ -54,7 +54,7 @@ public function handleBatch(array $records): void abstract protected function send(string $content, array $records): void; /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 07f85bbc4..353195197 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -22,10 +22,8 @@ */ class MandrillHandler extends MailHandler { - /** @var Swift_Message */ - protected $message; - /** @var string */ - protected $apiKey; + protected Swift_Message $message; + protected string $apiKey; /** * @phpstan-param (Swift_Message|callable(): Swift_Message) $message @@ -48,7 +46,7 @@ public function __construct(string $apiKey, $message, $level = Level::Error, boo } /** - * {@inheritDoc} + * @inheritDoc */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index d8248f999..7461ebc28 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -77,7 +77,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 6aad468ae..57d704e00 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -26,43 +26,39 @@ class NativeMailerHandler extends MailHandler * The email addresses to which the message will be sent * @var string[] */ - protected $to; + protected array $to; /** * The subject of the email - * @var string */ - protected $subject; + protected string $subject; /** * Optional headers for the message * @var string[] */ - protected $headers = []; + protected array $headers = []; /** * Optional parameters for the message * @var string[] */ - protected $parameters = []; + protected array $parameters = []; /** * The wordwrap length for the message - * @var int */ - protected $maxColumnWidth; + protected int $maxColumnWidth; /** * The Content-type for the message - * @var string|null */ - protected $contentType; + protected string|null $contentType = null; /** * The encoding for the message - * @var string */ - protected $encoding = 'utf-8'; + protected string $encoding = 'utf-8'; /** * @param string|string[] $to The receiver of the mail @@ -109,7 +105,7 @@ public function addParameter($parameters): self } /** - * {@inheritDoc} + * @inheritDoc */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 397606655..b040311a3 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -45,13 +45,11 @@ class NewRelicHandler extends AbstractProcessingHandler /** * 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; + protected bool $explodeArrays; /** - * {@inheritDoc} + * @inheritDoc */ public function __construct( $level = Level::Error, @@ -68,7 +66,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -184,7 +182,7 @@ protected function setNewRelicParameter(string $key, $value): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/NoopHandler.php b/src/Monolog/Handler/NoopHandler.php index 19fdf21af..d9fea180c 100644 --- a/src/Monolog/Handler/NoopHandler.php +++ b/src/Monolog/Handler/NoopHandler.php @@ -25,7 +25,7 @@ class NoopHandler extends Handler { /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -33,7 +33,7 @@ public function isHandling(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 923d59283..58579cd7d 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -40,7 +40,7 @@ public function __construct(string|int|Level|LevelName $level = Level::Debug) } /** - * {@inheritDoc} + * @inheritDoc */ public function isHandling(LogRecord $record): bool { @@ -48,7 +48,7 @@ public function isHandling(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index bd62316ec..a72b7a11d 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -37,18 +37,17 @@ */ class OverflowHandler extends AbstractHandler implements FormattableHandlerInterface { - /** @var HandlerInterface */ - private $handler; + private HandlerInterface $handler; /** @var array */ - private $thresholdMap = []; + private array $thresholdMap = []; /** * Buffer of all messages passed to the handler before the threshold was reached * * @var mixed[][] */ - private $buffer = []; + private array $buffer = []; /** * @param array $thresholdMap Dictionary of log level value => threshold @@ -76,7 +75,7 @@ public function __construct( * 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 { @@ -113,7 +112,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -127,7 +126,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index ff6c707f3..ccd44785a 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -42,7 +42,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler { /** @var array */ - private $options = [ + private array $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 @@ -65,8 +65,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'dataStorage' => null, // \PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) ]; - /** @var Connector */ - private $connector; + private Connector $connector; /** * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details @@ -243,7 +242,7 @@ private function getRecordTags(LogRecord $record): array } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index c43b88631..e5f619456 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -34,20 +34,14 @@ class ProcessHandler extends AbstractProcessingHandler */ private $process; - /** - * @var string - */ - private $command; + private string $command; - /** - * @var string|null - */ - private $cwd; + private ?string $cwd; /** * @var resource[] */ - private $pipes = []; + private array $pipes = []; /** * @var array @@ -177,7 +171,7 @@ protected function writeProcessInput(string $string): void } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 217b21365..7c4a88879 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -26,10 +26,10 @@ trait ProcessableHandlerTrait * @var callable[] * @phpstan-var array<(callable(LogRecord): LogRecord)|ProcessorInterface> */ - protected $processors = []; + protected array $processors = []; /** - * {@inheritDoc} + * @inheritDoc */ public function pushProcessor(callable $callback): HandlerInterface { @@ -39,7 +39,7 @@ public function pushProcessor(callable $callback): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function popProcessor(): callable { diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 6b45c3d6f..e8fc65e22 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -29,15 +29,10 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface { /** * PSR-3 compliant logger - * - * @var LoggerInterface */ - protected $logger; + protected LoggerInterface $logger; - /** - * @var FormatterInterface|null - */ - protected $formatter; + protected FormatterInterface|null $formatter = null; /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied @@ -50,7 +45,7 @@ public function __construct(LoggerInterface $logger, $level = Level::Debug, bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index c2a3129af..cf52dc347 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -26,30 +26,25 @@ */ class PushoverHandler extends SocketHandler { - /** @var string */ - private $token; + private string $token; /** @var array */ - private $users; - /** @var string */ - private $title; + private array $users; + private string $title; /** @var string|int|null */ private $user = null; - /** @var int */ - private $retry; - /** @var int */ - private $expire; + private int $retry; + private int $expire; private Level $highPriorityLevel; private Level $emergencyLevel; - /** @var bool */ - private $useFormattedMessage = false; + private bool $useFormattedMessage = false; /** * All parameters that can be sent to Pushover * @see https://pushover.net/api * @var array */ - private $parameterNames = [ + private array $parameterNames = [ 'token' => true, 'user' => true, 'message' => true, @@ -70,7 +65,7 @@ class PushoverHandler extends SocketHandler * @see https://pushover.net/api#sounds * @var string[] */ - private $sounds = [ + private array $sounds = [ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb', 'persistent', 'echo', 'updown', 'none', diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index a559f5ffd..fa1f06e49 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -31,10 +31,8 @@ class RedisHandler extends AbstractProcessingHandler { /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; - /** @var string */ - private $redisKey; - /** @var int */ - protected $capSize; + private string $redisKey; + protected int $capSize; /** * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance @@ -55,7 +53,7 @@ public function __construct($redis, string $key, $level = Level::Debug, bool $bu } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -89,7 +87,7 @@ protected function writeCapped(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 004ca6058..c9ef5cd87 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -31,8 +31,7 @@ class RedisPubSubHandler extends AbstractProcessingHandler { /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; - /** @var string */ - private $channelKey; + private string $channelKey; /** * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance @@ -51,7 +50,7 @@ public function __construct($redis, string $key, $level = Level::Debug, bool $bu } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -59,7 +58,7 @@ protected function write(LogRecord $record): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index fd5d127d6..a0fe5469a 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -35,20 +35,14 @@ */ class RollbarHandler extends AbstractProcessingHandler { - /** - * @var RollbarLogger - */ - protected $rollbarLogger; + protected RollbarLogger $rollbarLogger; /** * Records whether any log records have been added since the last flush of the rollbar notifier - * - * @var bool */ - private $hasRecords = false; + private bool $hasRecords = false; - /** @var bool */ - protected $initialized = false; + protected bool $initialized = false; /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token @@ -80,7 +74,7 @@ protected function toRollbarLevel(Level $level): string } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -121,7 +115,7 @@ public function flush(): void } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -129,9 +123,9 @@ public function close(): void } /** - * {@inheritDoc} + * @inheritDoc */ - public function reset() + public function reset(): void { $this->flush(); diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index c0d491db3..44f78c48f 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -31,18 +31,12 @@ class RotatingFileHandler extends StreamHandler public const FILE_PER_MONTH = 'Y-m'; public const FILE_PER_YEAR = 'Y'; - /** @var string */ - protected $filename; - /** @var int */ - protected $maxFiles; - /** @var bool */ - protected $mustRotate; - /** @var \DateTimeImmutable */ - protected $nextRotation; - /** @var string */ - protected $filenameFormat; - /** @var string */ - protected $dateFormat; + protected string $filename; + protected int $maxFiles; + protected bool|null $mustRotate = null; + protected \DateTimeImmutable $nextRotation; + protected string $filenameFormat; + protected string $dateFormat; /** * @param int $maxFiles The maximal amount of files to keep (0 means unlimited) @@ -61,7 +55,7 @@ public function __construct(string $filename, int $maxFiles = 0, $level = Level: } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -73,9 +67,9 @@ public function close(): void } /** - * {@inheritDoc} + * @inheritDoc */ - public function reset() + public function reset(): void { parent::reset(); @@ -108,7 +102,7 @@ public function setFilenameFormat(string $filenameFormat, string $dateFormat): s } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 8238de846..753190a93 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -38,10 +38,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter */ protected $handler; - /** - * @var int $factor - */ - protected $factor; + protected int $factor; /** * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler @@ -82,10 +79,8 @@ public function handle(LogRecord $record): bool * Return the nested handler * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. - * - * @return HandlerInterface */ - public function getHandler(LogRecord $record = null) + public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $this->handler = ($this->handler)($record, $this); @@ -98,7 +93,7 @@ public function getHandler(LogRecord $record = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -113,7 +108,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritDoc} + * @inheritDoc */ public function getFormatter(): FormatterInterface { diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 50b23e2c7..6752671b0 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -22,33 +22,29 @@ class SendGridHandler extends MailHandler { /** * The SendGrid API User - * @var string */ - protected $apiUser; + protected string $apiUser; /** * The SendGrid API Key - * @var string */ - protected $apiKey; + protected string $apiKey; /** * The email addresses to which the message will be sent - * @var string */ - protected $from; + protected string $from; /** * The email addresses to which the message will be sent * @var string[] */ - protected $to; + protected array $to; /** * The subject of the email - * @var string */ - protected $subject; + protected string $subject; /** * @param string $apiUser The SendGrid API User @@ -72,7 +68,7 @@ public function __construct(string $apiUser, string $apiKey, string $from, $to, } /** - * {@inheritDoc} + * @inheritDoc */ protected function send(string $content, array $records): void { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 141342bd1..4ef5f454c 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -37,55 +37,46 @@ class SlackRecord /** * Slack channel (encoded ID or name) - * @var string|null */ - private $channel; + private ?string $channel; /** * Name of a bot - * @var string|null */ - private $username; + private ?string $username; /** * User icon e.g. 'ghost', 'http://example.com/user.png' - * @var string|null */ - private $userIcon; + private ?string $userIcon; /** * Whether the message should be added to Slack as attachment (plain text otherwise) - * @var bool */ - private $useAttachment; + private bool $useAttachment; /** * Whether the the context/extra messages added to Slack as attachments are in a short style - * @var bool */ - private $useShortAttachment; + private bool $useShortAttachment; /** * Whether the attachment should include context and extra data - * @var bool */ - private $includeContextAndExtra; + private bool $includeContextAndExtra; /** * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @var string[] */ - private $excludeFields; + private array $excludeFields; /** * @var ?FormatterInterface */ private $formatter; - /** - * @var NormalizerFormatter - */ - private $normalizerFormatter; + private NormalizerFormatter $normalizerFormatter; /** * @param string[] $excludeFields diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 063606a4b..6360e0227 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -27,15 +27,13 @@ class SlackHandler extends SocketHandler { /** * Slack API token - * @var string */ - private $token; + private string $token; /** * Instance of the SlackRecord util class preparing data for Slack API. - * @var SlackRecord */ - private $slackRecord; + private SlackRecord $slackRecord; /** * @param string $token Slack API token @@ -104,7 +102,7 @@ public function getToken(): string } /** - * {@inheritDoc} + * @inheritDoc */ protected function generateDataStream(LogRecord $record): string { @@ -153,7 +151,7 @@ private function buildHeader(string $content): string } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index c0f2aaba0..14ed6b1fb 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -27,15 +27,13 @@ class SlackWebhookHandler extends AbstractProcessingHandler { /** * Slack Webhook token - * @var string */ - private $webhookUrl; + private string $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. - * @var SlackRecord */ - private $slackRecord; + private SlackRecord $slackRecord; /** * @param string $webhookUrl Slack Webhook URL @@ -89,7 +87,7 @@ public function getWebhookUrl(): string } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 517c12f80..8bcecb2d7 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -22,22 +22,17 @@ */ class SocketHandler extends AbstractProcessingHandler { - /** @var string */ - private $connectionString; - /** @var float */ - private $connectionTimeout; + private string $connectionString; + private float $connectionTimeout; /** @var resource|null */ private $resource; - /** @var float */ - private $timeout; - /** @var float */ - private $writingTimeout; + private float $timeout; + private float $writingTimeout; /** @var ?int */ private $lastSentBytes = null; /** @var ?int */ private $chunkSize; - /** @var bool */ - private $persistent; + private bool $persistent; /** @var ?int */ private $errno = null; /** @var ?string */ @@ -85,7 +80,7 @@ public function __construct( /** * Connect (if necessary) and write to the socket * - * {@inheritDoc} + * @inheritDoc * * @throws \UnexpectedValueException * @throws \RuntimeException @@ -260,10 +255,8 @@ protected function fsockopen() * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-timeout.php - * - * @return bool */ - protected function streamSetTimeout() + protected function streamSetTimeout(): bool { $seconds = floor($this->timeout); $microseconds = round(($this->timeout - $seconds) * 1e6); diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index fe9e1ecdc..ae91d4a33 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -28,10 +28,8 @@ class SqsHandler extends AbstractProcessingHandler /** 100 KB in bytes - head message size for new error log */ protected const HEAD_MESSAGE_SIZE = 102400; - /** @var SqsClient */ - private $client; - /** @var string */ - private $queueUrl; + private SqsClient $client; + private string $queueUrl; public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Level::Debug, bool $bubble = true) { @@ -42,7 +40,7 @@ public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Lev } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index a63d0140f..dd60b71e9 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -28,8 +28,7 @@ class StreamHandler extends AbstractProcessingHandler protected const MAX_CHUNK_SIZE = 2147483647; /** @const int 10MB */ protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; - /** @var int */ - protected $streamChunkSize; + protected int $streamChunkSize; /** @var resource|null */ protected $stream; /** @var ?string */ @@ -38,10 +37,9 @@ class StreamHandler extends AbstractProcessingHandler private $errorMessage = null; /** @var ?int */ protected $filePermission; - /** @var bool */ - protected $useLocking; + protected bool $useLocking; /** @var true|null */ - private $dirCreated = null; + private ?bool $dirCreated = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write @@ -82,7 +80,7 @@ public function __construct($stream, $level = Level::Debug, bool $bubble = true, } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -111,15 +109,13 @@ public function getUrl(): ?string return $this->url; } - /** - */ public function getStreamChunkSize(): int { return $this->streamChunkSize; } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 04b3f07e6..02990339d 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -30,10 +30,8 @@ */ class SyslogHandler extends AbstractSyslogHandler { - /** @var string */ - protected $ident; - /** @var int */ - protected $logopts; + protected string $ident; + protected int $logopts; /** * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant @@ -48,7 +46,7 @@ public function __construct(string $ident, $facility = LOG_USER, $level = Level: } /** - * {@inheritDoc} + * @inheritDoc */ public function close(): void { @@ -56,7 +54,7 @@ public function close(): void } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 059286790..e5fc753d6 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -18,12 +18,9 @@ class UdpSocket { protected const DATAGRAM_MAX_LENGTH = 65023; - /** @var string */ - protected $ip; - /** @var int */ - protected $port; - /** @var Socket|null */ - protected $socket; + protected string $ip; + protected int $port; + protected ?Socket $socket; public function __construct(string $ip, int $port = 514) { @@ -39,12 +36,7 @@ public function __construct(string $ip, int $port = 514) $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } - /** - * @param string $line - * @param string $header - * @return void - */ - public function write($line, $header = "") + public function write(string $line, string $header = ""): void { $this->send($this->assembleMessage($line, $header)); } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 3c0705213..a00a1b7ce 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -30,16 +30,14 @@ class SyslogUdpHandler extends AbstractSyslogHandler const RFC5424e = 2; /** @var array */ - private $dateFormats = [ + private array $dateFormats = [ self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, self::RFC5424e => \DateTime::RFC3339_EXTENDED, ]; - /** @var UdpSocket */ - protected $socket; - /** @var string */ - protected $ident; + protected UdpSocket $socket; + protected string $ident; /** @var self::RFC* */ protected $rfc; diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 3125e8e66..3ff49f081 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -51,16 +51,14 @@ 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 $apiKey; + private string $apiKey; /** * Telegram channel name. * Since to start with '@' symbol as prefix. - * @var string */ - private $channel; + private string $channel; /** * The kind of formatting that is used for the message. @@ -85,15 +83,13 @@ 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. - * @var bool */ - private $splitLongMessages; + private bool $splitLongMessages; /** * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). - * @var bool */ - private $delayBetweenMessages; + private bool $delayBetweenMessages; /** * @param string $apiKey Telegram bot access token provided by BotFather @@ -177,7 +173,7 @@ public function delayBetweenMessages(bool $delayBetweenMessages = false): self } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 8c23d4161..e7d47e0bd 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -72,43 +72,33 @@ class TestHandler extends AbstractProcessingHandler { /** @var LogRecord[] */ - protected $records = []; + protected array $records = []; /** @phpstan-var array, LogRecord[]> */ protected array $recordsByLevel = []; - /** @var bool */ - private $skipReset = false; + private bool $skipReset = false; /** * @return array */ - public function getRecords() + public function getRecords(): array { return $this->records; } - /** - * @return void - */ - public function clear() + public function clear(): void { $this->records = []; $this->recordsByLevel = []; } - /** - * @return void - */ - public function reset() + public function reset(): void { if (!$this->skipReset) { $this->clear(); } } - /** - * @return void - */ - public function setSkipReset(bool $skipReset) + public function setSkipReset(bool $skipReset): void { $this->skipReset = $skipReset; } @@ -177,7 +167,7 @@ public function hasRecordThatPasses(callable $predicate, Level $level): bool } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -186,11 +176,9 @@ protected function write(LogRecord $record): void } /** - * @param string $method - * @param mixed[] $args - * @return bool + * @param mixed[] $args */ - public function __call($method, $args) + public function __call(string $method, array $args): bool { if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 8d4dd2b8e..d891c25d0 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -23,7 +23,7 @@ class WhatFailureGroupHandler extends GroupHandler { /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { @@ -43,7 +43,7 @@ public function handle(LogRecord $record): bool } /** - * {@inheritDoc} + * @inheritDoc */ public function handleBatch(array $records): void { diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index e63356337..9db02765b 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -56,7 +56,7 @@ protected function toZendMonitorLevel(Level $level): int } /** - * {@inheritDoc} + * @inheritDoc */ protected function write(LogRecord $record): void { @@ -81,7 +81,7 @@ protected function writeZendMonitorCustomEvent(string $type, string $message, ar } /** - * {@inheritDoc} + * @inheritDoc */ public function getDefaultFormatter(): FormatterInterface { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index e38f87d1d..405acec75 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -106,17 +106,14 @@ class Logger implements LoggerInterface, ResettableInterface */ public const API = 3; - /** - * @var string - */ - protected $name; + protected string $name; /** * The handler stack * * @var HandlerInterface[] */ - protected $handlers; + protected array $handlers; /** * Processors that will process all log records @@ -127,15 +124,9 @@ class Logger implements LoggerInterface, ResettableInterface */ protected $processors; - /** - * @var bool - */ - protected $microsecondTimestamps = true; + protected bool $microsecondTimestamps = true; - /** - * @var DateTimeZone - */ - protected $timezone; + protected DateTimeZone $timezone; /** * @var callable|null @@ -150,7 +141,7 @@ class Logger implements LoggerInterface, ResettableInterface * * @phpstan-param array<(callable(LogRecord): LogRecord)|ProcessorInterface> $processors */ - public function __construct(string $name, array $handlers = [], array $processors = [], ?DateTimeZone $timezone = null) + public function __construct(string $name, array $handlers = [], array $processors = [], DateTimeZone|null $timezone = null) { $this->name = $name; $this->setHandlers($handlers); diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 2cefe4521..4b0351c41 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -40,7 +40,7 @@ public function __construct(int|string|Level|LevelName $level = Level::Debug) } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index b999b2842..cba6e0963 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -18,8 +18,7 @@ */ class HostnameProcessor implements ProcessorInterface { - /** @var string */ - private static $host; + private static string $host; public function __construct() { @@ -27,7 +26,7 @@ public function __construct() } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 8ff10818d..1a8f67f64 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -56,7 +56,7 @@ public function __construct(int|string|Level|LevelName $level = Level::Debug, ar } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index 3e98c4808..adc32c65d 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -22,7 +22,7 @@ class MemoryPeakUsageProcessor extends MemoryProcessor { /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/MemoryProcessor.php b/src/Monolog/Processor/MemoryProcessor.php index 89baadbf0..f808e51b4 100644 --- a/src/Monolog/Processor/MemoryProcessor.php +++ b/src/Monolog/Processor/MemoryProcessor.php @@ -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 $realUsage; + protected bool $realUsage; /** * @var bool If true, then format memory size to human readable string (MB, KB, B depending on size) */ - protected $useFormatting; + protected bool $useFormatting; /** * @param bool $realUsage Set this to true to get the real size of memory allocated from system. diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index fa48d2466..a814b1df3 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -22,7 +22,7 @@ class MemoryUsageProcessor extends MemoryProcessor { /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 37222a344..4af2ffc4e 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -39,7 +39,7 @@ public function __construct(int|string|Level|LevelName $level = Level::Debug) } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 686c50491..bb9a52243 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -21,7 +21,7 @@ class ProcessIdProcessor implements ProcessorInterface { /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index ebe41fc20..a044f1cdb 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -23,5 +23,5 @@ interface ProcessorInterface /** * @return LogRecord The processed record */ - public function __invoke(LogRecord $record); + public function __invoke(LogRecord $record): LogRecord; } diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 5f6aede14..b51f42a73 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -25,11 +25,9 @@ class PsrLogMessageProcessor implements ProcessorInterface { public const SIMPLE_DATE = "Y-m-d\TH:i:s.uP"; - /** @var string|null */ - private $dateFormat; + private ?string $dateFormat; - /** @var bool */ - private $removeUsedContextFields; + private bool $removeUsedContextFields; /** * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format @@ -42,7 +40,7 @@ public function __construct(?string $dateFormat = null, bool $removeUsedContextF } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index bbb7793c0..4543ccf61 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -21,7 +21,7 @@ class TagProcessor implements ProcessorInterface { /** @var string[] */ - private $tags; + private array $tags; /** * @param string[] $tags @@ -52,7 +52,7 @@ public function setTags(array $tags = []): self } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 835307ef4..3a0c128c2 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -37,7 +37,7 @@ public function __construct(int $length = 7) } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { @@ -51,7 +51,7 @@ public function getUid(): string return $this->uid; } - public function reset() + public function reset(): void { $this->uid = $this->generateUid(strlen($this->uid)); } diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 27496ebb8..e24dc6294 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -32,7 +32,7 @@ class WebProcessor implements ProcessorInterface * * @var array */ - protected $extraFields = [ + protected array $extraFields = [ 'url' => 'REQUEST_URI', 'ip' => 'REMOTE_ADDR', 'http_method' => 'REQUEST_METHOD', @@ -76,7 +76,7 @@ public function __construct($serverData = null, array $extraFields = null) } /** - * {@inheritDoc} + * @inheritDoc */ public function __invoke(LogRecord $record): LogRecord { diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index ae94ae6cc..08bf02dea 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -42,7 +42,7 @@ class Registry * * @var Logger[] */ - private static $loggers = []; + private static array $loggers = []; /** * Adds new logging channel to the registry @@ -51,9 +51,8 @@ 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) + public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false): void { $name = $name ?: $logger->getName(); @@ -110,7 +109,7 @@ public static function clear(): void * @param string $name Name of the requested Logger instance * @throws \InvalidArgumentException If named Logger instance is not in the registry */ - public static function getInstance($name): Logger + public static function getInstance(string $name): Logger { if (!isset(self::$loggers[$name])) { throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name)); @@ -127,7 +126,7 @@ public static function getInstance($name): Logger * @throws \InvalidArgumentException If named Logger instance is not in the registry * @return Logger Requested instance of Logger */ - public static function __callStatic($name, $arguments) + public static function __callStatic(string $name, array $arguments): Logger { return self::getInstance($name); } diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php index 2c5fd7851..4983a6b35 100644 --- a/src/Monolog/ResettableInterface.php +++ b/src/Monolog/ResettableInterface.php @@ -27,8 +27,5 @@ */ interface ResettableInterface { - /** - * @return void - */ - public function reset(); + public function reset(): void; } diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 8c0227305..546accb29 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -22,15 +22,14 @@ */ class SignalHandler { - /** @var LoggerInterface */ - private $logger; + private LoggerInterface $logger; /** @var array SIG_DFL, SIG_IGN or previous callable */ - private $previousSignalHandler = []; + private array $previousSignalHandler = []; /** @var array */ - private $signalLevelMap = []; + private array $signalLevelMap = []; /** @var array */ - private $signalRestartSyscalls = []; + private array $signalRestartSyscalls = []; public function __construct(LoggerInterface $logger) { diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index bc637efdf..01f875451 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -125,7 +125,6 @@ public function testCodeToString() $this->assertEquals('E_DEPRECATED', $method->invokeArgs(null, [E_DEPRECATED])); $this->assertEquals('E_USER_DEPRECATED', $method->invokeArgs(null, [E_USER_DEPRECATED])); - $this->assertEquals('Unknown PHP error', $method->invokeArgs(null, ['RANDOM_TEXT'])); $this->assertEquals('Unknown PHP error', $method->invokeArgs(null, [E_ALL])); } } diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index d8334f138..7a172dd28 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -191,12 +191,9 @@ public function testDefFormatWithResource() } /** - * @param string $expected - * @param string $actual - * * @internal param string $exception */ - private function assertContextContainsFormattedException($expected, $actual) + private function assertContextContainsFormattedException(string $expected, string $actual) { $this->assertEquals( '{"message":"foobar","context":{"exception":'.$expected.'},"level":500,"level_name":"CRITICAL","channel":"core","datetime":"2022-02-22T00:00:00+00:00","extra":{}}'."\n", @@ -204,10 +201,7 @@ private function assertContextContainsFormattedException($expected, $actual) ); } - /** - * @return string - */ - private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \Throwable $exception) + private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \Throwable $exception): string { $message = $formatter->format($this->getRecord( Level::Critical, @@ -222,10 +216,8 @@ private function formatRecordWithExceptionInContext(JsonFormatter $formatter, \T /** * @param \Exception|\Throwable $exception - * - * @return string */ - private function formatExceptionFilePathWithLine($exception) + private function formatExceptionFilePathWithLine($exception): string { $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; $path = substr(json_encode($exception->getFile(), $options), 1, -1); @@ -235,12 +227,8 @@ private function formatExceptionFilePathWithLine($exception) /** * @param \Exception|\Throwable $exception - * - * @param null|string $previous - * - * @return string */ - private function formatException($exception, $previous = null) + private function formatException($exception, ?string $previous = null): string { $formattedException = '{"class":"' . get_class($exception) . diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 0c61cf227..f34b7cc04 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -371,10 +371,7 @@ public function testExceptionTraceWithArgs() ); } - /** - * @return string - */ - private function formatRecordWithExceptionInContext(NormalizerFormatter $formatter, \Throwable $exception) + private function formatRecordWithExceptionInContext(NormalizerFormatter $formatter, \Throwable $exception): array { $message = $formatter->format($this->getRecord( Level::Critical, diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 8791c7058..a63b93605 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -24,12 +24,12 @@ class ElasticaHandlerTest extends TestCase /** * @var Client mock */ - protected $client; + protected Client $client; /** * @var array Default handler options */ - protected $options = [ + protected array $options = [ 'index' => 'my_index', 'type' => 'doc_type', ]; @@ -136,10 +136,7 @@ public function testConnectionErrors($ignore, $expectedError) } } - /** - * @return array - */ - public function providerTestConnectionErrors() + public function providerTestConnectionErrors(): array { return [ [false, ['RuntimeException', 'Error sending messages to Elasticsearch']], @@ -241,10 +238,9 @@ public function testHandleIntegrationNewESVersion() /** * Return last created document id from ES response - * @param Response $response Elastica Response object - * @return string|null + * @param Response $response Elastica Response object */ - protected function getCreatedDocId(Response $response) + protected function getCreatedDocId(Response $response): ?string { $data = $response->getData(); if (!empty($data['items'][0]['create']['_id'])) { @@ -254,13 +250,10 @@ protected function getCreatedDocId(Response $response) /** * Retrieve document by id from Elasticsearch - * @param Client $client Elastica client - * @param string $index - * @param ?string $type - * @param string $documentId - * @return array + * @param Client $client Elastica client + * @param ?string $type */ - protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + protected function getDocSourceFromElastic(Client $client, string $index, $type, string $documentId): array { if ($type === null) { $path = "/{$index}/_doc/{$documentId}"; diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 9009b71d4..792c6dc9b 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -23,12 +23,12 @@ class ElasticsearchHandlerTest extends TestCase /** * @var Client mock */ - protected $client; + protected Client $client; /** * @var array Default handler options */ - protected $options = [ + protected array $options = [ 'index' => 'my_index', 'type' => 'doc_type', ]; @@ -151,10 +151,7 @@ public function testConnectionErrors($ignore, $expectedError) } } - /** - * @return array - */ - public function providerTestConnectionErrors() + public function providerTestConnectionErrors(): array { return [ [false, ['RuntimeException', 'Error sending messages to Elasticsearch']], @@ -215,10 +212,9 @@ public function testHandleIntegration() /** * Return last created document id from ES response * - * @param array $info Elasticsearch last request info - * @return string|null + * @param array $info Elasticsearch last request info */ - protected function getCreatedDocId(array $info) + protected function getCreatedDocId(array $info): ?string { $data = json_decode($info['response']['body'], true); @@ -230,13 +226,9 @@ protected function getCreatedDocId(array $info) /** * Retrieve document by id from Elasticsearch * - * @param Client $client Elasticsearch client - * @param string $index - * @param string $type - * @param string $documentId - * @return array + * @param Client $client Elasticsearch client */ - protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + protected function getDocSourceFromElastic(Client $client, string $index, string $type, string $documentId): array { $params = [ 'index' => $index, diff --git a/tests/Monolog/Handler/ExceptionTestHandler.php b/tests/Monolog/Handler/ExceptionTestHandler.php index 721f1fc1d..bd4031f53 100644 --- a/tests/Monolog/Handler/ExceptionTestHandler.php +++ b/tests/Monolog/Handler/ExceptionTestHandler.php @@ -17,7 +17,7 @@ class ExceptionTestHandler extends TestHandler { /** - * {@inheritDoc} + * @inheritDoc */ public function handle(LogRecord $record): bool { diff --git a/tests/Monolog/Handler/FleepHookHandlerTest.php b/tests/Monolog/Handler/FleepHookHandlerTest.php index 4f865526a..75cd32be6 100644 --- a/tests/Monolog/Handler/FleepHookHandlerTest.php +++ b/tests/Monolog/Handler/FleepHookHandlerTest.php @@ -25,10 +25,7 @@ class FleepHookHandlerTest extends TestCase */ const TOKEN = '123abc'; - /** - * @var FleepHookHandler - */ - private $handler; + private FleepHookHandler $handler; public function setUp(): void { diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 102430988..7c630034a 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -26,10 +26,7 @@ class FlowdockHandlerTest extends TestCase */ private $res; - /** - * @var FlowdockHandler - */ - private $handler; + private FlowdockHandler $handler; public function setUp(): void { diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index 87a117b18..44c4fa794 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -18,10 +18,7 @@ */ class HandlerWrapperTest extends TestCase { - /** - * @var HandlerWrapper - */ - private $wrapper; + private HandlerWrapper $wrapper; private $handler; @@ -32,10 +29,7 @@ public function setUp(): void $this->wrapper = new HandlerWrapper($this->handler); } - /** - * @return array - */ - public function trueFalseDataProvider() + public function trueFalseDataProvider(): array { return [ [true], diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index d7e884e0b..213d89eda 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Level; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Robert Kaufmann III @@ -25,10 +26,7 @@ class InsightOpsHandlerTest extends TestCase */ private $resource; - /** - * @var LogEntriesHandler - */ - private $handler; + private InsightOpsHandler&MockObject $handler; public function testWriteContent() { diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 2f49fa912..29b8c88c8 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Level; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Robert Kaufmann III @@ -24,10 +25,7 @@ class LogEntriesHandlerTest extends TestCase */ private $res; - /** - * @var LogEntriesHandler - */ - private $handler; + private LogEntriesHandler&MockObject $handler; public function testWriteContent() { diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index 953ca14b8..e8ecfcdeb 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Level; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Julien Breux @@ -24,10 +25,7 @@ class LogmaticHandlerTest extends TestCase */ private $res; - /** - * @var LogmaticHandler - */ - private $handler; + private LogmaticHandler&MockObject $handler; public function testWriteContent() { diff --git a/tests/Monolog/Handler/ProcessHandlerTest.php b/tests/Monolog/Handler/ProcessHandlerTest.php index daa4ae55b..38eb31953 100644 --- a/tests/Monolog/Handler/ProcessHandlerTest.php +++ b/tests/Monolog/Handler/ProcessHandlerTest.php @@ -57,10 +57,8 @@ public function testWriteOpensProcessAndWritesToStdInOfProcess() /** * Data provider for invalid commands. - * - * @return array */ - public function invalidCommandProvider() + public function invalidCommandProvider(): array { return [ [1337, 'TypeError'], @@ -83,10 +81,8 @@ public function testConstructWithInvalidCommandThrowsInvalidArgumentException($i /** * Data provider for invalid CWDs. - * - * @return array */ - public function invalidCwdProvider() + public function invalidCwdProvider(): array { return [ [1337, 'TypeError'], diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 2b252ef5b..1454896c0 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -27,15 +27,9 @@ */ class RollbarHandlerTest extends TestCase { - /** - * @var MockObject - */ - private $rollbarLogger; + private RollbarLogger&MockObject $rollbarLogger; - /** - * @var array - */ - private $reportedExceptionArguments = null; + private array $reportedExceptionArguments; protected function setUp(): void { diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index eaa0ae5a2..f76b61a55 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -65,10 +65,7 @@ public function testNoUsernameByDefault() $this->assertArrayNotHasKey('username', $data); } - /** - * @return array - */ - public function dataStringify() + public function dataStringify(): array { $multipleDimensions = [[1, 2]]; $numericKeys = ['library' => 'monolog']; diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index dd63a4019..c2d93cb1f 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -27,10 +27,7 @@ class SlackHandlerTest extends TestCase */ private $res; - /** - * @var SlackHandler - */ - private $handler; + private SlackHandler $handler; public function setUp(): void { diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index a55981ea0..f763e3026 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -261,9 +261,8 @@ public function provideMemoryValues() /** * @dataProvider provideMemoryValues - * @return void */ - public function testPreventOOMError($phpMemory, $expectedChunkSize) + public function testPreventOOMError($phpMemory, $expectedChunkSize): void { $previousValue = ini_set('memory_limit', $phpMemory); @@ -287,10 +286,7 @@ public function testPreventOOMError($phpMemory, $expectedChunkSize) $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); } - /** - * @return void - */ - public function testSimpleOOMPrevention() + public function testSimpleOOMPrevention(): void { $previousValue = ini_set('memory_limit', '2048M'); diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 2a055bce7..5aa50c405 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Level; use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Mazur Alexandr @@ -20,10 +21,7 @@ */ class TelegramBotHandlerTest extends TestCase { - /** - * @var TelegramBotHandler - */ - private $handler; + private TelegramBotHandler&MockObject $handler; public function testSendTelegramRequest(): void { @@ -31,8 +29,6 @@ public function testSendTelegramRequest(): void $this->handler->handle($this->getRecord()); } - /** - */ private function createHandler( string $apiKey = 'testKey', string $channel = 'testChannel', diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index c1b4a1e63..35cf76ea2 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -15,10 +15,12 @@ use Monolog\Handler\TestHandler; use Monolog\Formatter\LineFormatter; use Monolog\Processor\PsrLogMessageProcessor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\InvalidArgumentException; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; +use Stringable; class PsrLogCompatTest extends TestCase { @@ -153,13 +155,11 @@ public function testContextExceptionKeyCanBeExceptionOrOtherValues() /** * Creates a mock of a `Stringable`. * - * @param string $string The string that must be represented by the stringable. - * @return \PHPUnit_Framework_MockObject_MockObject A mock of an object that has a `__toString()` method. + * @param string $string The string that must be represented by the stringable. */ - protected function createStringable($string = '') + protected function createStringable(string $string = ''): MockObject&Stringable { - $mock = $this->getMockBuilder('Stringable') - ->setMethods(['__toString']) + $mock = $this->getMockBuilder(Stringable::class) ->getMock(); $mock->method('__toString') diff --git a/tests/Monolog/UtilsTest.php b/tests/Monolog/UtilsTest.php index 08d127b15..60a662128 100644 --- a/tests/Monolog/UtilsTest.php +++ b/tests/Monolog/UtilsTest.php @@ -14,11 +14,9 @@ class UtilsTest extends \PHPUnit_Framework_TestCase { /** - * @param string $expected - * @param object $object * @dataProvider provideObjects */ - public function testGetClass($expected, $object) + public function testGetClass(string $expected, object $object) { $this->assertSame($expected, Utils::getClass($object)); } @@ -35,11 +33,9 @@ public function provideObjects() } /** - * @param string $expected - * @param string $input * @dataProvider providePathsToCanonicalize */ - public function testCanonicalizePath($expected, $input) + public function testCanonicalizePath(string $expected, string $input) { $this->assertSame($expected, Utils::canonicalizePath($input)); } @@ -58,11 +54,9 @@ public function providePathsToCanonicalize() } /** - * @param int $code - * @param string $msg * @dataProvider providesHandleJsonErrorFailure */ - public function testHandleJsonErrorFailure($code, $msg) + public function testHandleJsonErrorFailure(int $code, string $msg) { $this->expectException('RuntimeException', $msg); Utils::handleJsonError($code, 'faked'); @@ -114,10 +108,8 @@ public function providesDetectAndCleanUtf8() /** * @dataProvider providesPcreLastErrorMessage - * @param int $code - * @param string $msg */ - public function testPcreLastErrorMessage($code, $msg) + public function testPcreLastErrorMessage(int $code, string $msg) { if (PHP_VERSION_ID >= 80000) { $this->assertSame('No error', Utils::pcreLastErrorMessage($code)); @@ -131,7 +123,7 @@ public function testPcreLastErrorMessage($code, $msg) /** * @return array[] */ - public function providesPcreLastErrorMessage() + public function providesPcreLastErrorMessage(): array { return [ [0, 'PREG_NO_ERROR'], From 6634bd9b7942e3cffad755e63ed76f0015865a1c Mon Sep 17 00:00:00 2001 From: systemsolutionweb <88460896+systemsolutionweb@users.noreply.github.com> Date: Wed, 20 Apr 2022 02:25:41 -0500 Subject: [PATCH 426/498] Forgotten config (#1652) --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 52e9cb437..bf5ad4973 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,4 +4,4 @@ /phpstan.neon.dist export-ignore /phpunit.xml.dist export-ignore /_config.yml export-ignore -/UPGRADE.md +/UPGRADE.md export-ignore From 0dac87975ce1e3dbcf8773623ff62a8452ecb8ca Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 21 Apr 2022 21:58:19 +0200 Subject: [PATCH 427/498] Add property types to all properties where possible --- doc/04-extending.md | 6 +-- src/Monolog/ErrorHandler.php | 21 +++++--- src/Monolog/Formatter/ElasticaFormatter.php | 4 +- src/Monolog/Handler/AmqpHandler.php | 8 ++- src/Monolog/Handler/FilterHandler.php | 23 ++++---- src/Monolog/Handler/FingersCrossedHandler.php | 40 ++++++++------ .../Handler/FormattableHandlerTrait.php | 7 +-- src/Monolog/Handler/NewRelicHandler.php | 46 +++++++--------- src/Monolog/Handler/PushoverHandler.php | 10 +++- src/Monolog/Handler/RedisHandler.php | 23 ++++---- src/Monolog/Handler/RedisPubSubHandler.php | 15 +++--- src/Monolog/Handler/SamplingHandler.php | 25 +++++---- src/Monolog/Handler/Slack/SlackRecord.php | 11 ++-- src/Monolog/Handler/SocketHandler.php | 15 ++---- src/Monolog/Handler/StreamHandler.php | 14 ++--- src/Monolog/Handler/SyslogUdpHandler.php | 2 +- src/Monolog/Handler/TelegramBotHandler.php | 9 ++-- src/Monolog/Logger.php | 24 ++++----- src/Monolog/Processor/WebProcessor.php | 15 +++--- tests/Monolog/Formatter/LineFormatterTest.php | 2 +- .../Monolog/Formatter/ScalarFormatterTest.php | 2 +- tests/Monolog/Handler/BufferHandlerTest.php | 2 +- .../Monolog/Handler/ChromePHPHandlerTest.php | 2 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 22 +++----- tests/Monolog/Handler/FirePHPHandlerTest.php | 2 +- tests/Monolog/Handler/HandlerWrapperTest.php | 5 +- .../Monolog/Handler/PHPConsoleHandlerTest.php | 9 ++-- tests/Monolog/Handler/PushoverHandlerTest.php | 6 ++- tests/Monolog/Handler/RedisHandlerTest.php | 7 --- .../Handler/RedisPubSubHandlerTest.php | 7 --- .../Handler/RotatingFileHandlerTest.php | 2 +- tests/Monolog/Handler/SocketHandlerTest.php | 53 +++++++++---------- .../Handler/ZendMonitorHandlerTest.php | 2 - tests/Monolog/Processor/WebProcessorTest.php | 2 +- tests/Monolog/PsrLogCompatTest.php | 2 +- tests/Monolog/SignalHandlerTest.php | 6 +-- 36 files changed, 201 insertions(+), 250 deletions(-) diff --git a/doc/04-extending.md b/doc/04-extending.md index 49cded91b..f5d292ada 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -26,9 +26,9 @@ use Monolog\Handler\AbstractProcessingHandler; class PDOHandler extends AbstractProcessingHandler { - private $initialized = false; - private $pdo; - private $statement; + private bool $initialized = false; + private PDO $pdo; + private PDOStatement $statement; public function __construct(PDO $pdo, $level = Level::Debug, bool $bubble = true) { diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 50e999c35..74d86995e 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -26,28 +26,33 @@ */ class ErrorHandler { - private LoggerInterface $logger; - private Closure|null $previousExceptionHandler = null; + /** @var array an array of class name to LogLevel::* constant mapping */ private array $uncaughtExceptionLevelMap = []; - /** @var callable|true|null */ - private $previousErrorHandler = null; + /** @var Closure|true|null */ + private Closure|bool|null $previousErrorHandler = null; + /** @var array 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; + /** @var mixed|null */ private $lastFatalTrace = null; + private const FATAL_ERRORS = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; - public function __construct(LoggerInterface $logger) - { - $this->logger = $logger; + public function __construct( + private LoggerInterface $logger + ) { } /** @@ -108,7 +113,7 @@ public function registerErrorHandler(array $levelMap = [], bool $callPrevious = $prev = set_error_handler([$this, 'handleError'], $errorTypes); $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); if ($callPrevious) { - $this->previousErrorHandler = $prev ?: true; + $this->previousErrorHandler = $prev !== null ? $prev(...) : true; } else { $this->previousErrorHandler = null; } diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 750a66457..160510ad8 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -27,9 +27,9 @@ class ElasticaFormatter extends NormalizerFormatter protected string $index; /** - * @var ?string Elastic search document type + * @var string|null Elastic search document type */ - protected $type; + protected string|null $type; /** * @param string $index Elastic Search index name diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 8fe564b9d..2c83a207b 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -14,6 +14,7 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; +use Monolog\LevelName; use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; @@ -21,10 +22,7 @@ class AmqpHandler extends AbstractProcessingHandler { - /** - * @var AMQPExchange|AMQPChannel $exchange - */ - protected $exchange; + protected AMQPExchange|AMQPChannel $exchange; protected string $exchangeName; @@ -32,7 +30,7 @@ class AmqpHandler extends AbstractProcessingHandler * @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 = Level::Debug, bool $bubble = true) + public function __construct(AMQPExchange|AMQPChannel $exchange, ?string $exchangeName = null, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { if ($exchange instanceof AMQPChannel) { $this->exchangeName = (string) $exchangeName; diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 631996199..c697e72f6 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Closure; use Monolog\Level; use Monolog\LevelName; use Monolog\Logger; @@ -32,12 +33,11 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese use ProcessableHandlerTrait; /** - * Handler or factory callable($record, $this) + * Handler or factory Closure($record, $this) * - * @var callable|HandlerInterface - * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface + * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ - protected $handler; + protected Closure|HandlerInterface $handler; /** * Minimum level for logs that are passed to handler @@ -53,9 +53,9 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese protected bool $bubble; /** - * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler + * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). + * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|string|Level|LevelName|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int|string|Level|LevelName|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 @@ -63,15 +63,11 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel */ - public function __construct($handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency, bool $bubble = true) + public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::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"); - } } /** @@ -157,10 +153,11 @@ public function handleBatch(array $records): void public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { - $this->handler = ($this->handler)($record, $this); - if (!$this->handler instanceof HandlerInterface) { + $handler = ($this->handler)($record, $this); + if (!$handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } + $this->handler = $handler; } return $this->handler; diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index c500d5b4a..633233e20 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Closure; use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Level; @@ -42,33 +43,41 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa use ProcessableHandlerTrait; /** - * @var callable|HandlerInterface - * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface + * Handler or factory callable($record, $this) + * + * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ - protected $handler; + 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; /** - * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler + * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). - * @param int|string|Level|LevelName|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|LevelName|LogLevel::* $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). + * @param int|string|Level|LevelName|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|LevelName|LogLevel::*|null $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $passthruLevel */ - public function __construct($handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName $passthruLevel = null) + public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName|null $passthruLevel = null) { if (null === $activationStrategy) { $activationStrategy = new ErrorLevelActivationStrategy(Level::Warning); @@ -88,10 +97,6 @@ public function __construct($handler, int|string|Level|LevelName|ActivationStrat 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"); - } } /** @@ -198,10 +203,11 @@ private function flushBuffer(): void public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { - $this->handler = ($this->handler)($record, $this); - if (!$this->handler instanceof HandlerInterface) { + $handler = ($this->handler)($record, $this); + if (!$handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } + $this->handler = $handler; } return $this->handler; diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php index 2bf924d2e..c044e0786 100644 --- a/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -21,10 +21,7 @@ */ trait FormattableHandlerTrait { - /** - * @var ?FormatterInterface - */ - protected $formatter; + protected FormatterInterface|null $formatter = null; /** * @inheritDoc @@ -41,7 +38,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - if (!$this->formatter) { + if (null === $this->formatter) { $this->formatter = $this->getDefaultFormatter(); } diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index b040311a3..78108285e 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -28,41 +29,30 @@ */ class NewRelicHandler extends AbstractProcessingHandler { - /** - * 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? - */ - protected bool $explodeArrays; - /** * @inheritDoc */ public function __construct( - $level = Level::Error, + int|string|Level|LevelName $level = Level::Error, bool $bubble = true, - ?string $appName = null, - bool $explodeArrays = false, - ?string $transactionName = null + + /** + * 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 ) { parent::__construct($level, $bubble); - - $this->appName = $appName; - $this->explodeArrays = $explodeArrays; - $this->transactionName = $transactionName; } /** diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index cf52dc347..d745697cd 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -27,16 +27,22 @@ class PushoverHandler extends SocketHandler { private string $token; + /** @var array */ private array $users; + private string $title; - /** @var string|int|null */ - private $user = null; + + private string|int|null $user = null; + private int $retry; + private int $expire; private Level $highPriorityLevel; + private Level $emergencyLevel; + private bool $useFormattedMessage = false; /** diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index fa1f06e49..9edfa1817 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -14,7 +14,10 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; +use Predis\Client as Predis; +use Redis; /** * Logs to a Redis key using rpush @@ -29,22 +32,18 @@ */ class RedisHandler extends AbstractProcessingHandler { - /** @var \Predis\Client<\Predis\Client>|\Redis */ - private $redisClient; + /** @var Predis|Redis */ + private Predis|Redis $redisClient; private string $redisKey; protected int $capSize; /** - * @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 + * @param 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 */ - public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true, int $capSize = 0) + public function __construct(Predis|Redis $redis, string $key, int|string|Level|LevelName $level = Level::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; @@ -70,8 +69,8 @@ protected function write(LogRecord $record): void */ protected function writeCapped(LogRecord $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) ->ltrim($this->redisKey, -$this->capSize, -1) diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index c9ef5cd87..6c903515a 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -14,7 +14,10 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; +use Predis\Client as Predis; +use Redis; /** * Sends the message to a Redis Pub/Sub channel using PUBLISH @@ -29,20 +32,16 @@ */ class RedisPubSubHandler extends AbstractProcessingHandler { - /** @var \Predis\Client<\Predis\Client>|\Redis */ + /** @var Predis|Redis */ private $redisClient; private string $channelKey; /** - * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance - * @param string $key The channel key to publish records to + * @param Predis|Redis $redis The redis instance + * @param string $key The channel key to publish records to */ - public function __construct($redis, string $key, $level = Level::Debug, bool $bubble = true) + public function __construct(Predis|Redis $redis, string $key, int|string|Level|LevelName $level = Level::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; diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 753190a93..917413ef3 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Closure; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -33,28 +34,25 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter use ProcessableHandlerTrait; /** - * @var HandlerInterface|callable - * @phpstan-var (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface + * Handler or factory callable($record, $this) + * + * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ - protected $handler; + protected Closure|HandlerInterface $handler; protected int $factor; /** - * @phpstan-param (callable(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler + * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @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) + * @param Closure|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($handler, int $factor) + public function __construct(Closure|HandlerInterface $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 @@ -83,10 +81,11 @@ public function handle(LogRecord $record): bool public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { - $this->handler = ($this->handler)($record, $this); - if (!$this->handler instanceof HandlerInterface) { + $handler = ($this->handler)($record, $this); + if (!$handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } + $this->handler = $handler; } return $this->handler; diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 4ef5f454c..f530e3e5e 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -38,17 +38,17 @@ class SlackRecord /** * Slack channel (encoded ID or name) */ - private ?string $channel; + private string|null $channel; /** * Name of a bot */ - private ?string $username; + private string|null $username; /** * User icon e.g. 'ghost', 'http://example.com/user.png' */ - private ?string $userIcon; + private string|null $userIcon; /** * Whether the message should be added to Slack as attachment (plain text otherwise) @@ -71,10 +71,7 @@ class SlackRecord */ private array $excludeFields; - /** - * @var ?FormatterInterface - */ - private $formatter; + private FormatterInterface|null $formatter; private NormalizerFormatter $normalizerFormatter; diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 8bcecb2d7..811159713 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -28,17 +28,12 @@ class SocketHandler extends AbstractProcessingHandler private $resource; private float $timeout; private float $writingTimeout; - /** @var ?int */ - private $lastSentBytes = null; - /** @var ?int */ - private $chunkSize; + private int|null $lastSentBytes = null; + private int|null $chunkSize; private bool $persistent; - /** @var ?int */ - private $errno = null; - /** @var ?string */ - private $errstr = null; - /** @var ?float */ - private $lastWritingAt = null; + private int|null $errno = null; + private string|null $errstr = null; + private float|null $lastWritingAt = null; /** * @param string $connectionString Socket connection string diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index dd60b71e9..504b547ff 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -24,22 +24,18 @@ */ class StreamHandler extends AbstractProcessingHandler { - /** @const int */ protected const MAX_CHUNK_SIZE = 2147483647; - /** @const int 10MB */ + /** 10MB */ protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; protected int $streamChunkSize; /** @var resource|null */ protected $stream; - /** @var ?string */ - protected $url = null; - /** @var ?string */ - private $errorMessage = null; - /** @var ?int */ - protected $filePermission; + protected string|null $url = null; + private string|null $errorMessage = null; + protected int|null $filePermission; protected bool $useLocking; /** @var true|null */ - private ?bool $dirCreated = null; + private bool|null $dirCreated = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index a00a1b7ce..0370cf6eb 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -39,7 +39,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler protected UdpSocket $socket; protected string $ident; /** @var self::RFC* */ - protected $rfc; + protected int $rfc; /** * @param string $host Either IP/hostname or a path to a unix socket (port must be 0 then) diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 3ff49f081..7729d84c7 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -64,21 +64,18 @@ class TelegramBotHandler extends AbstractProcessingHandler * 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 $parseMode; + private string|null $parseMode; /** * Disables link previews for links in the message. - * @var ?bool */ - private $disableWebPagePreview; + private bool|null $disableWebPagePreview; /** * Sends the message silently. Users will receive a notification with no sound. - * @var ?bool */ - private $disableNotification; + private bool|null $disableNotification; /** * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages. diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 405acec75..fa38923a3 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -11,6 +11,7 @@ namespace Monolog; +use Closure; use DateTimeZone; use Monolog\Handler\HandlerInterface; use Monolog\Processor\ProcessorInterface; @@ -101,8 +102,6 @@ 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; @@ -111,7 +110,7 @@ class Logger implements LoggerInterface, ResettableInterface /** * The handler stack * - * @var HandlerInterface[] + * @var list */ protected array $handlers; @@ -122,16 +121,13 @@ class Logger implements LoggerInterface, ResettableInterface * * @var array<(callable(LogRecord): LogRecord)|ProcessorInterface> */ - protected $processors; + protected array $processors; protected bool $microsecondTimestamps = true; protected DateTimeZone $timezone; - /** - * @var callable|null - */ - protected $exceptionHandler; + protected Closure|null $exceptionHandler = null; /** * @param string $name The logging channel, a simple descriptive name that is attached to all log records @@ -182,7 +178,7 @@ public function pushHandler(HandlerInterface $handler): self */ public function popHandler(): HandlerInterface { - if (!$this->handlers) { + if (0 === \count($this->handlers)) { throw new \LogicException('You tried to pop from an empty handler stack.'); } @@ -194,7 +190,7 @@ public function popHandler(): HandlerInterface * * If a map is passed, keys will be ignored. * - * @param HandlerInterface[] $handlers + * @param list $handlers */ public function setHandlers(array $handlers): self { @@ -207,7 +203,7 @@ public function setHandlers(array $handlers): self } /** - * @return HandlerInterface[] + * @return list */ public function getHandlers(): array { @@ -231,7 +227,7 @@ public function pushProcessor(callable $callback): self */ public function popProcessor(): callable { - if (!$this->processors) { + if (0 === \count($this->processors)) { throw new \LogicException('You tried to pop from an empty processor stack.'); } @@ -439,14 +435,14 @@ public function isHandling(int|string|LevelName|Level $level): bool * * The callable will receive an exception object and the record that failed to be logged */ - public function setExceptionHandler(?callable $callback): self + public function setExceptionHandler(Closure|null $callback): self { $this->exceptionHandler = $callback; return $this; } - public function getExceptionHandler(): ?callable + public function getExceptionHandler(): Closure|null { return $this->exceptionHandler; } diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index e24dc6294..947de3627 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -11,6 +11,7 @@ namespace Monolog\Processor; +use ArrayAccess; use Monolog\LogRecord; /** @@ -21,9 +22,9 @@ class WebProcessor implements ProcessorInterface { /** - * @var array|\ArrayAccess + * @var array|ArrayAccess */ - protected $serverData; + protected array|ArrayAccess $serverData; /** * Default fields @@ -42,17 +43,15 @@ class WebProcessor implements ProcessorInterface ]; /** - * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|array|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|ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data + * @param array|array|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($serverData = null, array $extraFields = null) + public function __construct(array|ArrayAccess|null $serverData = null, array|null $extraFields = null) { if (null === $serverData) { $this->serverData = &$_SERVER; - } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) { - $this->serverData = $serverData; } else { - throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); + $this->serverData = $serverData; } $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer']; diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index 0cc5d246f..9e9364ca0 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -224,7 +224,7 @@ public function testFormatShouldNotStripInlineLineBreaksWhenFlagIsSet() class TestFoo { - public $foo = 'fooValue'; + public string $foo = 'fooValue'; } class TestBar diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index e75dd5d25..e12bbc034 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -16,7 +16,7 @@ class ScalarFormatterTest extends TestCase { - private $formatter; + private ScalarFormatter $formatter; public function setUp(): void { diff --git a/tests/Monolog/Handler/BufferHandlerTest.php b/tests/Monolog/Handler/BufferHandlerTest.php index 8e7096129..d36a27137 100644 --- a/tests/Monolog/Handler/BufferHandlerTest.php +++ b/tests/Monolog/Handler/BufferHandlerTest.php @@ -16,7 +16,7 @@ class BufferHandlerTest extends TestCase { - private $shutdownCheckHandler; + private TestHandler $shutdownCheckHandler; /** * @covers Monolog\Handler\BufferHandler::__construct diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 722e0350c..2dcb52005 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -134,7 +134,7 @@ public function testConcurrentHandlers() class TestChromePHPHandler extends ChromePHPHandler { - protected $headers = []; + protected array $headers = []; public static function resetStatic(): void { diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index b206ef845..d8ace4475 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -11,17 +11,19 @@ namespace Monolog\Handler; +use Aws\DynamoDb\DynamoDbClient; use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; class DynamoDbHandlerTest extends TestCase { - private $client; + private DynamoDbClient&MockObject $client; - private $isV3; + private bool $isV3; public function setUp(): void { - if (!class_exists('Aws\DynamoDb\DynamoDbClient')) { + if (!class_exists(DynamoDbClient::class)) { $this->markTestSkipped('aws/aws-sdk-php not installed'); } @@ -29,13 +31,13 @@ public function setUp(): void $implementedMethods = ['__call']; $absentMethods = []; - if (method_exists('Aws\DynamoDb\DynamoDbClient', 'formatAttributes')) { + if (method_exists(DynamoDbClient::class, 'formatAttributes')) { $implementedMethods[] = 'formatAttributes'; } else { $absentMethods[] = 'formatAttributes'; } - $clientMockBuilder = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') + $clientMockBuilder = $this->getMockBuilder(DynamoDbClient::class) ->onlyMethods($implementedMethods) ->disableOriginalConstructor(); if ($absentMethods) { @@ -45,16 +47,6 @@ public function setUp(): void $this->client = $clientMockBuilder->getMock(); } - public function testConstruct() - { - $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo')); - } - - public function testInterface() - { - $this->assertInstanceOf('Monolog\Handler\HandlerInterface', new DynamoDbHandler($this->client, 'foo')); - } - public function testGetFormatter() { $handler = new DynamoDbHandler($this->client, 'foo'); diff --git a/tests/Monolog/Handler/FirePHPHandlerTest.php b/tests/Monolog/Handler/FirePHPHandlerTest.php index fd28b95a8..40fb67821 100644 --- a/tests/Monolog/Handler/FirePHPHandlerTest.php +++ b/tests/Monolog/Handler/FirePHPHandlerTest.php @@ -75,7 +75,7 @@ public function testConcurrentHandlers() class TestFirePHPHandler extends FirePHPHandler { - protected $headers = []; + protected array $headers = []; public static function resetStatic(): void { diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index 44c4fa794..51e80b312 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; /** * @author Alexey Karapetov @@ -20,12 +21,12 @@ class HandlerWrapperTest extends TestCase { private HandlerWrapper $wrapper; - private $handler; + private HandlerInterface&MockObject $handler; public function setUp(): void { parent::setUp(); - $this->handler = $this->createMock('Monolog\\Handler\\HandlerInterface'); + $this->handler = $this->createMock(HandlerInterface::class); $this->wrapper = new HandlerWrapper($this->handler); } diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 84dc911a5..79a2502de 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -28,12 +28,9 @@ */ class PHPConsoleHandlerTest extends TestCase { - /** @var Connector|MockObject */ - protected $connector; - /** @var DebugDispatcher|MockObject */ - protected $debugDispatcher; - /** @var ErrorDispatcher|MockObject */ - protected $errorDispatcher; + protected Connector&MockObject $connector; + protected DebugDispatcher&MockObject $debugDispatcher; + protected ErrorDispatcher&MockObject $errorDispatcher; protected function setUp(): void { diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 7db7098e9..11f3cd24b 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -13,6 +13,7 @@ use Monolog\Test\TestCase; use Monolog\Level; +use PHPUnit\Framework\MockObject\MockObject; /** * Almost all examples (expected header, titles, messages) taken from @@ -22,8 +23,9 @@ */ class PushoverHandlerTest extends TestCase { + /** @var resource */ private $res; - private $handler; + private PushoverHandler&MockObject $handler; public function testWriteHeader() { @@ -116,7 +118,7 @@ private function createHandler($token = 'myToken', $user = 'myUser', $title = 'M { $constructorArgs = [$token, $user, $title]; $this->res = fopen('php://memory', 'a'); - $this->handler = $this->getMockBuilder('Monolog\Handler\PushoverHandler') + $this->handler = $this->getMockBuilder(PushoverHandler::class) ->setConstructorArgs($constructorArgs) ->onlyMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) ->getMock(); diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index c65885c71..479262cfc 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -17,13 +17,6 @@ class RedisHandlerTest extends TestCase { - public function testConstructorShouldThrowExceptionForInvalidRedis() - { - $this->expectException(\InvalidArgumentException::class); - - new RedisHandler(new \stdClass(), 'key'); - } - public function testConstructorShouldWorkWithPredis() { $redis = $this->createMock('Predis\Client'); diff --git a/tests/Monolog/Handler/RedisPubSubHandlerTest.php b/tests/Monolog/Handler/RedisPubSubHandlerTest.php index f3e9f6e69..38ece0d27 100644 --- a/tests/Monolog/Handler/RedisPubSubHandlerTest.php +++ b/tests/Monolog/Handler/RedisPubSubHandlerTest.php @@ -19,13 +19,6 @@ class RedisPubSubHandlerTest extends TestCase { - public function testConstructorShouldThrowExceptionForInvalidRedis() - { - $this->expectException(\InvalidArgumentException::class); - - new RedisPubSubHandler(new \stdClass(), 'key'); - } - public function testConstructorShouldWorkWithPredis() { $redis = $this->createMock('Predis\Client'); diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 8e131cd6f..02286bbbc 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -19,7 +19,7 @@ */ class RotatingFileHandlerTest extends TestCase { - private $lastError; + private array|null $lastError = null; public function setUp(): void { diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 192cfbe00..02d469c94 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -20,10 +20,7 @@ */ class SocketHandlerTest extends TestCase { - /** - * @var \Monolog\Handler\SocketHandler|MockObject - */ - private $handler; + private SocketHandler&MockObject $handler; /** * @var resource @@ -34,58 +31,58 @@ public function testInvalidHostname() { $this->expectException(\UnexpectedValueException::class); - $this->createHandler('garbage://here'); - $this->writeRecord('data'); + $handler = $this->createHandler('garbage://here'); + $handler->handle($this->getRecord(Level::Warning, 'data')); } public function testBadConnectionTimeout() { $this->expectException(\InvalidArgumentException::class); - $this->createHandler('localhost:1234'); - $this->handler->setConnectionTimeout(-1); + $handler = $this->createHandler('localhost:1234'); + $handler->setConnectionTimeout(-1); } public function testSetConnectionTimeout() { - $this->createHandler('localhost:1234'); - $this->handler->setConnectionTimeout(10.1); - $this->assertEquals(10.1, $this->handler->getConnectionTimeout()); + $handler = $this->createHandler('localhost:1234'); + $handler->setConnectionTimeout(10.1); + $this->assertEquals(10.1, $handler->getConnectionTimeout()); } public function testBadTimeout() { $this->expectException(\InvalidArgumentException::class); - $this->createHandler('localhost:1234'); - $this->handler->setTimeout(-1); + $handler = $this->createHandler('localhost:1234'); + $handler->setTimeout(-1); } public function testSetTimeout() { - $this->createHandler('localhost:1234'); - $this->handler->setTimeout(10.25); - $this->assertEquals(10.25, $this->handler->getTimeout()); + $handler = $this->createHandler('localhost:1234'); + $handler->setTimeout(10.25); + $this->assertEquals(10.25, $handler->getTimeout()); } public function testSetWritingTimeout() { - $this->createHandler('localhost:1234'); - $this->handler->setWritingTimeout(10.25); - $this->assertEquals(10.25, $this->handler->getWritingTimeout()); + $handler = $this->createHandler('localhost:1234'); + $handler->setWritingTimeout(10.25); + $this->assertEquals(10.25, $handler->getWritingTimeout()); } public function testSetChunkSize() { - $this->createHandler('localhost:1234'); - $this->handler->setChunkSize(1025); - $this->assertEquals(1025, $this->handler->getChunkSize()); + $handler = $this->createHandler('localhost:1234'); + $handler->setChunkSize(1025); + $this->assertEquals(1025, $handler->getChunkSize()); } public function testSetConnectionString() { - $this->createHandler('tcp://localhost:9090'); - $this->assertEquals('tcp://localhost:9090', $this->handler->getConnectionString()); + $handler = $this->createHandler('tcp://localhost:9090'); + $this->assertEquals('tcp://localhost:9090', $handler->getConnectionString()); } public function testExceptionIsThrownOnFsockopenError() @@ -277,10 +274,12 @@ public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSecond $this->writeRecord('Hello world'); } - private function createHandler($connectionString) + private function createHandler(string $connectionString): SocketHandler { - $this->handler = new SocketHandler($connectionString); - $this->handler->setFormatter($this->getIdentityFormatter()); + $handler = new SocketHandler($connectionString); + $handler->setFormatter($this->getIdentityFormatter()); + + return $handler; } private function writeRecord($string) diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 446bedb58..51362887f 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -15,8 +15,6 @@ class ZendMonitorHandlerTest extends TestCase { - protected $zendMonitorHandler; - public function setUp(): void { if (!function_exists('zend_monitor_custom_event')) { diff --git a/tests/Monolog/Processor/WebProcessorTest.php b/tests/Monolog/Processor/WebProcessorTest.php index 59cc52e20..7c50127a9 100644 --- a/tests/Monolog/Processor/WebProcessorTest.php +++ b/tests/Monolog/Processor/WebProcessorTest.php @@ -118,7 +118,7 @@ public function testProcessorConfiguringOfExtraFields() public function testInvalidData() { - $this->expectException(\UnexpectedValueException::class); + $this->expectException(\TypeError::class); new WebProcessor(new \stdClass); } diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index 35cf76ea2..eb5dafbcc 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -24,7 +24,7 @@ class PsrLogCompatTest extends TestCase { - private $handler; + private TestHandler $handler; public function getLogger(): LoggerInterface { diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index 0c406bb8c..1ca47724c 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -22,9 +22,9 @@ */ class SignalHandlerTest extends TestCase { - private $asyncSignalHandling; - private $blockedSignals; - private $signalHandlers; + private bool $asyncSignalHandling; + private array $blockedSignals = []; + private array $signalHandlers = []; protected function setUp(): void { From a7de8dd0c206ce5d94672151c42fc19395d8b849 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Apr 2022 14:26:03 +0200 Subject: [PATCH 428/498] Update a few more callable to Closure --- src/Monolog/Handler/FilterHandler.php | 6 +++--- src/Monolog/Handler/FingersCrossedHandler.php | 8 ++++---- src/Monolog/Handler/SamplingHandler.php | 8 ++++---- src/Monolog/Logger.php | 8 ++++++-- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index c697e72f6..e23742c10 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -55,7 +55,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). + * @param Closure|HandlerInterface $handler Handler or factory Closure($record|null, $filterHandler). * @param int|string|Level|LevelName|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int|string|Level|LevelName|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 @@ -148,14 +148,14 @@ public function handleBatch(array $records): void /** * Return the nested handler * - * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * If the handler was provided as a factory, this will trigger the handler's instantiation. */ public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $handler = ($this->handler)($record, $this); if (!$handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); + throw new \RuntimeException("The factory Closure should return a HandlerInterface"); } $this->handler = $handler; } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 633233e20..6a3e2391b 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -43,7 +43,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa use ProcessableHandlerTrait; /** - * Handler or factory callable($record, $this) + * Handler or factory Closure($record, $this) * * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ @@ -67,7 +67,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa /** * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). + * @param Closure|HandlerInterface $handler Handler or factory Closure($record|null, $fingersCrossedHandler). * @param int|string|Level|LevelName|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 @@ -198,14 +198,14 @@ private function flushBuffer(): void /** * Return the nested handler * - * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * If the handler was provided as a factory, this will trigger the handler's instantiation. */ public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $handler = ($this->handler)($record, $this); if (!$handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); + throw new \RuntimeException("The factory Closure should return a HandlerInterface"); } $this->handler = $handler; } diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 917413ef3..1301a63d3 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -34,7 +34,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter use ProcessableHandlerTrait; /** - * Handler or factory callable($record, $this) + * Handler or factory Closure($record, $this) * * @phpstan-var (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface */ @@ -45,7 +45,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter /** * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * - * @param Closure|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). + * @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) */ public function __construct(Closure|HandlerInterface $handler, int $factor) @@ -76,14 +76,14 @@ public function handle(LogRecord $record): bool /** * Return the nested handler * - * If the handler was provided as a factory callable, this will trigger the handler's instantiation. + * If the handler was provided as a factory, this will trigger the handler's instantiation. */ public function getHandler(LogRecord $record = null): HandlerInterface { if (!$this->handler instanceof HandlerInterface) { $handler = ($this->handler)($record, $this); if (!$handler instanceof HandlerInterface) { - throw new \RuntimeException("The factory callable should return a HandlerInterface"); + throw new \RuntimeException("The factory Closure should return a HandlerInterface"); } $this->handler = $handler; } diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index fa38923a3..5c75e28fd 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -212,8 +212,10 @@ public function getHandlers(): array /** * Adds a processor on to the stack. + * + * @phpstan-param ProcessorInterface|(callable(LogRecord): LogRecord) $callback */ - public function pushProcessor(callable $callback): self + public function pushProcessor(ProcessorInterface|callable $callback): self { array_unshift($this->processors, $callback); @@ -223,6 +225,7 @@ public function pushProcessor(callable $callback): self /** * Removes the processor on top of the stack and returns it. * + * @phpstan-return ProcessorInterface|(callable(LogRecord): LogRecord) * @throws \LogicException If empty processor stack */ public function popProcessor(): callable @@ -236,6 +239,7 @@ public function popProcessor(): callable /** * @return callable[] + * @phpstan-return array */ public function getProcessors(): array { @@ -433,7 +437,7 @@ public function isHandling(int|string|LevelName|Level $level): bool /** * Set a custom exception handler that will be called if adding a new record fails * - * The callable will receive an exception object and the record that failed to be logged + * The Closure will receive an exception object and the record that failed to be logged */ public function setExceptionHandler(Closure|null $callback): self { From 1c80bce4ad9c5a75e95a544345e36f31b0554774 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Apr 2022 21:32:10 +0200 Subject: [PATCH 429/498] Fix error handler to not receive $context anymore as php8 dropped that --- src/Monolog/ErrorHandler.php | 16 ++++++---------- tests/Monolog/Handler/PHPConsoleHandlerTest.php | 3 ++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 74d86995e..99e319937 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -110,7 +110,7 @@ public function registerExceptionHandler(array $levelMap = [], bool $callPreviou */ 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; @@ -129,7 +129,7 @@ public function registerErrorHandler(array $levelMap = [], bool $callPrevious = */ 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; @@ -200,12 +200,7 @@ private function handleException(\Throwable $e): never exit(255); } - /** - * @private - * - * @param mixed[] $context - */ - public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []): bool + private function handleError(int $code, string $message, string $file = '', int $line = 0): bool { if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { return false; @@ -223,8 +218,9 @@ public function handleError(int $code, string $message, string $file = '', int $ if ($this->previousErrorHandler === true) { return false; - } elseif ($this->previousErrorHandler) { - return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context); + } + if ($this->previousErrorHandler) { + return (bool) ($this->previousErrorHandler)($code, $message, $file, $line); } return true; diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 79a2502de..f99aba869 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -176,7 +176,8 @@ public function testError($classesPartialsTraceIgnore = null) ); $errorHandler = ErrorHandler::register($this->initLogger($classesPartialsTraceIgnore ? ['classesPartialsTraceIgnore' => $classesPartialsTraceIgnore] : []), false); $errorHandler->registerErrorHandler([], false, E_USER_WARNING); - $errorHandler->handleError($code, $message, $file, $line); + $reflMethod = new \ReflectionMethod($errorHandler, 'handleError'); + $reflMethod->invoke($errorHandler, $code, $message, $file, $line); } public function testException() From 733d6f1cc662a6bfbc750b13fac1a9bc1b3fceff Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 23 Apr 2022 13:51:26 +0200 Subject: [PATCH 430/498] Remove dead code --- src/Monolog/LevelName.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Monolog/LevelName.php b/src/Monolog/LevelName.php index b7ff371ce..e1a3248f7 100644 --- a/src/Monolog/LevelName.php +++ b/src/Monolog/LevelName.php @@ -54,9 +54,4 @@ public function toLevel(): Level 'ALERT', 'EMERGENCY', ]; - - public function jsonSerialize(): mixed - { - return $this->value; - } } From ad732b37a74d15efad88b30509b04b4b50cfec84 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 23 Apr 2022 13:51:36 +0200 Subject: [PATCH 431/498] Update upgrade notes --- UPGRADE.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/UPGRADE.md b/UPGRADE.md index 84e15e6b7..d1d24e7b9 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,3 +1,92 @@ +### 3.0.0 + +Overall / notable changes: + +- The minimum supported PHP version is now `8.1.0`. +- `Monolog\Logger::API` can be used to distinguish between a Monolog `3`, `2` or `1` + install when writing integration code. +- 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) +- 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. + +### Logger + +- `Logger::DEBUG`, `Logger::ERROR`, etc. are now deprecated in favor of the `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` has been removed in favor of `Monolog\Level->toLevelName()->value`. +- `Logger::$levels` has been removed. +- `Logger::getLevels` has been removed in favor of `Monolog\Level::VALUES` or `Monolog\Level::cases()`. +- `setExceptionHandler` now requires a `Closure` instance and not just any `callable`. + +#### HtmlFormatter + +- If you redefined colors in the `$logLevels` property you must now override the + `getLevelColor` method instead. + +#### NormalizerFormatter + +- A new `normalizeRecord` method is available as an extension point which is called + only when converting the LogRecord to an array. You may need this if you overrode + `format` previously as `parent::format` now needs to receive a LogRecord still + so you cannot modify it before. + +#### AbstractSyslogHandler + +- If you redefined syslog levels in the `$logLevels` property you must now override the + `toSyslogPriority` method instead. + +#### DynamoDbHandler + +- Dropped support for AWS SDK v2 + +### FilterHandler + +- The factory callable to lazy load the nested handler must now be a `Closure` instance + and not just a `callable`. + +### FingersCrossedHandler + +- The factory callable to lazy load the nested handler must now be a `Closure` instance + and not just a `callable`. + +#### RollbarHandler + +- If you redefined rollbar levels in the `$logLevels` property you must now override the + `toRollbarLevel` method instead. + +### SamplingHandler + +- The factory callable to lazy load the nested handler must now be a `Closure` instance + and not just a `callable`. + +### SwiftMailerHandler + +- Removed deprecated SwiftMailer handler, migrate to SymfonyMailerHandler instead. + +#### ZendMonitorHandler + +- If you redefined zend monitor levels in the `$levelMap` property you must now override the + `toZendMonitorLevel` method instead. + +#### ResettableInterface + +- `reset()` now requires a void return type. + ### 2.0.0 - `Monolog\Logger::API` can be used to distinguish between a Monolog `1` and `2` From 6627c092d8a22e3e5b634744ad658652563906a2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Apr 2022 11:08:10 +0200 Subject: [PATCH 432/498] Add phpstan strict rules and deprecation rules, fix all related issues --- composer.json | 8 +- phpstan-baseline.neon | 52 ++++++++++++- phpstan.neon.dist | 2 + src/Monolog/ErrorHandler.php | 12 +-- src/Monolog/Formatter/ChromePHPFormatter.php | 4 +- .../Formatter/GelfMessageFormatter.php | 6 +- src/Monolog/Formatter/HtmlFormatter.php | 6 +- src/Monolog/Formatter/LineFormatter.php | 6 +- src/Monolog/Formatter/LogmaticFormatter.php | 12 +-- src/Monolog/Formatter/LogstashFormatter.php | 9 +-- src/Monolog/Formatter/NormalizerFormatter.php | 2 +- .../Handler/AbstractProcessingHandler.php | 2 +- src/Monolog/Handler/AmqpHandler.php | 4 +- src/Monolog/Handler/BrowserConsoleHandler.php | 8 +- src/Monolog/Handler/BufferHandler.php | 2 +- src/Monolog/Handler/ChromePHPHandler.php | 4 +- src/Monolog/Handler/CouchDBHandler.php | 23 +++++- src/Monolog/Handler/CubeHandler.php | 18 ++--- src/Monolog/Handler/Curl/Util.php | 2 +- src/Monolog/Handler/DeduplicationHandler.php | 6 +- src/Monolog/Handler/DynamoDbHandler.php | 2 +- src/Monolog/Handler/ElasticaHandler.php | 17 +++- src/Monolog/Handler/ElasticsearchHandler.php | 17 +++- src/Monolog/Handler/FallbackGroupHandler.php | 4 +- src/Monolog/Handler/FilterHandler.php | 2 +- src/Monolog/Handler/FingersCrossedHandler.php | 2 +- src/Monolog/Handler/FirePHPHandler.php | 2 +- src/Monolog/Handler/GroupHandler.php | 4 +- src/Monolog/Handler/LogglyHandler.php | 17 ++-- src/Monolog/Handler/LogmaticHandler.php | 14 ++-- src/Monolog/Handler/MailHandler.php | 2 +- src/Monolog/Handler/MandrillHandler.php | 4 +- src/Monolog/Handler/NativeMailerHandler.php | 9 +-- src/Monolog/Handler/NewRelicHandler.php | 4 +- src/Monolog/Handler/PHPConsoleHandler.php | 78 +++++++++++++++---- src/Monolog/Handler/ProcessHandler.php | 4 +- .../Handler/ProcessableHandlerTrait.php | 2 +- src/Monolog/Handler/PsrHandler.php | 4 +- src/Monolog/Handler/PushoverHandler.php | 4 +- src/Monolog/Handler/RedisHandler.php | 4 +- src/Monolog/Handler/RotatingFileHandler.php | 2 +- src/Monolog/Handler/SamplingHandler.php | 2 +- src/Monolog/Handler/Slack/SlackRecord.php | 22 +++--- src/Monolog/Handler/SlackHandler.php | 2 +- src/Monolog/Handler/SocketHandler.php | 16 ++-- src/Monolog/Handler/StreamHandler.php | 8 +- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 8 +- src/Monolog/Handler/SyslogUdpHandler.php | 6 +- src/Monolog/Handler/TelegramBotHandler.php | 6 +- src/Monolog/Handler/TestHandler.php | 2 +- .../Handler/WhatFailureGroupHandler.php | 4 +- src/Monolog/Logger.php | 20 ++--- src/Monolog/Processor/GitProcessor.php | 6 +- .../Processor/IntrospectionProcessor.php | 4 +- src/Monolog/Processor/MercurialProcessor.php | 4 +- .../Processor/PsrLogMessageProcessor.php | 4 +- src/Monolog/Processor/WebProcessor.php | 2 +- src/Monolog/Registry.php | 2 +- src/Monolog/SignalHandler.php | 3 +- src/Monolog/Test/TestCase.php | 4 +- src/Monolog/Utils.php | 8 +- .../Formatter/LogmaticFormatterTest.php | 2 +- 62 files changed, 335 insertions(+), 186 deletions(-) diff --git a/composer.json b/composer.json index 625e62e46..3b1b8a10b 100644 --- a/composer.json +++ b/composer.json @@ -20,15 +20,17 @@ "aws/aws-sdk-php": "^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7", - "mongodb/mongodb": "^1.8", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.6.1", + "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", - "ruflin/elastica": ">=0.90@dev", - "phpstan/phpstan": "^1.4" + "ruflin/elastica": ">=0.90@dev" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index cc808e7ac..1dfa52e88 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,6 +10,31 @@ parameters: count: 1 path: src/Monolog/Formatter/WildfireFormatter.php + - + message: "#^Return type \\(array\\\\|bool\\|float\\|int\\|object\\|string\\|null\\) of method Monolog\\\\Formatter\\\\WildfireFormatter\\:\\:normalize\\(\\) should be covariant with return type \\(array\\\\|bool\\|float\\|int\\|string\\|null\\) of method Monolog\\\\Formatter\\\\NormalizerFormatter\\:\\:normalize\\(\\)$#" + count: 1 + path: src/Monolog/Formatter/WildfireFormatter.php + + - + message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" + count: 1 + path: src/Monolog/Handler/BrowserConsoleHandler.php + + - + message: "#^Instanceof between Monolog\\\\Handler\\\\HandlerInterface and Monolog\\\\Handler\\\\HandlerInterface will always evaluate to true\\.$#" + count: 1 + path: src/Monolog/Handler/FilterHandler.php + + - + message: "#^Instanceof between Monolog\\\\Handler\\\\HandlerInterface and Monolog\\\\Handler\\\\HandlerInterface will always evaluate to true\\.$#" + count: 1 + path: src/Monolog/Handler/FingersCrossedHandler.php + + - + message: "#^Short ternary operator is not allowed\\. Use null coalesce operator if applicable or consider using long ternary\\.$#" + count: 1 + path: src/Monolog/Handler/FingersCrossedHandler.php + - message: "#^Call to method setBody\\(\\) on an unknown class Swift_Message\\.$#" count: 1 @@ -30,9 +55,14 @@ parameters: count: 1 path: src/Monolog/Handler/MandrillHandler.php + - + message: "#^Instanceof between Swift_Message and Swift_Message will always evaluate to true\\.$#" + count: 1 + path: src/Monolog/Handler/MandrillHandler.php + - message: "#^Parameter \\$message of method Monolog\\\\Handler\\\\MandrillHandler\\:\\:__construct\\(\\) has invalid type Swift_Message\\.$#" - count: 2 + count: 3 path: src/Monolog/Handler/MandrillHandler.php - @@ -40,6 +70,26 @@ parameters: count: 1 path: src/Monolog/Handler/MandrillHandler.php + - + message: "#^Method Monolog\\\\Handler\\\\PHPConsoleHandler\\:\\:initOptions\\(\\) should return array\\{enabled\\: bool, classesPartialsTraceIgnore\\: array\\, debugTagsKeysInContext\\: array\\, useOwnErrorsHandler\\: bool, useOwnExceptionsHandler\\: bool, sourcesBasePath\\: string\\|null, registerHelper\\: bool, serverEncoding\\: string\\|null, \\.\\.\\.\\} but returns non\\-empty\\-array\\<'classesPartialsTrac…'\\|'dataStorage'\\|'debugTagsKeysInCont…'\\|'detectDumpTraceAndS…'\\|'dumperDetectCallbac…'\\|'dumperDumpSizeLimit'\\|'dumperItemsCountLim…'\\|'dumperItemSizeLimit'\\|'dumperLevelLimit'\\|'enabled'\\|'enableEvalListener'\\|'enableSslOnlyMode'\\|'headersLimit'\\|'ipMasks'\\|'password'\\|'registerHelper'\\|'serverEncoding'\\|'sourcesBasePath'\\|'useOwnErrorsHandler'\\|'useOwnExceptionsHan…', array\\\\|bool\\|int\\|PhpConsole\\\\Storage\\|string\\|null\\>\\.$#" + count: 1 + path: src/Monolog/Handler/PHPConsoleHandler.php + + - + message: "#^Instanceof between Monolog\\\\Handler\\\\HandlerInterface and Monolog\\\\Handler\\\\HandlerInterface will always evaluate to true\\.$#" + count: 1 + path: src/Monolog/Handler/SamplingHandler.php + + - + message: "#^Variable property access on \\$this\\(Monolog\\\\LogRecord\\)\\.$#" + count: 5 + path: src/Monolog/LogRecord.php + + - + message: "#^Parameter \\#1 \\$level \\('alert'\\|'critical'\\|'debug'\\|'emergency'\\|'error'\\|'info'\\|'notice'\\|'warning'\\|Monolog\\\\Level\\|Monolog\\\\LevelName\\) of method Monolog\\\\Logger\\:\\:log\\(\\) should be contravariant with parameter \\$level \\(mixed\\) of method Psr\\\\Log\\\\LoggerInterface\\:\\:log\\(\\)$#" + count: 1 + path: src/Monolog/Logger.php + - message: "#^Comparison operation \"\\<\" between int\\<1, 32\\> and 1 is always false\\.$#" count: 1 diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 5fcb94783..a7442c906 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -24,3 +24,5 @@ parameters: includes: - phpstan-baseline.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-deprecation-rules/rules.neon diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 99e319937..45008e4b0 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -97,7 +97,7 @@ public function registerExceptionHandler(array $levelMap = [], bool $callPreviou $this->uncaughtExceptionLevelMap[$class] = $level; } } - if ($callPrevious && $prev) { + if ($callPrevious && null !== $prev) { $this->previousExceptionHandler = $prev(...); } @@ -189,11 +189,11 @@ private function handleException(\Throwable $e): never ['exception' => $e] ); - if ($this->previousExceptionHandler) { + if (null !== $this->previousExceptionHandler) { ($this->previousExceptionHandler)($e); } - if (!headers_sent() && !ini_get('display_errors')) { + if (!headers_sent() && !(bool) ini_get('display_errors')) { http_response_code(500); } @@ -202,7 +202,7 @@ private function handleException(\Throwable $e): never private function handleError(int $code, string $message, string $file = '', int $line = 0): bool { - if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { + if ($this->handleOnlyReportedErrors && 0 === (error_reporting() & $code)) { return false; } @@ -219,7 +219,7 @@ private function handleError(int $code, string $message, string $file = '', int if ($this->previousErrorHandler === true) { return false; } - if ($this->previousErrorHandler) { + if ($this->previousErrorHandler instanceof Closure) { return (bool) ($this->previousErrorHandler)($code, $message, $file, $line); } @@ -234,7 +234,7 @@ public function handleFatalError(): void $this->reservedMemory = ''; $lastError = error_get_last(); - if ($lastError && in_array($lastError['type'], self::FATAL_ERRORS, true)) { + if (is_array($lastError) && in_array($lastError['type'], self::FATAL_ERRORS, true)) { $this->logger->log( $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 540657ba1..3f1d45829 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -53,10 +53,10 @@ public function format(LogRecord $record) } $message = ['message' => $record->message]; - if ($record->context) { + if (\count($record->context) > 0) { $message['context'] = $record->context; } - if ($record->extra) { + if (\count($record->extra) > 0) { $message['extra'] = $record->extra; } if (count($message) === 1) { diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 488e2387f..1ae2fd9e3 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -96,12 +96,12 @@ public function format(LogRecord $record): Message $message = new Message(); $message ->setTimestamp($record->datetime) - ->setShortMessage((string) $record->message) + ->setShortMessage($record->message) ->setHost($this->systemName) ->setLevel($this->getGraylog2Priority($record->level)); // message length + system name length + 200 for padding / metadata - $len = 200 + strlen((string) $record->message) + strlen($this->systemName); + $len = 200 + strlen($record->message) + strlen($this->systemName); if ($len > $this->maxLength) { $message->setShortMessage(Utils::substr($record->message, 0, $this->maxLength)); @@ -143,7 +143,7 @@ public function format(LogRecord $record): Message /** @phpstan-ignore-next-line */ if (null === $message->getFile() && isset($context['exception']['file'])) { - if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) { + if (1 === preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) { $message->setFile($matches[1]); $message->setLine($matches[2]); } diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 8a8c2ccb4..77901aa3d 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -88,10 +88,10 @@ public function format(LogRecord $record): string $output = $this->addTitle($record->levelName->value, $record->level); $output .= '
'; - $output .= $this->addRow('Message', (string) $record->message); + $output .= $this->addRow('Message', $record->message); $output .= $this->addRow('Time', $this->formatDate($record->datetime)); $output .= $this->addRow('Channel', $record->channel); - if ($record->context) { + if (\count($record->context) > 0) { $embeddedTable = '
'; foreach ($record->context as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); @@ -99,7 +99,7 @@ public function format(LogRecord $record): string $embeddedTable .= '
'; $output .= $this->addRow('Context', $embeddedTable, false); } - if ($record->extra) { + if (\count($record->extra) > 0) { $embeddedTable = ''; foreach ($record->extra as $key => $value) { $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 23a635216..554515c50 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -92,12 +92,12 @@ public function format(LogRecord $record): string } if ($this->ignoreEmptyContextAndExtra) { - if (empty($vars['context'])) { + if (\count($vars['context']) === 0) { unset($vars['context']); $output = str_replace('%context%', '', $output); } - if (empty($vars['extra'])) { + if (\count($vars['extra']) === 0) { unset($vars['extra']); $output = str_replace('%extra%', '', $output); } @@ -144,7 +144,7 @@ protected function normalizeException(\Throwable $e, int $depth = 0): string { $str = $this->formatException($e); - if ($previous = $e->getPrevious()) { + if (($previous = $e->getPrevious()) instanceof \Throwable) { do { $str .= "\n[previous exception] " . $this->formatException($previous); } while ($previous = $previous->getPrevious()); diff --git a/src/Monolog/Formatter/LogmaticFormatter.php b/src/Monolog/Formatter/LogmaticFormatter.php index a20a85eef..10ad0d9c0 100644 --- a/src/Monolog/Formatter/LogmaticFormatter.php +++ b/src/Monolog/Formatter/LogmaticFormatter.php @@ -24,7 +24,7 @@ class LogmaticFormatter extends JsonFormatter protected string $hostname = ''; - protected string $appname = ''; + protected string $appName = ''; public function setHostname(string $hostname): self { @@ -33,9 +33,9 @@ public function setHostname(string $hostname): self return $this; } - public function setAppname(string $appname): self + public function setAppName(string $appName): self { - $this->appname = $appname; + $this->appName = $appName; return $this; } @@ -50,11 +50,11 @@ public function normalizeRecord(LogRecord $record): array { $record = parent::normalizeRecord($record); - if (!empty($this->hostname)) { + if ($this->hostname !== '') { $record["hostname"] = $this->hostname; } - if (!empty($this->appname)) { - $record["appname"] = $this->appname; + if ($this->appName !== '') { + $record["appname"] = $this->appName; } $record["@marker"] = static::MARKERS; diff --git a/src/Monolog/Formatter/LogstashFormatter.php b/src/Monolog/Formatter/LogstashFormatter.php index 5e6951440..d0e8749e3 100644 --- a/src/Monolog/Formatter/LogstashFormatter.php +++ b/src/Monolog/Formatter/LogstashFormatter.php @@ -67,9 +67,6 @@ public function format(LogRecord $record): string { $recordData = parent::format($record); - if (empty($recordData['datetime'])) { - $recordData['datetime'] = gmdate('c'); - } $message = [ '@timestamp' => $recordData['datetime'], '@version' => 1, @@ -88,13 +85,13 @@ public function format(LogRecord $record): string if (isset($recordData['level'])) { $message['monolog_level'] = $recordData['level']; } - if ($this->applicationName) { + if ('' !== $this->applicationName) { $message['type'] = $this->applicationName; } - if (!empty($recordData['extra'])) { + if (\count($recordData['extra']) > 0) { $message[$this->extraKey] = $recordData['extra']; } - if (!empty($recordData['context'])) { + if (\count($recordData['context']) > 0) { $message[$this->contextKey] = $recordData['context']; } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 0e195450f..986750382 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -254,7 +254,7 @@ protected function normalizeException(Throwable $e, int $depth = 0) } } - if ($previous = $e->getPrevious()) { + if (($previous = $e->getPrevious()) instanceof \Throwable) { $data['previous'] = $this->normalizeException($previous, $depth + 1); } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 463f8dfe8..de13a76be 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -35,7 +35,7 @@ public function handle(LogRecord $record): bool return false; } - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 2c83a207b..700c3f02a 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -34,9 +34,7 @@ public function __construct(AMQPExchange|AMQPChannel $exchange, ?string $exchang { if ($exchange instanceof AMQPChannel) { $this->exchangeName = (string) $exchangeName; - } elseif (!$exchange instanceof AMQPExchange) { - throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required'); - } elseif ($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; diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 0f3587ee5..28564b3fc 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -76,10 +76,10 @@ public static function send(): void return; } - if (count(static::$records)) { + if (count(static::$records) > 0) { if ($format === self::FORMAT_HTML) { static::writeOutput(''); - } elseif ($format === self::FORMAT_JS) { + } else { // js format static::writeOutput(self::generateScript()); } static::resetStatic(); @@ -172,7 +172,7 @@ private static function generateScript(): string $context = self::dump('Context', $record->context); $extra = self::dump('Extra', $record->extra); - if (empty($context) && empty($extra)) { + if (\count($context) === 0 && \count($extra) === 0) { $script[] = self::call_array('log', self::handleStyles($record->formatted)); } else { $script = array_merge( @@ -247,7 +247,7 @@ private static function dump(string $title, array $dict): array { $script = []; $dict = array_filter($dict); - if (empty($dict)) { + if (\count($dict) === 0) { return $script; } $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 2d0b4429d..3bdd09bba 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -79,7 +79,7 @@ public function handle(LogRecord $record): bool } } - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 96257c3c0..8882fabb7 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -90,7 +90,7 @@ public function handleBatch(array $records): void $messages[] = $message; } - if (!empty($messages)) { + if (\count($messages) > 0) { $messages = $this->getFormatter()->formatBatch($messages); self::$json['rows'] = array_merge(self::$json['rows'], $messages); $this->send(); @@ -180,7 +180,7 @@ protected function sendHeader(string $header, string $content): void */ protected function headersAccepted(): bool { - if (empty($_SERVER['HTTP_USER_AGENT'])) { + if (!isset($_SERVER['HTTP_USER_AGENT'])) { return false; } diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index f92b1b139..3b97375d9 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -20,14 +20,33 @@ * CouchDB handler * * @author Markus Bachmann + * @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[] */ + /** + * @var mixed[] + * @phpstan-var Options + */ private array $options; /** * @param mixed[] $options + * + * @phpstan-param InputOptions $options */ public function __construct(array $options = [], $level = Level::Debug, bool $bubble = true) { @@ -48,7 +67,7 @@ public function __construct(array $options = [], $level = Level::Debug, bool $bu protected function write(LogRecord $record): void { $basicAuth = null; - if ($this->options['username']) { + if (null !== $this->options['username'] && null !== $this->options['password']) { $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']); } diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 50d2507fe..c2469ca6c 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -46,7 +46,7 @@ public function __construct(string $url, $level = Level::Debug, bool $bubble = t throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); } - if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) { + if (!in_array($urlInfo['scheme'], $this->acceptedSchemes, true)) { throw new \UnexpectedValueException( 'Invalid protocol (' . $urlInfo['scheme'] . ').' . ' Valid options are ' . implode(', ', $this->acceptedSchemes) @@ -55,7 +55,7 @@ public function __construct(string $url, $level = Level::Debug, bool $bubble = t $this->scheme = $urlInfo['scheme']; $this->host = $urlInfo['host']; - $this->port = (int) $urlInfo['port']; + $this->port = $urlInfo['port']; parent::__construct($level, $bubble); } @@ -113,16 +113,16 @@ protected function write(LogRecord $record): void $date = $record->datetime; $data = ['time' => $date->format('Y-m-d\TH:i:s.uO')]; - unset($record->datetime); + $context = $record->context; - if (isset($record->context['type'])) { - $data['type'] = $record->context['type']; - unset($record->context['type']); + if (isset($context['type'])) { + $data['type'] = $context['type']; + unset($context['type']); } else { $data['type'] = $record->channel; } - $data['data'] = $record->context; + $data['data'] = $context; $data['data']['level'] = $record->level; if ($this->scheme === 'http') { @@ -134,7 +134,7 @@ protected function write(LogRecord $record): void private function writeUdp(string $data): void { - if (!$this->udpConnection) { + if (null === $this->udpConnection) { $this->connectUdp(); } @@ -147,7 +147,7 @@ private function writeUdp(string $data): void private function writeHttp(string $data): void { - if (!$this->httpConnection) { + if (null === $this->httpConnection) { $this->connectHttp(); } diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 64981c980..4decf0e62 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -44,7 +44,7 @@ public static function execute(CurlHandle $ch, int $retries = 5, bool $closeAfte if ($curlResponse === false) { $curlErrno = curl_errno($ch); - if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) { + if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || $retries === 0) { $curlError = curl_error($ch); if ($closeAfterDone) { diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index a8ae211ac..4ba371c52 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -75,7 +75,7 @@ public function flush(): void foreach ($this->buffer as $record) { if ($record->level->value >= $this->deduplicationLevel->value) { - $passthru = $passthru || !$this->isDuplicate($record); + $passthru = $passthru === true || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); } @@ -132,7 +132,7 @@ private function collectLogs(): void $handle = fopen($this->deduplicationStore, 'rw+'); - if (!$handle) { + if (false === $handle) { throw new \RuntimeException('Failed to open file for reading and writing: ' . $this->deduplicationStore); } @@ -143,7 +143,7 @@ private function collectLogs(): void while (!feof($handle)) { $log = fgets($handle); - if ($log && substr($log, 0, 10) >= $timestampValidity) { + if (is_string($log) && '' !== $log && substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 51994462e..c79d484e1 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -66,7 +66,7 @@ protected function write(LogRecord $record): void protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { - return !empty($value) || false === $value || 0 === $value; + return [] !== $value; }); } diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index fff3417aa..e9eb0d6aa 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -34,6 +34,16 @@ * $log->pushHandler($handler); * * @author Jelle Vink + * @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 { @@ -41,12 +51,15 @@ class ElasticaHandler extends AbstractProcessingHandler /** * @var mixed[] Handler config options + * @phpstan-var Options */ - protected array $options = []; + protected array $options; /** * @param Client $client Elastica Client object * @param mixed[] $options Handler configuration + * + * @phpstan-param InputOptions $options */ public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) { @@ -84,6 +97,8 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface /** * @return mixed[] + * + * @phpstan-return Options */ public function getOptions(): array { diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 427c8f3a6..2b14e33b1 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -41,6 +41,16 @@ * $log->pushHandler($handler); * * @author Avtandil Kikabidze + * @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 { @@ -48,12 +58,15 @@ class ElasticsearchHandler extends AbstractProcessingHandler /** * @var mixed[] Handler config options + * @phpstan-var Options */ - protected array $options = []; + protected array $options; /** * @param Client $client Elasticsearch Client object * @param mixed[] $options Handler configuration + * + * @phpstan-param InputOptions $options */ public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) { @@ -93,6 +106,8 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface * Getter options * * @return mixed[] + * + * @phpstan-return Options */ public function getOptions(): array { diff --git a/src/Monolog/Handler/FallbackGroupHandler.php b/src/Monolog/Handler/FallbackGroupHandler.php index 4c10b2017..1776eb517 100644 --- a/src/Monolog/Handler/FallbackGroupHandler.php +++ b/src/Monolog/Handler/FallbackGroupHandler.php @@ -28,7 +28,7 @@ class FallbackGroupHandler extends GroupHandler */ public function handle(LogRecord $record): bool { - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -48,7 +48,7 @@ public function handle(LogRecord $record): bool */ public function handleBatch(array $records): void { - if ($this->processors) { + if (\count($this->processors) > 0) { $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index e23742c10..60a8b418f 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -119,7 +119,7 @@ public function handle(LogRecord $record): bool return false; } - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 6a3e2391b..5e88dbc54 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -125,7 +125,7 @@ public function activate(): void */ public function handle(LogRecord $record): bool { - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index 1a6d3b952..6b9e5103a 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -165,7 +165,7 @@ protected function write(LogRecord $record): void */ protected function headersAccepted(): bool { - if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) { + if (isset($_SERVER['HTTP_USER_AGENT']) && 1 === preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) { return true; } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 16f3b6b71..7ab8bd973 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -63,7 +63,7 @@ public function isHandling(LogRecord $record): bool */ public function handle(LogRecord $record): bool { - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } @@ -79,7 +79,7 @@ public function handle(LogRecord $record): bool */ public function handleBatch(array $records): void { - if ($this->processors) { + if (\count($this->processors) > 0) { $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index e14223706..f0be46ace 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -90,10 +90,13 @@ private function loadCurlHandle(string $endpoint): CurlHandle /** * @param string[]|string $tag */ - public function setTag($tag): self + public function setTag(string|array $tag): self { - $tag = !empty($tag) ? $tag : []; - $this->tag = is_array($tag) ? $tag : [$tag]; + if ('' === $tag || [] === $tag) { + $this->tag = []; + } else { + $this->tag = is_array($tag) ? $tag : [$tag]; + } return $this; } @@ -101,9 +104,9 @@ public function setTag($tag): self /** * @param string[]|string $tag */ - public function addTag($tag): self + public function addTag(string|array $tag): self { - if (!empty($tag)) { + if ('' !== $tag) { $tag = is_array($tag) ? $tag : [$tag]; $this->tag = array_unique(array_merge($this->tag, $tag)); } @@ -124,7 +127,7 @@ public function handleBatch(array $records): void return ($record->level >= $level); }); - if ($records) { + if (\count($records) > 0) { $this->send($this->getFormatter()->formatBatch($records), static::ENDPOINT_BATCH); } } @@ -135,7 +138,7 @@ protected function send(string $data, string $endpoint): void $headers = ['Content-Type: application/json']; - if (!empty($this->tag)) { + if (\count($this->tag) > 0) { $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag); } diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php index 98935f2c5..876b1a953 100644 --- a/src/Monolog/Handler/LogmaticHandler.php +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -25,12 +25,12 @@ class LogmaticHandler extends SocketHandler private string $hostname; - private string $appname; + private string $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 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 @@ -38,7 +38,7 @@ class LogmaticHandler extends SocketHandler public function __construct( string $token, string $hostname = '', - string $appname = '', + string $appName = '', bool $useSSL = true, $level = Level::Debug, bool $bubble = true, @@ -68,7 +68,7 @@ public function __construct( $this->logToken = $token; $this->hostname = $hostname; - $this->appname = $appname; + $this->appName = $appName; } /** @@ -86,11 +86,11 @@ protected function getDefaultFormatter(): FormatterInterface { $formatter = new LogmaticFormatter(); - if (!empty($this->hostname)) { + if ($this->hostname !== '') { $formatter->setHostname($this->hostname); } - if (!empty($this->appname)) { - $formatter->setAppname($this->appname); + if ($this->appName !== '') { + $formatter->setAppName($this->appName); } return $formatter; diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index c6488f1a3..b6c822772 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -38,7 +38,7 @@ public function handleBatch(array $records): void $messages[] = $message; } - if (!empty($messages)) { + if (\count($messages) > 0) { $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); } } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index 353195197..bc8553e13 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -31,11 +31,11 @@ class MandrillHandler extends MailHandler * @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, $message, $level = Level::Error, bool $bubble = true) + public function __construct(string $apiKey, callable|Swift_Message $message, $level = Level::Error, bool $bubble = true) { parent::__construct($level, $bubble); - if (!$message instanceof Swift_Message && is_callable($message)) { + if (!$message instanceof Swift_Message) { $message = $message(); } if (!$message instanceof Swift_Message) { diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 57d704e00..436d93c91 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -109,7 +109,7 @@ public function addParameter($parameters): self */ 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,11 +121,8 @@ protected function send(string $content, array $records): void $headers .= 'MIME-Version: 1.0' . "\r\n"; } - $subject = $this->subject; - if ($records) { - $subjectFormatter = new LineFormatter($this->subject); - $subject = $subjectFormatter->format($this->getHighestRecord($records)); - } + $subjectFormatter = new LineFormatter($this->subject); + $subject = $subjectFormatter->format($this->getHighestRecord($records)); $parameters = implode(' ', $this->parameters); foreach ($this->to as $to) { diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 78108285e..7c660e083 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -64,11 +64,11 @@ protected function write(LogRecord $record): void throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); } - if ($appName = $this->getAppName($record->context)) { + if (null !== ($appName = $this->getAppName($record->context))) { $this->setNewRelicAppName($appName); } - if ($transactionName = $this->getTransactionName($record->context)) { + if (null !== ($transactionName = $this->getTransactionName($record->context))) { $this->setNewRelicTransactionName($transactionName); unset($record->formatted['context']['transaction_name']); } diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index ccd44785a..80e40d20d 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -19,6 +19,7 @@ use PhpConsole\Handler as VendorPhpConsoleHandler; use PhpConsole\Helper; use Monolog\LogRecord; +use PhpConsole\Storage; /** * Monolog handler for Google Chrome extension "PHP Console" @@ -38,10 +39,56 @@ * 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, + * 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, + * 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 + * } */ class PHPConsoleHandler extends AbstractProcessingHandler { - /** @var array */ + /** + * @phpstan-var Options + */ private array $options = [ 'enabled' => true, // bool Is PHP Console server enabled 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... @@ -71,6 +118,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler * @param array $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, $level = Level::Debug, bool $bubble = true) { @@ -83,14 +131,16 @@ public function __construct(array $options = [], ?Connector $connector = null, $ } /** - * @param array $options - * + * @param array $options * @return array + * + * @phpstan-param InputOptions $options + * @phpstan-return Options */ private function initOptions(array $options): array { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); - if ($wrongOptions) { + if (\count($wrongOptions) > 0) { throw new \RuntimeException('Unknown options: ' . implode(', ', $wrongOptions)); } @@ -99,8 +149,8 @@ private function initOptions(array $options): array private function initConnector(?Connector $connector = null): Connector { - if (!$connector) { - if ($this->options['dataStorage']) { + if (null === $connector) { + if ($this->options['dataStorage'] instanceof Storage) { Connector::setPostponeStorage($this->options['dataStorage']); } $connector = Connector::getInstance(); @@ -117,22 +167,22 @@ private function initConnector(?Connector $connector = null): Connector $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']); $handler->start(); } - if ($this->options['sourcesBasePath']) { + if (null !== $this->options['sourcesBasePath']) { $connector->setSourcesBasePath($this->options['sourcesBasePath']); } - if ($this->options['serverEncoding']) { + if (null !== $this->options['serverEncoding']) { $connector->setServerEncoding($this->options['serverEncoding']); } - if ($this->options['password']) { + if (null !== $this->options['password']) { $connector->setPassword($this->options['password']); } if ($this->options['enableSslOnlyMode']) { $connector->enableSslOnlyMode(); } - if ($this->options['ipMasks']) { + if (\count($this->options['ipMasks']) > 0) { $connector->setAllowedIpMasks($this->options['ipMasks']); } - if ($this->options['headersLimit']) { + if (null !== $this->options['headersLimit'] && $this->options['headersLimit'] > 0) { $connector->setHeadersLimit($this->options['headersLimit']); } if ($this->options['detectDumpTraceAndSource']) { @@ -192,7 +242,7 @@ private function handleDebugRecord(LogRecord $record): void { [$tags, $filteredContext] = $this->getRecordTags($record); $message = $record->message; - if ($filteredContext) { + if (\count($filteredContext) > 0) { $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($filteredContext)), null, true); } $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); @@ -226,7 +276,7 @@ private function getRecordTags(LogRecord $record): array if ($record->context !== []) { $filteredContext = $record->context; foreach ($this->options['debugTagsKeysInContext'] as $key) { - if (!empty($filteredContext[$key])) { + if (isset($filteredContext[$key])) { $tags = $filteredContext[$key]; if ($key === 0) { array_shift($filteredContext); @@ -238,7 +288,7 @@ private function getRecordTags(LogRecord $record): array } } - return [$tags ?: strtolower($record->levelName->value), $filteredContext]; + return [$tags ?? strtolower($record->levelName->value), $filteredContext]; } /** diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index e5f619456..57f3cbf2d 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -85,7 +85,7 @@ protected function write(LogRecord $record): void $this->writeProcessInput($record->formatted); $errors = $this->readProcessErrors(); - if (empty($errors) === false) { + if ($errors !== '') { throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors)); } } @@ -129,7 +129,7 @@ private function handleStartupErrors(): void $errors = $this->readProcessErrors(); - if (is_resource($this->process) === false || empty($errors) === false) { + if (is_resource($this->process) === false || $errors !== '') { throw new \UnexpectedValueException( sprintf('The process "%s" could not be opened: ' . $errors, $this->command) ); diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 7c4a88879..74eeddddc 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -43,7 +43,7 @@ public function pushProcessor(callable $callback): HandlerInterface */ public function popProcessor(): callable { - if (!$this->processors) { + if (\count($this->processors) === 0) { throw new \LogicException('You tried to pop from an empty processor stack.'); } diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index e8fc65e22..2c17a56d8 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -53,7 +53,7 @@ public function handle(LogRecord $record): bool return false; } - if ($this->formatter) { + if ($this->formatter !== null) { $formatted = $this->formatter->format($record); $this->logger->log(strtolower($record->levelName->value), (string) $formatted, $record->context); } else { @@ -78,7 +78,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface */ public function getFormatter(): FormatterInterface { - if (!$this->formatter) { + if ($this->formatter === null) { throw new \LogicException('No formatter has been set and this handler does not have a default formatter'); } diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index d745697cd..81eb84801 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -129,7 +129,7 @@ public function __construct( $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; @@ -177,7 +177,7 @@ private function buildContent(LogRecord $record): string $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)) { + if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds, true)) { unset($dataArray['sound']); } diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 9edfa1817..44362566f 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -56,7 +56,7 @@ public function __construct(Predis|Redis $redis, string $key, int|string|Level|L */ protected function write(LogRecord $record): void { - if ($this->capSize) { + if ($this->capSize > 0) { $this->writeCapped($record); } else { $this->redisClient->rpush($this->redisKey, $record->formatted); @@ -72,7 +72,7 @@ protected function writeCapped(LogRecord $record): void 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 { diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 44f78c48f..c9febeb56 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -80,7 +80,7 @@ public function reset(): void public function setFilenameFormat(string $filenameFormat, string $dateFormat): self { - if (!preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { + if (0 === 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") '. diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 1301a63d3..511ec5854 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -63,7 +63,7 @@ public function isHandling(LogRecord $record): bool public function handle(LogRecord $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index f530e3e5e..7e9cccc9d 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -113,15 +113,15 @@ public function getSlackData(LogRecord $record): array { $dataArray = []; - if ($this->username) { + if ($this->username !== null) { $dataArray['username'] = $this->username; } - if ($this->channel) { + if ($this->channel !== null) { $dataArray['channel'] = $this->channel; } - if ($this->formatter && !$this->useAttachment) { + if ($this->formatter !== null && !$this->useAttachment) { $message = $this->formatter->format($record); } else { $message = $record->message; @@ -150,13 +150,13 @@ public function getSlackData(LogRecord $record): array if ($this->includeContextAndExtra) { foreach (['extra', 'context'] as $key) { - if (empty($recordData[$key])) { + if (!isset($recordData[$key]) || \count($recordData[$key]) === 0) { continue; } if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( - (string) $key, + $key, $recordData[$key] ); } else { @@ -174,9 +174,9 @@ public function getSlackData(LogRecord $record): array $dataArray['text'] = $message; } - if ($this->userIcon) { - if (filter_var($this->userIcon, FILTER_VALIDATE_URL)) { - $dataArray['icon_url'] = $this->userIcon; + if ($this->userIcon !== null) { + if (false !== ($iconUrl = filter_var($this->userIcon, FILTER_VALIDATE_URL))) { + $dataArray['icon_url'] = $iconUrl; } else { $dataArray['icon_emoji'] = ":{$this->userIcon}:"; } @@ -209,10 +209,10 @@ public function stringify(array $fields): string /** @var array $normalized */ $normalized = $this->normalizerFormatter->normalizeValue($fields); - $hasSecondDimension = count(array_filter($normalized, 'is_array')); - $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); + $hasSecondDimension = \count(array_filter($normalized, 'is_array')) > 0; + $hasOnlyNonNumericKeys = \count(array_filter(array_keys($normalized), 'is_numeric')) === 0; - return $hasSecondDimension || $hasNonNumericKeys + return $hasSecondDimension || $hasOnlyNonNumericKeys ? Utils::jsonEncode($normalized, JSON_PRETTY_PRINT|Utils::DEFAULT_JSON_FLAGS) : Utils::jsonEncode($normalized, Utils::DEFAULT_JSON_FLAGS); } diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 6360e0227..321d8660f 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -129,7 +129,7 @@ protected function prepareContentData(LogRecord $record): array $dataArray = $this->slackRecord->getSlackData($record); $dataArray['token'] = $this->token; - if (!empty($dataArray['attachments'])) { + if (isset($dataArray['attachments']) && is_array($dataArray['attachments']) && \count($dataArray['attachments']) > 0) { $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']); } diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 811159713..c5f708884 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -268,9 +268,9 @@ protected function streamSetTimeout(): bool * * @see http://php.net/manual/en/function.stream-set-chunk-size.php * - * @return int|bool + * @return int|false */ - protected function streamSetChunkSize() + protected function streamSetChunkSize(): int|bool { if (!is_resource($this->resource)) { throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource'); @@ -286,9 +286,9 @@ protected function streamSetChunkSize() /** * Wrapper to allow mocking * - * @return int|bool + * @return int|false */ - protected function fwrite(string $data) + protected function fwrite(string $data): int|bool { if (!is_resource($this->resource)) { throw new \LogicException('fwrite called but $this->resource is not a resource'); @@ -302,7 +302,7 @@ protected function fwrite(string $data) * * @return mixed[]|bool */ - protected function streamGetMetadata() + protected function streamGetMetadata(): array|bool { if (!is_resource($this->resource)) { throw new \LogicException('streamGetMetadata called but $this->resource is not a resource'); @@ -368,7 +368,7 @@ private function setSocketTimeout(): void private function setStreamChunkSize(): void { - if ($this->chunkSize && !$this->streamSetChunkSize()) { + if (null !== $this->chunkSize && false === $this->streamSetChunkSize()) { throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); } } @@ -389,7 +389,7 @@ private function writeToSocket(string $data): void } $sent += $chunk; $socketInfo = $this->streamGetMetadata(); - if (is_array($socketInfo) && $socketInfo['timed_out']) { + if (is_array($socketInfo) && (bool) $socketInfo['timed_out']) { throw new \RuntimeException("Write timed-out"); } @@ -418,7 +418,7 @@ private function writingIsTimedOut(int $sent): bool usleep(100); } - if ((microtime(true) - $this->lastWritingAt) >= $this->writingTimeout) { + if ((microtime(true) - (float) $this->lastWritingAt) >= $this->writingTimeout) { $this->closeSocket(); return true; diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 504b547ff..0426868be 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -80,7 +80,7 @@ public function __construct($stream, $level = Level::Debug, bool $bubble = true, */ public function close(): void { - if ($this->url && is_resource($this->stream)) { + if (null !== $this->url && is_resource($this->stream)) { fclose($this->stream); } $this->stream = null; @@ -138,10 +138,6 @@ protected function write(LogRecord $record): void } $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); @@ -187,7 +183,7 @@ private function getDirFromStream(string $stream): ?string private function createDir(string $url): void { // Do not try to create dir if it has already been tried. - if ($this->dirCreated) { + if (true === $this->dirCreated) { return; } diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index e5fc753d6..19db89508 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -20,7 +20,7 @@ class UdpSocket protected string $ip; protected int $port; - protected ?Socket $socket; + protected ?Socket $socket = null; public function __construct(string $ip, int $port = 514) { @@ -33,7 +33,11 @@ public function __construct(string $ip, int $port = 514) $domain = AF_UNIX; $protocol = IPPROTO_IP; } - $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; + + $socket = socket_create($domain, SOCK_DGRAM, $protocol); + if ($socket instanceof Socket) { + $this->socket = $socket; + } } public function write(string $line, string $header = ""): void diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 0370cf6eb..a40317d2f 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -109,11 +109,13 @@ protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $date { $priority = $severity + $this->facility; - if (!$pid = getmypid()) { + $pid = getmypid(); + if (false === $pid) { $pid = '-'; } - if (!$hostname = gethostname()) { + $hostname = gethostname(); + if (false === $hostname) { $hostname = '-'; } diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 7729d84c7..2e1be9f6b 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -123,7 +123,7 @@ public function __construct( public function setParseMode(string $parseMode = null): self { - if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES)) { + if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES, true)) { throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . implode(', ', self::AVAILABLE_PARSE_MODES) . '.'); } @@ -181,14 +181,14 @@ public function handleBatch(array $records): void continue; } - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } $messages[] = $record; } - if (!empty($messages)) { + if (\count($messages) > 0) { $this->send((string) $this->getFormatter()->formatBatch($messages)); } } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index e7d47e0bd..b645d1ed2 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -158,7 +158,7 @@ public function hasRecordThatPasses(callable $predicate, Level $level): bool } foreach ($this->recordsByLevel[$level->value] as $i => $rec) { - if ($predicate($rec, $i)) { + if ((bool) $predicate($rec, $i)) { return true; } } diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index d891c25d0..2dbc5fe8d 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -27,7 +27,7 @@ class WhatFailureGroupHandler extends GroupHandler */ public function handle(LogRecord $record): bool { - if ($this->processors) { + if (\count($this->processors) > 0) { $record = $this->processRecord($record); } @@ -47,7 +47,7 @@ public function handle(LogRecord $record): bool */ public function handleBatch(array $records): void { - if ($this->processors) { + if (\count($this->processors) > 0) { $processed = []; foreach ($records as $record) { $processed[] = $this->processRecord($record); diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 5c75e28fd..60df34d07 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -142,7 +142,7 @@ public function __construct(string $name, array $handlers = [], array $processor $this->name = $name; $this->setHandlers($handlers); $this->processors = $processors; - $this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get() ?: 'UTC'); + $this->timezone = $timezone ?? new DateTimeZone(date_default_timezone_get()); } public function getName(): string @@ -483,7 +483,7 @@ public function log($level, string|\Stringable $message, array $context = []): v */ public function debug(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::DEBUG, (string) $message, $context); + $this->addRecord(Level::Debug, (string) $message, $context); } /** @@ -496,7 +496,7 @@ public function debug(string|\Stringable $message, array $context = []): void */ public function info(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::INFO, (string) $message, $context); + $this->addRecord(Level::Info, (string) $message, $context); } /** @@ -509,7 +509,7 @@ public function info(string|\Stringable $message, array $context = []): void */ public function notice(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::NOTICE, (string) $message, $context); + $this->addRecord(Level::Notice, (string) $message, $context); } /** @@ -522,7 +522,7 @@ public function notice(string|\Stringable $message, array $context = []): void */ public function warning(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::WARNING, (string) $message, $context); + $this->addRecord(Level::Warning, (string) $message, $context); } /** @@ -535,7 +535,7 @@ public function warning(string|\Stringable $message, array $context = []): void */ public function error(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::ERROR, (string) $message, $context); + $this->addRecord(Level::Error, (string) $message, $context); } /** @@ -548,7 +548,7 @@ public function error(string|\Stringable $message, array $context = []): void */ public function critical(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::CRITICAL, (string) $message, $context); + $this->addRecord(Level::Critical, (string) $message, $context); } /** @@ -561,7 +561,7 @@ public function critical(string|\Stringable $message, array $context = []): void */ public function alert(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::ALERT, (string) $message, $context); + $this->addRecord(Level::Alert, (string) $message, $context); } /** @@ -574,7 +574,7 @@ public function alert(string|\Stringable $message, array $context = []): void */ public function emergency(string|\Stringable $message, array $context = []): void { - $this->addRecord(static::EMERGENCY, (string) $message, $context); + $this->addRecord(Level::Emergency, (string) $message, $context); } /** @@ -601,7 +601,7 @@ public function getTimezone(): DateTimeZone */ protected function handleException(Throwable $e, LogRecord $record): void { - if (!$this->exceptionHandler) { + if (null === $this->exceptionHandler) { throw $e; } diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 4b0351c41..87c234496 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -59,12 +59,12 @@ public function __invoke(LogRecord $record): LogRecord */ private static function getGitInfo(): array { - if (self::$cache) { + if (self::$cache !== null) { return self::$cache; } - $branches = `git branch -v --no-abbrev`; - if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { + $branches = shell_exec('git branch -v --no-abbrev'); + if (is_string($branches) && 1 === preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { return self::$cache = [ 'branch' => $matches[1], 'commit' => $matches[2], diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 1a8f67f64..6f4816382 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -83,7 +83,7 @@ public function __invoke(LogRecord $record): LogRecord continue 2; } } - } elseif (in_array($trace[$i]['function'], self::SKIP_FUNCTIONS)) { + } elseif (in_array($trace[$i]['function'], self::SKIP_FUNCTIONS, true)) { $i++; continue; @@ -118,6 +118,6 @@ private function isTraceClassOrSkippedFunction(array $trace, int $index): bool return false; } - return isset($trace[$index]['class']) || in_array($trace[$index]['function'], self::SKIP_FUNCTIONS); + return isset($trace[$index]['class']) || in_array($trace[$index]['function'], self::SKIP_FUNCTIONS, true); } } diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 4af2ffc4e..41ba16fa4 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -58,11 +58,11 @@ public function __invoke(LogRecord $record): LogRecord */ private static function getMercurialInfo(): array { - if (self::$cache) { + if (self::$cache !== null) { return self::$cache; } - $result = explode(' ', trim(`hg id -nb`)); + $result = explode(' ', trim((string) shell_exec('hg id -nb'))); if (count($result) >= 3) { return self::$cache = [ diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index b51f42a73..329efa223 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -60,12 +60,12 @@ public function __invoke(LogRecord $record): LogRecord if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { $replacements[$placeholder] = $val; } elseif ($val instanceof \DateTimeInterface) { - if (!$this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) { + if (null === $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 (is_object($val)) { $replacements[$placeholder] = '[object '.Utils::getClass($val).']'; diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 947de3627..2088b180b 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -65,7 +65,7 @@ public function __construct(array|ArrayAccess|null $serverData = null, array|nul } if (isset($extraFields[0])) { foreach (array_keys($this->extraFields) as $fieldName) { - if (!in_array($fieldName, $extraFields)) { + if (!in_array($fieldName, $extraFields, true)) { unset($this->extraFields[$fieldName]); } } diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index 08bf02dea..2ef2edceb 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -54,7 +54,7 @@ class Registry */ public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false): void { - $name = $name ?: $logger->getName(); + $name = $name ?? $logger->getName(); if (isset(self::$loggers[$name]) && !$overwrite) { throw new InvalidArgumentException('Logger with the given name already exists'); diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 546accb29..6c41dc0ab 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -77,8 +77,7 @@ public function handleSignal(int $signo, $siginfo = null): void if (!$signals && extension_loaded('pcntl')) { $pcntl = new ReflectionExtension('pcntl'); - // HHVM 3.24.2 returns an empty array. - foreach ($pcntl->getConstants() ?: get_defined_constants(true)['Core'] as $name => $value) { + foreach ($pcntl->getConstants() as $name => $value) { if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { $signals[$value] = $name; } diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index aa7144882..be4025020 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -61,9 +61,9 @@ protected function getMultipleRecords(): array protected function getIdentityFormatter(): FormatterInterface { $formatter = $this->createMock(FormatterInterface::class); - $formatter->expects($this->any()) + $formatter->expects(self::any()) ->method('format') - ->will($this->returnCallback(function ($record) { + ->will(self::returnCallback(function ($record) { return $record->message; })); diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 4a1d9e98c..a9cf0f761 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -196,7 +196,7 @@ private static function throwEncodeError(int $code, $data): never */ private static function detectAndCleanUtf8(&$data): void { - if (is_string($data) && !preg_match('//u', $data)) { + if (is_string($data) && preg_match('//u', $data) !== 1) { $data = preg_replace_callback( '/[\x80-\xFF]+/', function ($m) { @@ -234,7 +234,7 @@ public static function expandIniShorthandBytes($val) return (int) $val; } - if (!preg_match('/^\s*(?\d+)(?:\.\d+)?\s*(?[gmk]?)\s*$/i', $val, $match)) { + if (preg_match('/^\s*(?\d+)(?:\.\d+)?\s*(?[gmk]?)\s*$/i', $val, $match) !== 1) { return false; } @@ -259,10 +259,10 @@ public static function getRecordMessageForException(LogRecord $record): string $extra = ''; try { - if ($record->context) { + if (\count($record->context) > 0) { $context = "\nContext: " . json_encode($record->context, JSON_THROW_ON_ERROR); } - if ($record->extra) { + if (\count($record->extra) > 0) { $extra = "\nExtra: " . json_encode($record->extra, JSON_THROW_ON_ERROR); } } catch (\Throwable $e) { diff --git a/tests/Monolog/Formatter/LogmaticFormatterTest.php b/tests/Monolog/Formatter/LogmaticFormatterTest.php index d27670fab..00d6536fd 100644 --- a/tests/Monolog/Formatter/LogmaticFormatterTest.php +++ b/tests/Monolog/Formatter/LogmaticFormatterTest.php @@ -25,7 +25,7 @@ public function testFormat() { $formatter = new LogmaticFormatter(); $formatter->setHostname('testHostname'); - $formatter->setAppname('testAppname'); + $formatter->setAppName('testAppname'); $record = $this->getRecord(); $formatted_decoded = json_decode($formatter->format($record), true); $this->assertArrayHasKey('hostname', $formatted_decoded); From bd5968a567d90566f17e9c011ec5512a7d7a0e48 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Apr 2022 11:17:17 +0200 Subject: [PATCH 433/498] Add missing types to constructor args --- doc/04-extending.md | 2 +- src/Monolog/Handler/AbstractSyslogHandler.php | 3 ++- src/Monolog/Handler/ChromePHPHandler.php | 3 ++- src/Monolog/Handler/CouchDBHandler.php | 3 ++- src/Monolog/Handler/CubeHandler.php | 3 ++- src/Monolog/Handler/DoctrineCouchDBHandler.php | 3 ++- src/Monolog/Handler/DynamoDbHandler.php | 3 ++- src/Monolog/Handler/ElasticaHandler.php | 3 ++- src/Monolog/Handler/ElasticsearchHandler.php | 3 ++- src/Monolog/Handler/ErrorLogHandler.php | 3 ++- src/Monolog/Handler/GelfHandler.php | 3 ++- src/Monolog/Handler/IFTTTHandler.php | 3 ++- src/Monolog/Handler/LogglyHandler.php | 3 ++- src/Monolog/Handler/MandrillHandler.php | 3 ++- src/Monolog/Handler/MongoDBHandler.php | 7 ++----- src/Monolog/Handler/NativeMailerHandler.php | 3 ++- src/Monolog/Handler/PHPConsoleHandler.php | 3 ++- src/Monolog/Handler/ProcessHandler.php | 3 ++- src/Monolog/Handler/PsrHandler.php | 3 ++- src/Monolog/Handler/RotatingFileHandler.php | 3 ++- src/Monolog/Handler/SendGridHandler.php | 3 ++- src/Monolog/Handler/SqsHandler.php | 3 ++- src/Monolog/Handler/StreamHandler.php | 3 ++- src/Monolog/Handler/SyslogHandler.php | 3 ++- src/Monolog/Handler/SyslogUdpHandler.php | 3 ++- src/Monolog/Handler/ZendMonitorHandler.php | 3 ++- tests/Monolog/Handler/MongoDBHandlerTest.php | 2 +- 27 files changed, 52 insertions(+), 31 deletions(-) diff --git a/doc/04-extending.md b/doc/04-extending.md index f5d292ada..8d9d09a4b 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -30,7 +30,7 @@ class PDOHandler extends AbstractProcessingHandler private PDO $pdo; private PDOStatement $statement; - public function __construct(PDO $pdo, $level = Level::Debug, bool $bubble = true) + public function __construct(PDO $pdo, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $this->pdo = $pdo; parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 8535ab84f..0315d981a 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -14,6 +14,7 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; +use Monolog\LevelName; /** * Common syslog functionality @@ -60,7 +61,7 @@ protected function toSyslogPriority(Level $level): int /** * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant */ - public function __construct($facility = \LOG_USER, $level = Level::Debug, bool $bubble = true) + public function __construct(string|int $facility = \LOG_USER, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 8882fabb7..f6914bd02 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; use Monolog\DateTimeImmutable; @@ -62,7 +63,7 @@ class ChromePHPHandler extends AbstractProcessingHandler protected static bool $sendHeaders = true; - public function __construct($level = Level::Debug, bool $bubble = true) + public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); if (!function_exists('json_encode')) { diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index 3b97375d9..8437ccecc 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -48,7 +49,7 @@ class CouchDBHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(array $options = [], $level = Level::Debug, bool $bubble = true) + public function __construct(array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $this->options = array_merge([ 'host' => 'localhost', diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index c2469ca6c..1f8ea3843 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -38,7 +39,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, $level = Level::Debug, bool $bubble = true) + public function __construct(string $url, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $urlInfo = parse_url($url); diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index 44d2ff5c5..fad4ac9db 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -15,6 +15,7 @@ use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; use Doctrine\CouchDB\CouchDBClient; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -26,7 +27,7 @@ class DoctrineCouchDBHandler extends AbstractProcessingHandler { private CouchDBClient $client; - public function __construct(CouchDBClient $client, $level = Level::Debug, bool $bubble = true) + public function __construct(CouchDBClient $client, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $this->client = $client; parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index c79d484e1..e23632fe6 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -17,6 +17,7 @@ use Aws\DynamoDb\Marshaler; use Monolog\Formatter\ScalarFormatter; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -35,7 +36,7 @@ class DynamoDbHandler extends AbstractProcessingHandler protected Marshaler $marshaler; - public function __construct(DynamoDbClient $client, string $table, $level = Level::Debug, bool $bubble = true) + public function __construct(DynamoDbClient $client, string $table, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { $this->marshaler = new Marshaler; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index e9eb0d6aa..6c064d711 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -17,6 +17,7 @@ use Monolog\Level; use Elastica\Client; use Elastica\Exception\ExceptionInterface; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -61,7 +62,7 @@ class ElasticaHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) + public function __construct(Client $client, array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 2b14e33b1..55679afb8 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\LevelName; use Throwable; use RuntimeException; use Monolog\Level; @@ -68,7 +69,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(Client $client, array $options = [], $level = Level::Debug, bool $bubble = true) + public function __construct(Client $client, array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index e19a129f7..d52e92603 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -34,7 +35,7 @@ class ErrorLogHandler extends AbstractProcessingHandler * @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, $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false) + public function __construct(int $messageType = self::OPERATING_SYSTEM, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 6ed79c386..ed35f6d12 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -15,6 +15,7 @@ use Monolog\Level; use Monolog\Formatter\GelfMessageFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -33,7 +34,7 @@ class GelfHandler extends AbstractProcessingHandler /** * @param PublisherInterface $publisher a gelf publisher object */ - public function __construct(PublisherInterface $publisher, $level = Level::Debug, bool $bubble = true) + public function __construct(PublisherInterface $publisher, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 4bbd4d59f..bbf28c1da 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -35,7 +36,7 @@ class IFTTTHandler extends AbstractProcessingHandler * @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, $level = Level::Error, bool $bubble = true) + public function __construct(string $eventName, string $secretKey, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the IFTTTHandler'); diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index f0be46ace..51ec6e1ab 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -14,6 +14,7 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; +use Monolog\LevelName; use function array_key_exists; use CurlHandle; use Monolog\LogRecord; @@ -48,7 +49,7 @@ class LogglyHandler extends AbstractProcessingHandler * * @throws MissingExtensionException If the curl extension is missing */ - public function __construct(string $token, $level = Level::Debug, bool $bubble = true) + public function __construct(string $token, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler'); diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index bc8553e13..f1351b50e 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Swift; use Swift_Message; @@ -31,7 +32,7 @@ class MandrillHandler extends MailHandler * @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, $level = Level::Error, bool $bubble = true) + public function __construct(string $apiKey, callable|Swift_Message $message, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 7461ebc28..7ca9f3232 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -17,6 +17,7 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\MongoDBFormatter; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -47,12 +48,8 @@ class MongoDBHandler extends AbstractProcessingHandler * @param string $database Database name * @param string $collection Collection name */ - public function __construct($mongodb, string $database, string $collection, $level = Level::Debug, bool $bubble = true) + public function __construct(Client|Manager $mongodb, string $database, string $collection, int|string|Level|LevelName $level = Level::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 { diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 436d93c91..1bd5a0e89 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -13,6 +13,7 @@ use Monolog\Level; use Monolog\Formatter\LineFormatter; +use Monolog\LevelName; /** * NativeMailerHandler uses the mail() function to send the emails @@ -66,7 +67,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($to, string $subject, string $from, $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70) + public function __construct(string|array $to, string $subject, string $from, int|string|Level|LevelName $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70) { parent::__construct($level, $bubble); $this->to = (array) $to; diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 80e40d20d..c2bf2b626 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use PhpConsole\Connector; use PhpConsole\Handler as VendorPhpConsoleHandler; @@ -120,7 +121,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler * @throws \RuntimeException * @phpstan-param InputOptions $options */ - public function __construct(array $options = [], ?Connector $connector = null, $level = Level::Debug, bool $bubble = true) + public function __construct(array $options = [], ?Connector $connector = null, int|string|Level|LevelName $level = Level::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'); diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 57f3cbf2d..c6cb654e2 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -58,7 +59,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, $level = Level::Debug, bool $bubble = true, ?string $cwd = null) + public function __construct(string $command, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, ?string $cwd = null) { if ($command === '') { throw new \InvalidArgumentException('The command argument must be a non-empty string.'); diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 2c17a56d8..3f1f097f9 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Psr\Log\LoggerInterface; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -37,7 +38,7 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied */ - public function __construct(LoggerInterface $logger, $level = Level::Debug, bool $bubble = true) + public function __construct(LoggerInterface $logger, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index c9febeb56..6228d49d3 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -13,6 +13,7 @@ use InvalidArgumentException; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -43,7 +44,7 @@ class RotatingFileHandler extends StreamHandler * @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, $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct(string $filename, int $maxFiles = 0, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 6752671b0..9a6823b10 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; /** * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html @@ -53,7 +54,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, $to, string $subject, $level = Level::Error, bool $bubble = true) + public function __construct(string $apiUser, string $apiKey, string $from, string|array $to, string $subject, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler'); diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index ae91d4a33..83dd8327f 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -13,6 +13,7 @@ use Aws\Sqs\SqsClient; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -31,7 +32,7 @@ class SqsHandler extends AbstractProcessingHandler private SqsClient $client; private string $queueUrl; - public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Level::Debug, bool $bubble = true) + public function __construct(SqsClient $sqsClient, string $queueUrl, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 0426868be..099f7fd0c 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -44,7 +45,7 @@ class StreamHandler extends AbstractProcessingHandler * * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct($stream, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 02990339d..d761f0d93 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Level; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -37,7 +38,7 @@ class SyslogHandler extends AbstractSyslogHandler * @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, $facility = LOG_USER, $level = Level::Debug, bool $bubble = true, int $logopts = LOG_PID) + public function __construct(string $ident, string|int $facility = LOG_USER, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, int $logopts = LOG_PID) { parent::__construct($facility, $level, $bubble); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index a40317d2f..a308c2c23 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -14,6 +14,7 @@ use DateTimeInterface; use Monolog\Level; use Monolog\Handler\SyslogUdp\UdpSocket; +use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -52,7 +53,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler * * @phpstan-param self::RFC* $rfc */ - public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Level::Debug, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) + public function __construct(string $host, int $port = 514, string|int $facility = LOG_USER, int|string|Level|LevelName $level = Level::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'); diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 9db02765b..791c11f5b 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\NormalizerFormatter; use Monolog\Level; +use Monolog\LevelName; use Monolog\LogRecord; /** @@ -27,7 +28,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler /** * @throws MissingExtensionException */ - public function __construct($level = Level::Debug, bool $bubble = true) + public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) { if (!function_exists('zend_monitor_custom_event')) { throw new MissingExtensionException( diff --git a/tests/Monolog/Handler/MongoDBHandlerTest.php b/tests/Monolog/Handler/MongoDBHandlerTest.php index 6fbdc5f39..0a518c717 100644 --- a/tests/Monolog/Handler/MongoDBHandlerTest.php +++ b/tests/Monolog/Handler/MongoDBHandlerTest.php @@ -18,7 +18,7 @@ class MongoDBHandlerTest extends TestCase { public function testConstructorShouldThrowExceptionForInvalidMongo() { - $this->expectException(\InvalidArgumentException::class); + $this->expectException(\TypeError::class); new MongoDBHandler(new \stdClass, 'db', 'collection'); } From c312cfdabfbbc1b7862ce8ce483ef0c70622b94f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Apr 2022 13:49:06 +0200 Subject: [PATCH 434/498] Restore getLevelName but deprecate it --- UPGRADE.md | 1 - src/Monolog/Logger.php | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/UPGRADE.md b/UPGRADE.md index d1d24e7b9..39aa5dcb9 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -28,7 +28,6 @@ Overall / notable changes: 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` has been removed in favor of `Monolog\Level->toLevelName()->value`. - `Logger::$levels` has been removed. - `Logger::getLevels` has been removed in favor of `Monolog\Level::VALUES` or `Monolog\Level::cases()`. - `setExceptionHandler` now requires a `Closure` instance and not just any `callable`. diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 60df34d07..9a300b80e 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -365,6 +365,23 @@ public function reset(): void } } + /** + * Gets the name of the logging level as a string. + * + * This still returns a string instead of a LevelName for BC, but new code should not rely on this method. + * + * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level $level + * @phpstan-return LevelName + * + * @deprecated Use Monolog\Level->toLevelName()->value instead + */ + public static function getLevelName(int|Level $level): string + { + return self::toMonologLevel($level)->toLevelName()->value; + } + /** * Converts PSR-3 levels to Monolog ones if necessary * From a6a66b117811ee9680585b76f292306345342af4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Apr 2022 14:11:03 +0200 Subject: [PATCH 435/498] Fix phpdoc --- src/Monolog/Logger.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 9a300b80e..0b378464f 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -372,8 +372,8 @@ public function reset(): void * * @throws \Psr\Log\InvalidArgumentException If level is not defined * - * @phpstan-param Level $level - * @phpstan-return LevelName + * @phpstan-param value-of|Level $level + * @phpstan-return value-of * * @deprecated Use Monolog\Level->toLevelName()->value instead */ From 4c7a12b0264f5d073343d34ae6d8b59c38304371 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 7 May 2022 13:05:55 +0200 Subject: [PATCH 436/498] Add SymfonyMailerHandler, deprecate SwiftMailerHandler (#1663) --- composer.json | 8 +- src/Monolog/Handler/SwiftMailerHandler.php | 3 + src/Monolog/Handler/SymfonyMailerHandler.php | 111 ++++++++++++++++++ .../Handler/SymfonyMailerHandlerTest.php | 100 ++++++++++++++++ 4 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 src/Monolog/Handler/SymfonyMailerHandler.php create mode 100644 tests/Monolog/Handler/SymfonyMailerHandlerTest.php diff --git a/composer.json b/composer.json index b151c6549..1c0a5c223 100644 --- a/composer.json +++ b/composer.json @@ -20,17 +20,19 @@ "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "elasticsearch/elasticsearch": "^7", - "mongodb/mongodb": "^1.8", "graylog2/gelf-php": "^1.4.2", + "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", - "phpspec/prophecy": "^1.6.1", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3 || ^2 || ^3", "ruflin/elastica": ">=0.90@dev", "swiftmailer/swiftmailer": "^5.3|^6.0", - "phpstan/phpstan": "^0.12.91" + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index be7e2a587..fae925141 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -24,6 +24,7 @@ * @author Gyula Sallai * * @phpstan-import-type Record from \Monolog\Logger + * @deprecated Since Monolog 2.6. Use SymfonyMailerHandler instead. */ class SwiftMailerHandler extends MailHandler { @@ -42,6 +43,8 @@ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ER { parent::__construct($level, $bubble); + @trigger_error('The SwiftMailerHandler is deprecated since Monolog 2.6. Use SymfonyMailerHandler instead.', E_USER_DEPRECATED); + $this->mailer = $mailer; $this->messageTemplate = $message; } diff --git a/src/Monolog/Handler/SymfonyMailerHandler.php b/src/Monolog/Handler/SymfonyMailerHandler.php new file mode 100644 index 000000000..130e6f1f3 --- /dev/null +++ b/src/Monolog/Handler/SymfonyMailerHandler.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Utils; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Email; + +/** + * SymfonyMailerHandler uses Symfony's Mailer component to send the emails + * + * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + */ +class SymfonyMailerHandler extends MailHandler +{ + /** @var MailerInterface|TransportInterface */ + protected $mailer; + /** @var Email|callable(string, Record[]): Email */ + private $emailTemplate; + + /** + * @psalm-param Email|callable(string, Record[]): Email $email + * + * @param MailerInterface|TransportInterface $mailer The mailer to use + * @param callable|Email $email An email template, the subject/body will be replaced + */ + public function __construct($mailer, $email, $level = Logger::ERROR, bool $bubble = true) + { + parent::__construct($level, $bubble); + + $this->mailer = $mailer; + $this->emailTemplate = $email; + } + + /** + * {@inheritDoc} + */ + protected function send(string $content, array $records): void + { + $this->mailer->send($this->buildMessage($content, $records)); + } + + /** + * Gets the formatter for the Swift_Message subject. + * + * @param string|null $format The format of the subject + */ + protected function getSubjectFormatter(?string $format): FormatterInterface + { + return new LineFormatter($format); + } + + /** + * Creates instance of Email to be sent + * + * @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 + { + $message = null; + if ($this->emailTemplate instanceof Email) { + $message = clone $this->emailTemplate; + } elseif (is_callable($this->emailTemplate)) { + $message = ($this->emailTemplate)($content, $records); + } + + if (!$message instanceof Email) { + $record = reset($records); + throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); + } + + if ($records) { + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); + $message->subject($subjectFormatter->format($this->getHighestRecord($records))); + } + + if ($this->isHtmlBody($content)) { + if (null !== ($charset = $message->getHtmlCharset())) { + $message->html($content, $charset); + } else { + $message->html($content); + } + } else { + if (null !== ($charset = $message->getTextCharset())) { + $message->text($content, $charset); + } else { + $message->text($content); + } + } + + return $message->date(new \DateTimeImmutable()); + } +} diff --git a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php new file mode 100644 index 000000000..af1e926aa --- /dev/null +++ b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Test\TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Email; + +class SymfonyMailerHandlerTest extends TestCase +{ + /** @var MailerInterface&MockObject */ + private $mailer; + + public function setUp(): void + { + $this->mailer = $this + ->getMockBuilder(MailerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testMessageCreationIsLazyWhenUsingCallback() + { + $this->mailer->expects($this->never()) + ->method('send'); + + $callback = function () { + throw new \RuntimeException('Email creation callback should not have been called in this test'); + }; + $handler = new SymfonyMailerHandler($this->mailer, $callback); + + $records = [ + $this->getRecord(Logger::DEBUG), + $this->getRecord(Logger::INFO), + ]; + $handler->handleBatch($records); + } + + public function testMessageCanBeCustomizedGivenLoggedData() + { + // Wire Mailer to expect a specific Email with a customized Subject + $expectedMessage = new Email(); + $this->mailer->expects($this->once()) + ->method('send') + ->with($this->callback(function ($value) use ($expectedMessage) { + return $value instanceof Email + && $value->getSubject() === 'Emergency' + && $value === $expectedMessage; + })); + + // Callback dynamically changes subject based on number of logged records + $callback = function ($content, array $records) use ($expectedMessage) { + $subject = count($records) > 0 ? 'Emergency' : 'Normal'; + return $expectedMessage->subject($subject); + }; + $handler = new SymfonyMailerHandler($this->mailer, $callback); + + // Logging 1 record makes this an Emergency + $records = [ + $this->getRecord(Logger::EMERGENCY), + ]; + $handler->handleBatch($records); + } + + public function testMessageSubjectFormatting() + { + // Wire Mailer to expect a specific Email with a customized Subject + $messageTemplate = new Email(); + $messageTemplate->subject('Alert: %level_name% %message%'); + $receivedMessage = null; + + $this->mailer->expects($this->once()) + ->method('send') + ->with($this->callback(function ($value) use (&$receivedMessage) { + $receivedMessage = $value; + + return true; + })); + + $handler = new SymfonyMailerHandler($this->mailer, $messageTemplate); + + $records = [ + $this->getRecord(Logger::EMERGENCY), + ]; + $handler->handleBatch($records); + + $this->assertEquals('Alert: EMERGENCY test', $receivedMessage->getSubject()); + } +} From bd247659176eb4031163090cf8a85757537d2179 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 22:23:46 +0200 Subject: [PATCH 437/498] ElasticSearch v8 support (#1662) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ElasticSearch v8 support * CI updates Co-authored-by: Thomas Müller --- .github/workflows/continuous-integration.yml | 221 ++++++++++++++++-- composer.json | 14 +- phpstan.neon.dist | 3 + src/Monolog/Handler/ElasticsearchHandler.php | 47 +++- src/Monolog/Test/TestCase.php | 9 + .../Monolog/Formatter/ScalarFormatterTest.php | 7 + tests/Monolog/Handler/AmqpHandlerTest.php | 2 +- tests/Monolog/Handler/DynamoDbHandlerTest.php | 7 + tests/Monolog/Handler/ElasticaHandlerTest.php | 77 ++---- .../Handler/ElasticsearchHandlerTest.php | 153 ++++++------ tests/Monolog/Handler/FlowdockHandlerTest.php | 7 + tests/Monolog/Handler/HandlerWrapperTest.php | 7 + .../Monolog/Handler/InsightOpsHandlerTest.php | 7 + .../Monolog/Handler/LogEntriesHandlerTest.php | 7 + tests/Monolog/Handler/LogmaticHandlerTest.php | 7 + .../Monolog/Handler/PHPConsoleHandlerTest.php | 7 + tests/Monolog/Handler/PushoverHandlerTest.php | 7 + tests/Monolog/Handler/RollbarHandlerTest.php | 7 + .../Handler/RotatingFileHandlerTest.php | 20 +- tests/Monolog/Handler/SlackHandlerTest.php | 7 + tests/Monolog/Handler/SocketHandlerTest.php | 7 + tests/Monolog/Handler/StreamHandlerTest.php | 35 +-- .../Handler/SwiftMailerHandlerTest.php | 7 + .../Handler/SymfonyMailerHandlerTest.php | 7 + .../Handler/ZendMonitorHandlerTest.php | 7 + tests/Monolog/PsrLogCompatTest.php | 7 + tests/Monolog/SignalHandlerTest.php | 6 +- 27 files changed, 506 insertions(+), 193 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5cb0839c2..9ed491d8a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -4,71 +4,242 @@ on: - push - pull_request -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - jobs: tests: name: "CI" - runs-on: ubuntu-latest + runs-on: "${{ matrix.operating-system }}" strategy: + fail-fast: false + matrix: php-version: - "7.2" - "7.3" - "7.4" - "8.0" - # disabled for now as phpspec/prophecy does not allow 8.1 - # - "8.1" + - "8.1" + dependencies: [highest] + + operating-system: + - "ubuntu-latest" + include: - php-version: "7.2" dependencies: lowest - - php-version: "8.0" + operating-system: ubuntu-latest + - php-version: "8.1" dependencies: lowest + operating-system: ubuntu-latest steps: - name: "Checkout" uses: "actions/checkout@v2" + - name: Run CouchDB + timeout-minutes: 1 + continue-on-error: true + uses: "cobot/couchdb-action@master" + with: + couchdb version: '2.3.1' + + - name: Run MongoDB + uses: supercharge/mongodb-github-action@1.7.0 + with: + mongodb-version: 5.0 + - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" php-version: "${{ matrix.php-version }}" extensions: mongodb, redis, amqp + tools: "composer:v2" + ini-values: "memory_limit=-1" - - name: Get composer cache directory - id: composercache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Add require for mongodb/mongodb to make tests runnable + run: 'composer require mongodb/mongodb --dev --no-update' + + - name: "Change dependencies" + run: | + composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^7 + composer config --no-plugins allow-plugins.ocramius/package-versions true - - name: Cache dependencies - uses: actions/cache@v2 + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" with: - path: ${{ steps.composercache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- + dependency-versions: "${{ matrix.dependencies }}" - - name: Add require for mongodb/mongodb to make tests runnable - run: 'composer require ${{ env.COMPOSER_FLAGS }} mongodb/mongodb --dev --no-update' + - name: "Run tests" + run: "composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose" + + - name: "Run tests with psr/log 3" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" + run: | + composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update psr/log:^3 + composer update -W + composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose + + tests-es-7: + name: "CI with ES ${{ matrix.es-version }} on PHP ${{ matrix.php-version }}" + + needs: "tests" + + runs-on: "${{ matrix.operating-system }}" - - name: "Handle lowest dependencies update" - if: "contains(matrix.dependencies, 'lowest')" - run: "echo \"COMPOSER_FLAGS=$COMPOSER_FLAGS --prefer-lowest\" >> $GITHUB_ENV" + strategy: + fail-fast: false + + matrix: + operating-system: + - "ubuntu-latest" + + php-version: + - "7.2" + - "7.3" + - "7.4" + - "8.0" + - "8.1" - - name: "Install latest dependencies" + dependencies: + - "highest" + - "lowest" + + es-version: + - "7.0.0" + - "7.17.0" + + exclude: + # php 7.3 is required + - php-version: "7.2" + es-version: "7.17.0" + # tests failing due an error in deprecated guzzlehttp/ringphp + - php-version: "7.3" + es-version: "7.0.0" + - php-version: "7.4" + es-version: "7.0.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + # required for elasticsearch + - name: Configure sysctl limits run: | - composer update ${{ env.COMPOSER_FLAGS }} + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Run Elasticsearch + timeout-minutes: 1 + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: "${{ matrix.es-version }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp + tools: "composer:v2" + ini-values: "memory_limit=-1" + + - name: "Change dependencies" + run: "composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^${{ matrix.es-version }}" + + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" - name: "Run tests" - run: "composer exec phpunit -- --verbose" + run: "composer exec phpunit -- --group Elasticsearch,Elastica --verbose" - name: "Run tests with psr/log 3" if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" run: | composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update --no-interaction --dev ruflin/elastica elasticsearch/elasticsearch:^7 + composer require --no-update psr/log:^3 + composer update -W + composer exec phpunit -- --group Elasticsearch,Elastica --verbose + + tests-es-8: + name: "CI with ES ${{ matrix.es-version }} on PHP ${{ matrix.php-version }}" + + needs: "tests" + + runs-on: "${{ matrix.operating-system }}" + + strategy: + fail-fast: false + + matrix: + operating-system: + - "ubuntu-latest" + + php-version: + # ES 8 requires PHP 7.4+ + - "7.4" + - "8.0" + - "8.1" + + dependencies: + - "highest" + - "lowest" + + es-version: + - "8.0.0" + - "8.2.0" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + # required for elasticsearch + - name: Configure sysctl limits + run: | + sudo swapoff -a + sudo sysctl -w vm.swappiness=1 + sudo sysctl -w fs.file-max=262144 + sudo sysctl -w vm.max_map_count=262144 + + - name: Run Elasticsearch + timeout-minutes: 1 + uses: elastic/elastic-github-actions/elasticsearch@master + with: + stack-version: "${{ matrix.es-version }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: mongodb, redis, amqp + tools: "composer:v2" + ini-values: "memory_limit=-1" + + - name: "Change dependencies" + run: | + composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar + composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^8 + + - name: "Update dependencies with composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.dependencies }}" + + - name: "Run tests" + run: "composer exec phpunit -- --group Elasticsearch,Elastica --verbose" + + - name: "Run tests with psr/log 3" + if: "contains(matrix.dependencies, 'highest') && matrix.php-version >= '8.0'" + run: | composer require --no-update psr/log:^3 - composer update -W ${{ env.COMPOSER_FLAGS }} - composer exec phpunit -- --verbose + composer update -W + composer exec phpunit -- --group Elasticsearch,Elastica --verbose diff --git a/composer.json b/composer.json index 1c0a5c223..52cb35f67 100644 --- a/composer.json +++ b/composer.json @@ -17,19 +17,22 @@ "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { + "ext-json": "*", "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "elasticsearch/elasticsearch": "^7", + "elasticsearch/elasticsearch": "^7 || ^8", "graylog2/gelf-php": "^1.4.2", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", - "phpunit/phpunit": "^8.5", + "phpunit/phpunit": "^8.5.14", "predis/predis": "^1.1", "rollbar/rollbar": "^1.3 || ^2 || ^3", - "ruflin/elastica": ">=0.90@dev", + "ruflin/elastica": "^7", "swiftmailer/swiftmailer": "^5.3|^6.0", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" @@ -72,6 +75,9 @@ "config": { "lock": false, "sort-packages": true, - "platform-check": false + "platform-check": false, + "allow-plugins": { + "composer/package-versions-deprecated": true + } } } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 961f7ce47..4a368cd2b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -35,3 +35,6 @@ parameters: - '#::popProcessor\(\) should return callable#' - '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#' - '#is incompatible with native type array.#' + + # legacy elasticsearch namespace failures + - '# Elastic\\Elasticsearch\\#' diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index b9d323d83..e88375c0e 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Elastic\Elasticsearch\Response\Elasticsearch; use Throwable; use RuntimeException; use Monolog\Logger; @@ -19,6 +20,8 @@ use InvalidArgumentException; use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; use Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException; +use Elastic\Elasticsearch\Client as Client8; /** * Elasticsearch handler @@ -44,7 +47,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler { /** - * @var Client + * @var Client|Client8 */ protected $client; @@ -54,11 +57,20 @@ class ElasticsearchHandler extends AbstractProcessingHandler protected $options = []; /** - * @param Client $client Elasticsearch Client object - * @param mixed[] $options Handler configuration + * @var bool */ - public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + private $needsType; + + /** + * @param Client|Client8 $client Elasticsearch Client object + * @param mixed[] $options Handler configuration + */ + 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( @@ -69,6 +81,14 @@ public function __construct(Client $client, array $options = [], $level = Logger ], $options ); + + if ($client instanceof Client8 || $client::VERSION[0] === '7') { + $this->needsType = false; + // force the type to _doc for ES8/ES7 + $this->options['type'] = '_doc'; + } else { + $this->needsType = true; + } } /** @@ -133,9 +153,11 @@ protected function bulkSend(array $records): void foreach ($records as $record) { $params['body'][] = [ - 'index' => [ + 'index' => $this->needsType ? [ '_index' => $record['_index'], '_type' => $record['_type'], + ] : [ + '_index' => $record['_index'], ], ]; unset($record['_index'], $record['_type']); @@ -143,6 +165,7 @@ protected function bulkSend(array $records): void $params['body'][] = $record; } + /** @var Elasticsearch */ $responses = $this->client->bulk($params); if ($responses['errors'] === true) { @@ -160,9 +183,9 @@ protected function bulkSend(array $records): void * * Only the first error is converted into an exception. * - * @param mixed[] $responses returned by $this->client->bulk() + * @param mixed[]|Elasticsearch $responses returned by $this->client->bulk() */ - protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException + protected function createExceptionFromResponses($responses): Throwable { foreach ($responses['items'] ?? [] as $item) { if (isset($item['index']['error'])) { @@ -170,6 +193,10 @@ protected function createExceptionFromResponses(array $responses): Elasticsearch } } + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException('Elasticsearch failed to index one or more records.'); + } + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); } @@ -178,10 +205,14 @@ protected function createExceptionFromResponses(array $responses): Elasticsearch * * @param mixed[] $error */ - protected function createExceptionFromError(array $error): ElasticsearchRuntimeException + protected function createExceptionFromError(array $error): Throwable { $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException($error['type'] . ': ' . $error['reason'], 0, $previous); + } + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); } } diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 1824fde45..c4e424967 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -25,6 +25,15 @@ */ class TestCase extends \PHPUnit\Framework\TestCase { + public function tearDown(): void + { + parent::tearDown(); + + if (isset($this->handler)) { + unset($this->handler); + } + } + /** * @param mixed[] $context * diff --git a/tests/Monolog/Formatter/ScalarFormatterTest.php b/tests/Monolog/Formatter/ScalarFormatterTest.php index c72227f7d..596ed78f6 100644 --- a/tests/Monolog/Formatter/ScalarFormatterTest.php +++ b/tests/Monolog/Formatter/ScalarFormatterTest.php @@ -22,6 +22,13 @@ public function setUp(): void $this->formatter = new ScalarFormatter(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->formatter); + } + public function buildTrace(\Exception $e) { $data = []; diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index c2de874c6..62d41a5ed 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -78,7 +78,7 @@ public function testHandleAmqpExt() public function testHandlePhpAmqpLib() { - if (!class_exists('PhpAmqpLib\Connection\AMQPConnection')) { + if (!class_exists('PhpAmqpLib\Channel\AMQPChannel')) { $this->markTestSkipped("php-amqplib not installed"); } diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index 2b237bfa5..92c9c4c37 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -45,6 +45,13 @@ public function setUp(): void $this->client = $clientMockBuilder->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->client); + } + public function testConstruct() { $this->assertInstanceOf('Monolog\Handler\DynamoDbHandler', new DynamoDbHandler($this->client, 'foo')); diff --git a/tests/Monolog/Handler/ElasticaHandlerTest.php b/tests/Monolog/Handler/ElasticaHandlerTest.php index 7fb9808e9..c03fefd09 100644 --- a/tests/Monolog/Handler/ElasticaHandlerTest.php +++ b/tests/Monolog/Handler/ElasticaHandlerTest.php @@ -19,6 +19,9 @@ use Elastica\Request; use Elastica\Response; +/** + * @group Elastica + */ class ElasticaHandlerTest extends TestCase { /** @@ -48,6 +51,13 @@ public function setUp(): void ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->client); + } + /** * @covers Monolog\Handler\ElasticaHandler::write * @covers Monolog\Handler\ElasticaHandler::handleBatch @@ -155,60 +165,6 @@ public function providerTestConnectionErrors() ]; } - /** - * Integration test using localhost Elastic Search server version <7 - * - * @covers Monolog\Handler\ElasticaHandler::__construct - * @covers Monolog\Handler\ElasticaHandler::handleBatch - * @covers Monolog\Handler\ElasticaHandler::bulkSend - * @covers Monolog\Handler\ElasticaHandler::getDefaultFormatter - */ - public function testHandleIntegration() - { - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; - - $expected = $msg; - $expected['datetime'] = $msg['datetime']->format(\DateTime::ISO8601); - $expected['context'] = [ - 'class' => '[object] (stdClass: {})', - 'foo' => 7, - 0 => 'bar', - ]; - - $client = new Client(); - $handler = new ElasticaHandler($client, $this->options); - - try { - $handler->handleBatch([$msg]); - } catch (\RuntimeException $e) { - $this->markTestSkipped("Cannot connect to Elastic Search server on localhost"); - } - - // check document id from ES server response - $documentId = $this->getCreatedDocId($client->getLastResponse()); - $this->assertNotEmpty($documentId, 'No elastic document id received'); - - // retrieve document source from ES and validate - $document = $this->getDocSourceFromElastic( - $client, - $this->options['index'], - $this->options['type'], - $documentId - ); - $this->assertEquals($expected, $document); - - // remove test index from ES - $client->request("/{$this->options['index']}", Request::DELETE); - } - /** * Integration test using localhost Elastic Search server version 7+ * @@ -237,7 +193,9 @@ public function testHandleIntegrationNewESVersion() 0 => 'bar', ]; - $client = new Client(); + $clientOpts = ['url' => 'http://elastic:changeme@127.0.0.1:9200']; + $client = new Client($clientOpts); + $handler = new ElasticaHandler($client, $this->options); try { @@ -271,9 +229,14 @@ public function testHandleIntegrationNewESVersion() protected function getCreatedDocId(Response $response) { $data = $response->getData(); - if (!empty($data['items'][0]['create']['_id'])) { - return $data['items'][0]['create']['_id']; + + if (!empty($data['items'][0]['index']['_id'])) { + return $data['items'][0]['index']['_id']; } + + var_dump('Unexpected response: ', $data); + + return null; } /** diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 764c54c95..e84cdbd60 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -11,17 +11,22 @@ namespace Monolog\Handler; -use Elasticsearch\ClientBuilder; use Monolog\Formatter\ElasticsearchFormatter; use Monolog\Formatter\NormalizerFormatter; use Monolog\Test\TestCase; use Monolog\Logger; use Elasticsearch\Client; +use Elastic\Elasticsearch\Client as Client8; +use Elasticsearch\ClientBuilder; +use Elastic\Elasticsearch\ClientBuilder as ClientBuilder8; +/** + * @group Elasticsearch + */ class ElasticsearchHandlerTest extends TestCase { /** - * @var Client mock + * @var Client|Client8 mock */ protected $client; @@ -35,63 +40,23 @@ class ElasticsearchHandlerTest extends TestCase public function setUp(): void { - // Elasticsearch lib required - if (!class_exists('Elasticsearch\Client')) { - $this->markTestSkipped('elasticsearch/elasticsearch not installed'); - } + $hosts = ['http://elastic:changeme@127.0.0.1:9200']; + $this->client = $this->getClientBuilder() + ->setHosts($hosts) + ->build(); - // base mock Elasticsearch Client object - $this->client = $this->getMockBuilder('Elasticsearch\Client') - ->onlyMethods(['bulk']) - ->disableOriginalConstructor() - ->getMock(); + try { + $this->client->info(); + } catch (\Throwable $e) { + $this->markTestSkipped('Could not connect to Elasticsearch on 127.0.0.1:9200'); + } } - /** - * @covers Monolog\Handler\ElasticsearchHandler::write - * @covers Monolog\Handler\ElasticsearchHandler::handleBatch - * @covers Monolog\Handler\ElasticsearchHandler::bulkSend - * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter - */ - public function testHandle() + public function tearDown(): void { - // log message - $msg = [ - 'level' => Logger::ERROR, - 'level_name' => 'ERROR', - 'channel' => 'meh', - 'context' => ['foo' => 7, 'bar', 'class' => new \stdClass], - 'datetime' => new \DateTimeImmutable("@0"), - 'extra' => [], - 'message' => 'log', - ]; - - // format expected result - $formatter = new ElasticsearchFormatter($this->options['index'], $this->options['type']); - $data = $formatter->format($msg); - unset($data['_index'], $data['_type']); - - $expected = [ - 'body' => [ - [ - 'index' => [ - '_index' => $this->options['index'], - '_type' => $this->options['type'], - ], - ], - $data, - ], - ]; - - // setup ES client mock - $this->client->expects($this->any()) - ->method('bulk') - ->with($expected); + parent::tearDown(); - // perform tests - $handler = new ElasticsearchHandler($this->client, $this->options); - $handler->handle($msg); - $handler->handleBatch([$msg]); + unset($this->client); } /** @@ -108,7 +73,7 @@ public function testSetFormatter() } /** - * @covers Monolog\Handler\ElasticsearchHandler::setFormatter + * @covers Monolog\Handler\ElasticsearchHandler::setFormatter */ public function testSetFormatterInvalid() { @@ -132,6 +97,11 @@ public function testOptions() 'type' => $this->options['type'], 'ignore_error' => false, ]; + + if ($this->client instanceof Client8 || $this->client::VERSION[0] === '7') { + $expected['type'] = '_doc'; + } + $handler = new ElasticsearchHandler($this->client, $this->options); $this->assertEquals($expected, $handler->getOptions()); } @@ -142,10 +112,10 @@ public function testOptions() */ public function testConnectionErrors($ignore, $expectedError) { - $hosts = [['host' => '127.0.0.1', 'port' => 1]]; - $client = ClientBuilder::create() - ->setHosts($hosts) - ->build(); + $hosts = ['http://127.0.0.1:1']; + $client = $this->getClientBuilder() + ->setHosts($hosts) + ->build(); $handlerOpts = ['ignore_error' => $ignore]; $handler = new ElasticsearchHandler($client, $handlerOpts); @@ -178,7 +148,7 @@ public function providerTestConnectionErrors() * @covers Monolog\Handler\ElasticsearchHandler::bulkSend * @covers Monolog\Handler\ElasticsearchHandler::getDefaultFormatter */ - public function testHandleIntegration() + public function testHandleBatchIntegration() { $msg = [ 'level' => Logger::ERROR, @@ -198,21 +168,26 @@ public function testHandleIntegration() 0 => 'bar', ]; - $hosts = [['host' => '127.0.0.1', 'port' => 9200]]; - $client = ClientBuilder::create() + $hosts = ['http://elastic:changeme@127.0.0.1:9200']; + $client = $this->getClientBuilder() ->setHosts($hosts) ->build(); $handler = new ElasticsearchHandler($client, $this->options); - - try { - $handler->handleBatch([$msg]); - } catch (\RuntimeException $e) { - $this->markTestSkipped('Cannot connect to Elasticsearch server on localhost'); - } + $handler->handleBatch([$msg]); // check document id from ES server response - $documentId = $this->getCreatedDocId($client->transport->getLastConnection()->getLastRequestInfo()); - $this->assertNotEmpty($documentId, 'No elastic document id received'); + if ($client instanceof Client8) { + $messageBody = $client->getTransport()->getLastResponse()->getBody(); + + $info = json_decode((string) $messageBody, true); + $this->assertNotNull($info, 'Decoding failed'); + + $documentId = $this->getCreatedDocIdV8($info); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + } else { + $documentId = $this->getCreatedDocId($client->transport->getLastConnection()->getLastRequestInfo()); + $this->assertNotEmpty($documentId, 'No elastic document id received'); + } // retrieve document source from ES and validate $document = $this->getDocSourceFromElastic( @@ -241,25 +216,45 @@ protected function getCreatedDocId(array $info) if (!empty($data['items'][0]['index']['_id'])) { return $data['items'][0]['index']['_id']; } + + return null; + } + + /** + * Return last created document id from ES response + * + * @param array $data Elasticsearch last request info + * @return string|null + */ + protected function getCreatedDocIdV8(array $data) + { + if (!empty($data['items'][0]['index']['_id'])) { + return $data['items'][0]['index']['_id']; + } + + return null; } /** * Retrieve document by id from Elasticsearch * - * @param Client $client Elasticsearch client + * @param Client|Client8 $client Elasticsearch client * @param string $index * @param string $type * @param string $documentId * @return array */ - protected function getDocSourceFromElastic(Client $client, $index, $type, $documentId) + protected function getDocSourceFromElastic($client, $index, $type, $documentId) { $params = [ 'index' => $index, - 'type' => $type, 'id' => $documentId, ]; + if (!$client instanceof Client8 && $client::VERSION[0] !== '7') { + $params['type'] = $type; + } + $data = $client->get($params); if (!empty($data['_source'])) { @@ -268,4 +263,16 @@ protected function getDocSourceFromElastic(Client $client, $index, $type, $docum return []; } + + /** + * @return ClientBuilder|ClientBuilder8 + */ + private function getClientBuilder() + { + if (class_exists(ClientBuilder8::class)) { + return ClientBuilder8::create(); + } + + return ClientBuilder::create(); + } } diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 04bf063dd..45c8799c4 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -38,6 +38,13 @@ public function setUp(): void } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/HandlerWrapperTest.php b/tests/Monolog/Handler/HandlerWrapperTest.php index 87a117b18..67cc2a32f 100644 --- a/tests/Monolog/Handler/HandlerWrapperTest.php +++ b/tests/Monolog/Handler/HandlerWrapperTest.php @@ -32,6 +32,13 @@ public function setUp(): void $this->wrapper = new HandlerWrapper($this->handler); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->wrapper); + } + /** * @return array */ diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php index 9c98d3796..808084e8d 100644 --- a/tests/Monolog/Handler/InsightOpsHandlerTest.php +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -30,6 +30,13 @@ class InsightOpsHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->resource); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index 034d6ab8b..3d7273c80 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -29,6 +29,13 @@ class LogEntriesHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index c30a17942..1cb4254eb 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -29,6 +29,13 @@ class LogmaticHandlerTest extends TestCase */ private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteContent() { $this->createHandler(); diff --git a/tests/Monolog/Handler/PHPConsoleHandlerTest.php b/tests/Monolog/Handler/PHPConsoleHandlerTest.php index 98d8a4b2b..f1ffcf96e 100644 --- a/tests/Monolog/Handler/PHPConsoleHandlerTest.php +++ b/tests/Monolog/Handler/PHPConsoleHandlerTest.php @@ -56,6 +56,13 @@ protected function setUp(): void $this->connector->setErrorsDispatcher($this->errorDispatcher); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->connector, $this->debugDispatcher, $this->errorDispatcher); + } + protected function initDebugDispatcherMock(Connector $connector) { return $this->getMockBuilder('PhpConsole\Dispatcher\Debug') diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 2c77d30ca..8596e3566 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -25,6 +25,13 @@ class PushoverHandlerTest extends TestCase private $res; private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/RollbarHandlerTest.php b/tests/Monolog/Handler/RollbarHandlerTest.php index 0aa7cbff0..60e08d6d3 100644 --- a/tests/Monolog/Handler/RollbarHandlerTest.php +++ b/tests/Monolog/Handler/RollbarHandlerTest.php @@ -44,6 +44,13 @@ protected function setUp(): void $this->setupRollbarLoggerMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->rollbarLogger, $this->reportedExceptionArguments); + } + /** * When reporting exceptions to Rollbar the * level has to be set in the payload data diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 5446f40e8..dd77c853b 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -39,6 +39,18 @@ public function setUp(): void }); } + public function tearDown(): void + { + parent::tearDown(); + + foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { + unlink($file); + } + restore_error_handler(); + + unset($this->lastError); + } + private function assertErrorWasTriggered($code, $message) { if (empty($this->lastError)) { @@ -239,12 +251,4 @@ public function testReuseCurrentFile() $handler->handle($this->getRecord()); $this->assertEquals('footest', file_get_contents($log)); } - - public function tearDown(): void - { - foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { - unlink($file); - } - restore_error_handler(); - } } diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index c6e30a75f..4e4d82207 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -39,6 +39,13 @@ public function setUp(): void } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testWriteHeader() { $this->createHandler(); diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 272dd704a..ba5a1bad4 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -30,6 +30,13 @@ class SocketHandlerTest extends TestCase */ private $res; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->res); + } + public function testInvalidHostname() { $this->expectException(\UnexpectedValueException::class); diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index 43a520bcd..8c69cc58e 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -271,20 +271,20 @@ public function testPreventOOMError($phpMemory, $expectedChunkSize) $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } - $stream = tmpfile(); - - if ($stream === false) { - $this->markTestSkipped('We could not create a temp file to be use as a stream.'); - } - - $exceptionRaised = false; + try { + $stream = tmpfile(); - $handler = new StreamHandler($stream); - stream_get_contents($stream, 1024); + if ($stream === false) { + $this->markTestSkipped('We could not create a temp file to be use as a stream.'); + } - ini_set('memory_limit', $previousValue); + $handler = new StreamHandler($stream); + stream_get_contents($stream, 1024); - $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); + $this->assertEquals($expectedChunkSize, $handler->getStreamChunkSize()); + } finally { + ini_set('memory_limit', $previousValue); + } } /** @@ -298,10 +298,13 @@ public function testSimpleOOMPrevention() $this->markTestSkipped('We could not set a memory limit that would trigger the error.'); } - $stream = tmpfile(); - new StreamHandler($stream); - stream_get_contents($stream); - ini_set('memory_limit', $previousValue); - $this->assertTrue(true); + try { + $stream = tmpfile(); + new StreamHandler($stream); + stream_get_contents($stream); + $this->assertTrue(true); + } finally { + ini_set('memory_limit', $previousValue); + } } } diff --git a/tests/Monolog/Handler/SwiftMailerHandlerTest.php b/tests/Monolog/Handler/SwiftMailerHandlerTest.php index 51596c392..9dd65e61a 100644 --- a/tests/Monolog/Handler/SwiftMailerHandlerTest.php +++ b/tests/Monolog/Handler/SwiftMailerHandlerTest.php @@ -28,6 +28,13 @@ public function setUp(): void ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->mailer); + } + public function testMessageCreationIsLazyWhenUsingCallback() { $this->mailer->expects($this->never()) diff --git a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php index af1e926aa..ea4b9e26f 100644 --- a/tests/Monolog/Handler/SymfonyMailerHandlerTest.php +++ b/tests/Monolog/Handler/SymfonyMailerHandlerTest.php @@ -30,6 +30,13 @@ public function setUp(): void ->getMock(); } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->mailer); + } + public function testMessageCreationIsLazyWhenUsingCallback() { $this->mailer->expects($this->never()) diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index e8fe55c50..e01c0db6c 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -25,6 +25,13 @@ public function setUp(): void } } + public function tearDown(): void + { + parent::tearDown(); + + unset($this->zendMonitorHandler); + } + /** * @covers Monolog\Handler\ZendMonitorHandler::write */ diff --git a/tests/Monolog/PsrLogCompatTest.php b/tests/Monolog/PsrLogCompatTest.php index eaeb3552c..e22f60548 100644 --- a/tests/Monolog/PsrLogCompatTest.php +++ b/tests/Monolog/PsrLogCompatTest.php @@ -25,6 +25,13 @@ class PsrLogCompatTest extends TestCase { private $handler; + public function tearDown(): void + { + parent::tearDown(); + + unset($this->handler); + } + public function getLogger(): LoggerInterface { $logger = new Logger('foo'); diff --git a/tests/Monolog/SignalHandlerTest.php b/tests/Monolog/SignalHandlerTest.php index e73ad8fd3..8c28fc147 100644 --- a/tests/Monolog/SignalHandlerTest.php +++ b/tests/Monolog/SignalHandlerTest.php @@ -39,8 +39,10 @@ protected function setUp(): void } } - protected function tearDown(): void + public function tearDown(): void { + parent::tearDown(); + if ($this->asyncSignalHandling !== null) { pcntl_async_signals($this->asyncSignalHandling); } @@ -53,6 +55,8 @@ protected function tearDown(): void pcntl_signal($signo, $handler); } } + + unset($this->signalHandlers, $this->blockedSignals, $this->asyncSignalHandling); } private function setSignalHandler($signo, $handler = SIG_DFL) From 8a356498d91c9aaac86b6a51243a89f371aaae9f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:08:23 +0200 Subject: [PATCH 438/498] Fix ES8 build --- tests/Monolog/Handler/ElasticsearchHandlerTest.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/Monolog/Handler/ElasticsearchHandlerTest.php b/tests/Monolog/Handler/ElasticsearchHandlerTest.php index 0b4447d9a..e8e466dfa 100644 --- a/tests/Monolog/Handler/ElasticsearchHandlerTest.php +++ b/tests/Monolog/Handler/ElasticsearchHandlerTest.php @@ -25,10 +25,7 @@ */ class ElasticsearchHandlerTest extends TestCase { - /** - * @var Client|Client8 mock - */ - protected Client $client; + protected Client|Client8 $client; /** * @var array Default handler options From acc142c2b7ffac52936c33a84dc6b12ed8fe0023 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:13:26 +0200 Subject: [PATCH 439/498] Drop prophecy usage --- composer.json | 1 - tests/Monolog/Handler/RedisHandlerTest.php | 7 ++++--- tests/Monolog/Handler/RedisPubSubHandlerTest.php | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 0f19dd15f..d050a2c85 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.3", - "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^1.4", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index 479262cfc..806919e69 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -35,9 +35,10 @@ public function testConstructorShouldWorkWithRedis() public function testPredisHandle() { - $redis = $this->prophesize('Predis\Client'); - $redis->rpush('key', 'test')->shouldBeCalled(); - $redis = $redis->reveal(); + $redis = $this->getMockBuilder('Predis\Client')->getMock(); + $redis->expects($this->atLeastOnce()) + ->method('__call') + ->with(self::equalTo('rpush'), self::equalTo(['key', 'test'])); $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass, 'foo' => 34]); diff --git a/tests/Monolog/Handler/RedisPubSubHandlerTest.php b/tests/Monolog/Handler/RedisPubSubHandlerTest.php index 38ece0d27..1dea351fa 100644 --- a/tests/Monolog/Handler/RedisPubSubHandlerTest.php +++ b/tests/Monolog/Handler/RedisPubSubHandlerTest.php @@ -37,9 +37,10 @@ public function testConstructorShouldWorkWithRedis() public function testPredisHandle() { - $redis = $this->prophesize('Predis\Client'); - $redis->publish('key', 'test')->shouldBeCalled(); - $redis = $redis->reveal(); + $redis = $this->getMockBuilder('Predis\Client')->getMock(); + $redis->expects($this->atLeastOnce()) + ->method('__call') + ->with(self::equalTo('publish'), self::equalTo(['key', 'test'])); $record = $this->getRecord(Level::Warning, 'test', ['data' => new \stdClass(), 'foo' => 34]); From 709cb93aa6c11cd405acfe43897f6e481ddec3bb Mon Sep 17 00:00:00 2001 From: Jan-Eric Ortgies Date: Sun, 8 May 2022 23:13:55 +0200 Subject: [PATCH 440/498] replace deprecated method calls in GelfMessageFormatter (#1664) - the getter/setter methods for file, level and facility are deprecated in gelf v1.1 - add those fields as additional instead, as suggested in the gelf spec (https://docs.graylog.org/v1/docs/gelf#gelf-payload-specification) - update tests to reflect changes --- src/Monolog/Formatter/GelfMessageFormatter.php | 13 ++++++------- .../Monolog/Formatter/GelfMessageFormatterTest.php | 14 +++++++------- tests/Monolog/Handler/GelfHandlerTest.php | 6 +++--- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 1ae2fd9e3..338ea2279 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -108,14 +108,14 @@ public function format(LogRecord $record): Message } if (isset($record->channel)) { - $message->setFacility($record->channel); + $message->setAdditional('facility', $record->channel); } if (isset($extra['line'])) { - $message->setLine($extra['line']); + $message->setAdditional('line', $extra['line']); unset($extra['line']); } if (isset($extra['file'])) { - $message->setFile($extra['file']); + $message->setAdditional('file', $extra['file']); unset($extra['file']); } @@ -141,11 +141,10 @@ public function format(LogRecord $record): Message $message->setAdditional($this->contextPrefix . $key, $val); } - /** @phpstan-ignore-next-line */ - if (null === $message->getFile() && isset($context['exception']['file'])) { + if (!$message->hasAdditional('file') && isset($context['exception']['file'])) { if (1 === preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) { - $message->setFile($matches[1]); - $message->setLine($matches[2]); + $message->setAdditional('file', $matches[1]); + $message->setAdditional('line', $matches[2]); } } diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index eb72aa64c..eab7022ce 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -41,9 +41,9 @@ public function testDefaultFormatter() $this->assertInstanceOf('Gelf\Message', $message); $this->assertEquals(0, $message->getTimestamp()); $this->assertEquals('log', $message->getShortMessage()); - $this->assertEquals('meh', $message->getFacility()); - $this->assertEquals(null, $message->getLine()); - $this->assertEquals(null, $message->getFile()); + $this->assertEquals('meh', $message->getAdditional('facility')); + $this->assertEquals(false, $message->hasAdditional('line')); + $this->assertEquals(false, $message->hasAdditional('file')); $this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel()); $this->assertNotEmpty($message->getHost()); @@ -73,8 +73,8 @@ public function testFormatWithFileAndLine() $message = $formatter->format($record); $this->assertInstanceOf('Gelf\Message', $message); - $this->assertEquals('test', $message->getFile()); - $this->assertEquals(14, $message->getLine()); + $this->assertEquals('test', $message->getAdditional('file')); + $this->assertEquals(14, $message->getAdditional('line')); } /** @@ -135,8 +135,8 @@ public function testFormatWithContextContainingException() $this->assertInstanceOf('Gelf\Message', $message); - $this->assertEquals("/some/file/in/dir.php", $message->getFile()); - $this->assertEquals("56", $message->getLine()); + $this->assertEquals("/some/file/in/dir.php", $message->getAdditional('file')); + $this->assertEquals("56", $message->getAdditional('line')); } /** diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 918f53248..e96f11660 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -55,7 +55,7 @@ public function testDebug() $expectedMessage = new Message(); $expectedMessage ->setLevel(7) - ->setFacility("test") + ->setAdditional('facility', 'test') ->setShortMessage($record->message) ->setTimestamp($record->datetime) ; @@ -76,7 +76,7 @@ public function testWarning() $expectedMessage = new Message(); $expectedMessage ->setLevel(4) - ->setFacility("test") + ->setAdditional('facility', 'test') ->setShortMessage($record->message) ->setTimestamp($record->datetime) ; @@ -103,7 +103,7 @@ public function testInjectedGelfMessageFormatter() $expectedMessage = new Message(); $expectedMessage ->setLevel(4) - ->setFacility("test") + ->setAdditional('facility', 'test') ->setHost("mysystem") ->setShortMessage($record->message) ->setTimestamp($record->datetime) From de11fc39ded2babba4a8a2e868ecbdbfb7b70c04 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:19:31 +0200 Subject: [PATCH 441/498] Update upgrade notes --- UPGRADE.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 39aa5dcb9..429423579 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -22,7 +22,7 @@ Overall / notable changes: - 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. -### Logger +#### Logger - `Logger::DEBUG`, `Logger::ERROR`, etc. are now deprecated in favor of the `Level` enum. e.g. instead of `Logger::WARNING` use `Level::Warning` if you need to pass the enum case @@ -53,27 +53,32 @@ Overall / notable changes: - Dropped support for AWS SDK v2 -### FilterHandler +#### FilterHandler - The factory callable to lazy load the nested handler must now be a `Closure` instance and not just a `callable`. -### FingersCrossedHandler +#### FingersCrossedHandler - The factory callable to lazy load the nested handler must now be a `Closure` instance and not just a `callable`. +#### GelfHandler + +- Dropped support for Gelf <1.1 and added support for graylog2/gelf-php v2.x. File, level + and facility are now passed in as additional fields (#1664)[https://github.com/Seldaek/monolog/pull/1664]. + #### RollbarHandler - If you redefined rollbar levels in the `$logLevels` property you must now override the `toRollbarLevel` method instead. -### SamplingHandler +#### SamplingHandler - The factory callable to lazy load the nested handler must now be a `Closure` instance and not just a `callable`. -### SwiftMailerHandler +#### SwiftMailerHandler - Removed deprecated SwiftMailer handler, migrate to SymfonyMailerHandler instead. From 8f6efe928aab56540adf270655c13c9b22bf0fa3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:49:25 +0200 Subject: [PATCH 442/498] Allow more time as elastic search sometimes is slow to boot --- .github/workflows/continuous-integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 9ed491d8a..6f8a4f11a 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -39,7 +39,7 @@ jobs: uses: "actions/checkout@v2" - name: Run CouchDB - timeout-minutes: 1 + timeout-minutes: 3 continue-on-error: true uses: "cobot/couchdb-action@master" with: @@ -135,7 +135,7 @@ jobs: sudo sysctl -w vm.max_map_count=262144 - name: Run Elasticsearch - timeout-minutes: 1 + timeout-minutes: 3 uses: elastic/elastic-github-actions/elasticsearch@master with: stack-version: "${{ matrix.es-version }}" From 354ddc802026d0769e6e12aca702101a529a94ba Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:49:54 +0200 Subject: [PATCH 443/498] Fix changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4963ba8..d04ab53f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ### 2.5.0 (2022-04-08) -* Added `callType` to IntrospectionProcessor (#1612) -* Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651) + * Added `callType` to IntrospectionProcessor (#1612) + * Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651) ### 2.4.0 (2022-03-14) From a71c4e02502dd04d91f1c7d72ffccf0bd11310eb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 8 May 2022 23:50:49 +0200 Subject: [PATCH 444/498] Update changelog --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d04ab53f8..279897d6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,40 @@ +### 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. + +New deprecations: + +- `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. + ### 2.5.0 (2022-04-08) * Added `callType` to IntrospectionProcessor (#1612) From 38fd8efb89a7b0a893675b666ed40f154266f47a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 9 May 2022 00:07:56 +0200 Subject: [PATCH 445/498] Update docs --- README.md | 7 +++++-- doc/01-usage.md | 11 ++++++++--- doc/04-extending.md | 2 ++ doc/message-structure.md | 21 ++++++++++++++------- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8a431d7e3..ac7ec324d 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ $ composer require monolog/monolog ```php pushProcessor(function ($record) { ``` Monolog provides some built-in processors that can be used in your project. -Look at the [dedicated chapter](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#processors) for the list. +Look at the [dedicated chapter](https://github.com/Seldaek/monolog/blob/main/doc/02-handlers-formatters-processors.md#processors) for the list. > Tip: processors can also be registered on a specific handler instead of the logger to apply only for this handler. @@ -165,6 +166,7 @@ You can easily grep through the log files filtering this or that channel. ```php formatted ``` -field in the log record to store its formatted value. Again, this field depends on the implementation of the *Handler* but is a good idea to **stick into the good practices and conventions of the project**. +property in the log record to store its formatted value. You can choose between predefined formatter classes or write your own (e.g. a multiline text file for human-readable output). @@ -206,7 +208,10 @@ You can choose between predefined formatter classes or write your own (e.g. a mu > > This formatter, as its name might indicate, is able to return a lineal string representation of the log record provided. > -> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values $record->context["foo"] and $record->extra["foo"] will be rendered as part of th final result. +> It is also capable to interpolate values from the log record, into the output format template used by the formatter to generate +> the final result, and in order to do it, you need to provide the log record values you are interested in, in the output template +> string using the form %value%, e.g: "'%context.foo% => %extra.foo%'" , in this example the values `$record->context["foo"]` +> and `$record->extra["foo"]` will be rendered as part of the final result. In the following example, we demonstrate how to: 1. Create a `LineFormatter` instance and set a custom output format template. diff --git a/doc/04-extending.md b/doc/04-extending.md index 8d9d09a4b..a57c70b7a 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -21,6 +21,8 @@ abstract class provided by Monolog to keep things DRY. ```php 'John']` as context will be written as "User John logged in". -level | int | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels). -level_name | string | String representation of log level. +level | Monolog\Level case | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels). +levelName | Monolog\LevelName case | String representation of log level. context | array | Arbitrary data passed with the construction of the message. For example the username of the current user or their IP address. channel | string | The channel this message was logged to. This is the name that was passed when the logger was created with `new Logger($channel)`. datetime | Monolog\DateTimeImmutable | Date and time when the message was logged. Class extends `\DateTimeImmutable`. extra | array | A placeholder array where processors can put additional data. Always available, but empty if there are no processors registered. At first glance `context` and `extra` look very similar, and they are in the sense that they both carry arbitrary data that is related to the log message somehow. -The main difference is that `context` can be supplied in user land (it is the 3rd parameter to `Logger::addRecord()`) whereas `extra` is internal only and can be filled by processors. -The reason processors write to `extra` and not to `context` is to prevent overriding any user-provided data in `context`. +The main difference is that `context` can be supplied in user land (it is the 3rd parameter to `Psr\Log\LoggerInterface` methods) whereas `extra` is internal only +and can be filled by processors. The reason processors write to `extra` and not to `context` is to prevent overriding any user-provided data in `context`. + +All properties except `extra` are read-only. + +> Note: For BC reasons with Monolog 1 and 2 which used arrays, `LogRecord` implements `ArrayAccess` so you can access the above properties +> using `$record['message']` for example, with the notable exception of `levelName` which must be referred to as `level_name` for BC. From 2af3276ca6662996863a9cc563d85565c1a8ffb5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 9 May 2022 00:10:39 +0200 Subject: [PATCH 446/498] Update list of handlers --- doc/02-handlers-formatters-processors.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index d999c146a..72c5da013 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -29,7 +29,7 @@ - [_NativeMailerHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NativeMailerHandler.php): Sends emails using PHP's [`mail()`](http://php.net/manual/en/function.mail.php) function. -- [_SwiftMailerHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SwiftMailerHandler.php): Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. +- [_SymfonyMailerHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SymfonyMailerHandler.php): Sends emails using a [`symfony/mailer`](https://symfony.com/doc/current/mailer.html) instance. - [_PushoverHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PushoverHandler.php): Sends mobile notifications via the [Pushover](https://www.pushover.net/) API. - [_FlowdockHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FlowdockHandler.php): Logs records to a [Flowdock](https://www.flowdock.com/) account. - [_SlackWebhookHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SlackWebhookHandler.php): Logs records to a [Slack](https://www.slack.com/) account using Slack Webhooks. @@ -39,7 +39,8 @@ - [_FleepHookHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/FleepHookHandler.php): Logs records to a [Fleep](https://fleep.io/) conversation using Webhooks. - [_IFTTTHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/IFTTTHandler.php): Notifies an [IFTTT](https://ifttt.com/maker) trigger with the log channel, level name and message. - [_TelegramBotHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/TelegramBotHandler.php): Logs records to a [Telegram](https://core.telegram.org/bots/api) bot account. -- [_HipChatHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) +- [_HipChatHandler_](https://github.com/Seldaek/monolog/blob/1.x/src/Monolog/Handler/HipChatHandler.php): Logs records to a [HipChat](http://hipchat.com) chat room using its API. **Deprecated** and removed in Monolog 2.0, use Slack handlers instead, see [Atlassian's announcement](https://www.atlassian.com/partnerships/slack) +- [_SwiftMailerHandler_](https://github.com/Seldaek/monolog/blob/2.x/src/Monolog/Handler/SwiftMailerHandler.php): Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance. **Deprecated** and removed in Monolog 3.0. Use SymfonyMailerHandler instead. ### Log specific servers and networked logging @@ -60,7 +61,7 @@ - [_InsightOpsHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/InsightOpsHandler.php): Logs records to an [InsightOps](https://www.rapid7.com/products/insightops/) account. - [_LogmaticHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogmaticHandler.php): Logs records to a [Logmatic](http://logmatic.io/) account. - [_SqsHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/SqsHandler.php): Logs records to an [AWS SQS](http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-sqs.html) queue. -- [_RavenHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using +- [_RavenHandler_](https://github.com/Seldaek/monolog/blob/1.x/src/Monolog/Handler/RavenHandler.php): Logs records to a [Sentry](http://getsentry.com/) server using [raven](https://packagist.org/packages/raven/raven). **Deprecated** and removed in Monolog 2.0, use sentry/sentry 2.x and the [Sentry\Monolog\Handler](https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php) class instead. ### Logging in development From 2a8c7dffdf0c4f7dd58ae1e7f74b9a3eb93f1ad9 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 9 May 2022 00:16:47 +0200 Subject: [PATCH 447/498] Also allow for slow ES8 start --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 6f8a4f11a..ff2cc1a63 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -210,7 +210,7 @@ jobs: sudo sysctl -w vm.max_map_count=262144 - name: Run Elasticsearch - timeout-minutes: 1 + timeout-minutes: 3 uses: elastic/elastic-github-actions/elasticsearch@master with: stack-version: "${{ matrix.es-version }}" From c709906d0a41790b000625ce70b0c6430add266d Mon Sep 17 00:00:00 2001 From: Lito Date: Mon, 9 May 2022 22:37:14 +0200 Subject: [PATCH 448/498] [2.X] Allow stacktraces parser on LineFormatter (#1665) * Allow stacktraces parser on LineFormatter * Added includeStacktraces parse tests --- src/Monolog/Formatter/LineFormatter.php | 23 ++++++- tests/Monolog/Formatter/LineFormatterTest.php | 67 +++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index a855c5259..d0b4de94a 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -33,6 +33,8 @@ class LineFormatter extends NormalizerFormatter protected $ignoreEmptyContextAndExtra; /** @var bool */ protected $includeStacktraces; + /** @var ?callable */ + protected $stacktracesParser; /** * @param string|null $format The format of the message @@ -49,11 +51,12 @@ public function __construct(?string $format = null, ?string $dateFormat = null, parent::__construct($dateFormat); } - public function includeStacktraces(bool $include = true): self + public function includeStacktraces(bool $include = true, ?callable $parser = null): self { $this->includeStacktraces = $include; if ($this->includeStacktraces) { $this->allowInlineLineBreaks = true; + $this->stacktracesParser = $parser; } return $this; @@ -209,9 +212,25 @@ private function formatException(\Throwable $e): string $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; if ($this->includeStacktraces) { - $str .= "\n[stacktrace]\n" . $e->getTraceAsString() . "\n"; + $str .= $this->stacktracesParser($e); } return $str; } + + private function stacktracesParser(\Throwable $e): string + { + $trace = $e->getTraceAsString(); + + if ($this->stacktracesParser) { + $trace = $this->stacktracesParserCustom($trace); + } + + return "\n[stacktrace]\n" . $trace . "\n"; + } + + private function stacktracesParserCustom(string $trace): string + { + return implode("\n", array_filter(array_map($this->stacktracesParser, explode("\n", $trace)))); + } } diff --git a/tests/Monolog/Formatter/LineFormatterTest.php b/tests/Monolog/Formatter/LineFormatterTest.php index 86d22d38e..d4d7c6588 100644 --- a/tests/Monolog/Formatter/LineFormatterTest.php +++ b/tests/Monolog/Formatter/LineFormatterTest.php @@ -155,6 +155,73 @@ public function testDefFormatWithExceptionAndStacktrace() $this->assertRegexp('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 8).'\)\n\[stacktrace]\n#0}', $message); } + public function testDefFormatWithExceptionAndStacktraceParserFull() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $formatter->includeStacktraces(true, function ($line) { + return $line; + }); + + $message = $formatter->format([ + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => ['exception' => new \RuntimeException('Foo')], + 'datetime' => new \DateTimeImmutable, + 'extra' => [], + 'message' => 'foobar', + ]); + + $trace = explode('[stacktrace]', $message, 2)[1]; + + $this->assertStringContainsString('TestCase.php', $trace); + $this->assertStringContainsString('TestResult.php', $trace); + } + + public function testDefFormatWithExceptionAndStacktraceParserCustom() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $formatter->includeStacktraces(true, function ($line) { + if (strpos($line, 'TestCase.php') === false) { + return $line; + } + }); + + $message = $formatter->format([ + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => ['exception' => new \RuntimeException('Foo')], + 'datetime' => new \DateTimeImmutable, + 'extra' => [], + 'message' => 'foobar', + ]); + + $trace = explode('[stacktrace]', $message, 2)[1]; + + $this->assertStringNotContainsString('TestCase.php', $trace); + $this->assertStringContainsString('TestResult.php', $trace); + } + + public function testDefFormatWithExceptionAndStacktraceParserEmpty() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $formatter->includeStacktraces(true, function ($line) { + return null; + }); + + $message = $formatter->format([ + 'level_name' => 'CRITICAL', + 'channel' => 'core', + 'context' => ['exception' => new \RuntimeException('Foo')], + 'datetime' => new \DateTimeImmutable, + 'extra' => [], + 'message' => 'foobar', + ]); + + $trace = explode('[stacktrace]', $message, 2)[1]; + + $this->assertStringNotContainsString('#', $trace); + } + public function testDefFormatWithPreviousException() { $formatter = new LineFormatter(null, 'Y-m-d'); From 5d43fd52d34230b973b482482e354acf598a4330 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 10:19:45 +0200 Subject: [PATCH 449/498] Allow UdpSocket to reconnect after close() --- src/Monolog/Handler/SyslogUdp/UdpSocket.php | 40 ++++++++++++++------- tests/Monolog/Handler/UdpSocketTest.php | 4 +-- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 30b5186bd..dbd8ef69d 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -23,20 +23,12 @@ class UdpSocket /** @var int */ protected $port; /** @var resource|Socket|null */ - protected $socket; + protected $socket = null; public function __construct(string $ip, int $port = 514) { $this->ip = $ip; $this->port = $port; - $domain = AF_INET; - $protocol = SOL_UDP; - // Check if we are using unix sockets. - if ($port === 0) { - $domain = AF_UNIX; - $protocol = IPPROTO_IP; - } - $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } /** @@ -57,12 +49,34 @@ public function close(): void } } - protected function send(string $chunk): void + /** + * @return resource|Socket + */ + protected function getSocket() { - if (!is_resource($this->socket) && !$this->socket instanceof Socket) { - throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); + if (null !== $this->socket) { + return $this->socket; } - socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); + + $domain = AF_INET; + $protocol = SOL_UDP; + // Check if we are using unix sockets. + if ($this->port === 0) { + $domain = AF_UNIX; + $protocol = IPPROTO_IP; + } + + $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'); + } + + return $this->socket; + } + + protected function send(string $chunk): void + { + socket_sendto($this->getSocket(), $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); } protected function assembleMessage(string $line, string $header): string diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index c14fa8d48..98c65dc24 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -58,10 +58,8 @@ public function testDoubleCloseDoesNotError() $socket->close(); } - public function testWriteAfterCloseErrors() + public function testWriteAfterCloseReopened() { - $this->expectException(\RuntimeException::class); - $socket = new UdpSocket('127.0.0.1', 514); $socket->close(); $socket->write('foo', "HEADER"); From a5d65f6ec48b6ec5f4aefeea59073ac48432d753 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 11:10:07 +0200 Subject: [PATCH 450/498] Fix infinite loops when a log handler triggers logging itself --- src/Monolog/Logger.php | 77 ++++++++++++++++++++++-------------- tests/Monolog/LoggerTest.php | 56 ++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 1f4ef7f1a..0c2240e27 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -147,6 +147,11 @@ class Logger implements LoggerInterface, ResettableInterface */ protected $exceptionHandler; + /** + * @var int Keeps track of depth to prevent infinite logging loops + */ + private $logDepth = 0; + /** * @psalm-param array $processors * @@ -291,30 +296,51 @@ public function useMicrosecondTimestamps(bool $micro): self */ public function addRecord(int $level, string $message, array $context = []): bool { - $record = null; + $this->logDepth += 1; + if ($this->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 + return false; + } - foreach ($this->handlers as $handler) { - if (null === $record) { - // skip creating the record as long as no handler is going to handle it - if (!$handler->isHandling(['level' => $level])) { - continue; - } + try { + $record = null; - $levelName = static::getLevelName($level); + foreach ($this->handlers as $handler) { + if (null === $record) { + // skip creating the record as long as no handler is going to handle it + if (!$handler->isHandling(['level' => $level])) { + continue; + } - $record = [ - 'message' => $message, - 'context' => $context, - 'level' => $level, - 'level_name' => $levelName, - 'channel' => $this->name, - 'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), - 'extra' => [], - ]; + $levelName = static::getLevelName($level); + + $record = [ + 'message' => $message, + 'context' => $context, + 'level' => $level, + 'level_name' => $levelName, + 'channel' => $this->name, + 'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + 'extra' => [], + ]; + + try { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + } catch (Throwable $e) { + $this->handleException($e, $record); + + return true; + } + } + // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted try { - foreach ($this->processors as $processor) { - $record = $processor($record); + if (true === $handler->handle($record)) { + break; } } catch (Throwable $e) { $this->handleException($e, $record); @@ -322,17 +348,8 @@ public function addRecord(int $level, string $message, array $context = []): boo return true; } } - - // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted - try { - if (true === $handler->handle($record)) { - break; - } - } catch (Throwable $e) { - $this->handleException($e, $record); - - return true; - } + } finally { + $this->logDepth--; } return null !== $record; diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index bd5ae20d3..bec548fd3 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -11,6 +11,7 @@ namespace Monolog; +use Monolog\Handler\HandlerInterface; use Monolog\Processor\WebProcessor; use Monolog\Handler\TestHandler; @@ -84,6 +85,28 @@ public function testChannel() $this->assertEquals('foo', $record['channel']); } + /** + * @covers Monolog\Logger::addRecord + */ + public function testLogPreventsCircularLogging() + { + $logger = new Logger(__METHOD__); + + $loggingHandler = new LoggingHandler($logger); + $testHandler = new TestHandler(); + + $logger->pushHandler($loggingHandler); + $logger->pushHandler($testHandler); + + $logger->addRecord(Logger::ALERT, 'test'); + + $records = $testHandler->getRecords(); + $this->assertCount(3, $records); + $this->assertSame('ALERT', $records[0]['level_name']); + $this->assertSame('DEBUG', $records[1]['level_name']); + $this->assertSame('WARNING', $records[2]['level_name']); + } + /** * @covers Monolog\Logger::addRecord */ @@ -717,3 +740,36 @@ public function testReset() $this->assertNotSame($uid2, $processorUid2->getUid()); } } + +class LoggingHandler implements HandlerInterface +{ + /** + * @var Logger + */ + private $logger; + + public function __construct(Logger $logger) + { + $this->logger = $logger; + } + + public function isHandling(array $record): bool + { + return true; + } + + public function handle(array $record): bool + { + $this->logger->debug('Log triggered while logging'); + + return false; + } + + public function handleBatch(array $records): void + { + } + + public function close(): void + { + } +} From 1dacc790b9cdbbac11dacc089937f6e2fa75130d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 11:15:16 +0200 Subject: [PATCH 451/498] Remove LevelName enum in favor of a Level::getName method, fixes #1667 (#1668) --- CHANGELOG.md | 6 ++ UPGRADE.md | 2 +- doc/04-extending.md | 3 +- doc/message-structure.md | 3 +- phpstan-baseline.neon | 4 +- src/Monolog/Formatter/FlowdockFormatter.php | 4 +- src/Monolog/Formatter/FluentdFormatter.php | 4 +- src/Monolog/Formatter/HtmlFormatter.php | 2 +- src/Monolog/Handler/AbstractHandler.php | 13 ++-- src/Monolog/Handler/AbstractSyslogHandler.php | 3 +- src/Monolog/Handler/AmqpHandler.php | 5 +- src/Monolog/Handler/BufferHandler.php | 3 +- src/Monolog/Handler/ChromePHPHandler.php | 3 +- src/Monolog/Handler/CouchDBHandler.php | 3 +- src/Monolog/Handler/CubeHandler.php | 3 +- src/Monolog/Handler/DeduplicationHandler.php | 11 ++- .../Handler/DoctrineCouchDBHandler.php | 3 +- src/Monolog/Handler/DynamoDbHandler.php | 3 +- src/Monolog/Handler/ElasticaHandler.php | 3 +- src/Monolog/Handler/ElasticsearchHandler.php | 3 +- src/Monolog/Handler/ErrorLogHandler.php | 3 +- src/Monolog/Handler/FilterHandler.php | 21 +++-- .../ChannelLevelActivationStrategy.php | 11 ++- .../ErrorLevelActivationStrategy.php | 7 +- src/Monolog/Handler/FingersCrossedHandler.php | 11 ++- src/Monolog/Handler/GelfHandler.php | 3 +- src/Monolog/Handler/IFTTTHandler.php | 3 +- src/Monolog/Handler/LogglyHandler.php | 3 +- src/Monolog/Handler/MandrillHandler.php | 3 +- src/Monolog/Handler/MongoDBHandler.php | 3 +- src/Monolog/Handler/NativeMailerHandler.php | 3 +- src/Monolog/Handler/NewRelicHandler.php | 3 +- src/Monolog/Handler/NullHandler.php | 7 +- src/Monolog/Handler/PHPConsoleHandler.php | 5 +- src/Monolog/Handler/ProcessHandler.php | 3 +- src/Monolog/Handler/PsrHandler.php | 7 +- src/Monolog/Handler/PushoverHandler.php | 27 ++++--- src/Monolog/Handler/RedisHandler.php | 3 +- src/Monolog/Handler/RedisPubSubHandler.php | 3 +- src/Monolog/Handler/RollbarHandler.php | 5 +- src/Monolog/Handler/RotatingFileHandler.php | 3 +- src/Monolog/Handler/SendGridHandler.php | 3 +- src/Monolog/Handler/SqsHandler.php | 3 +- src/Monolog/Handler/StreamHandler.php | 3 +- src/Monolog/Handler/SymfonyMailerHandler.php | 3 +- src/Monolog/Handler/SyslogHandler.php | 3 +- src/Monolog/Handler/SyslogUdpHandler.php | 3 +- src/Monolog/Handler/TestHandler.php | 7 +- src/Monolog/Handler/ZendMonitorHandler.php | 5 +- src/Monolog/Level.php | 76 ++++++++++++++++--- src/Monolog/LevelName.php | 57 -------------- src/Monolog/LogRecord.php | 15 ++-- src/Monolog/Logger.php | 30 ++++---- src/Monolog/Processor/GitProcessor.php | 7 +- .../Processor/IntrospectionProcessor.php | 7 +- src/Monolog/Processor/MercurialProcessor.php | 7 +- src/Monolog/SignalHandler.php | 6 +- src/Monolog/Test/TestCase.php | 5 +- .../Formatter/LogstashFormatterTest.php | 3 +- .../Formatter/MongoDBFormatterTest.php | 3 +- .../Formatter/NormalizerFormatterTest.php | 7 +- tests/Monolog/Handler/PsrHandlerTest.php | 10 +-- .../Monolog/Handler/Slack/SlackRecordTest.php | 9 +-- .../Handler/SlackWebhookHandlerTest.php | 3 +- .../Handler/ZendMonitorHandlerTest.php | 2 +- 65 files changed, 219 insertions(+), 279 deletions(-) delete mode 100644 src/Monolog/LevelName.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 279897d6f..f79170469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 3.0.0-RC2 + +BC Breaks 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 diff --git a/UPGRADE.md b/UPGRADE.md index 429423579..0446803f7 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -18,7 +18,7 @@ Overall / notable changes: 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) +- Log levels are now stored as an enum [`Monolog\Level`](src/Monolog/Level.php) - 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. diff --git a/doc/04-extending.md b/doc/04-extending.md index a57c70b7a..2235fd3b1 100644 --- a/doc/04-extending.md +++ b/doc/04-extending.md @@ -22,7 +22,6 @@ abstract class provided by Monolog to keep things DRY. pdo = $pdo; parent::__construct($level, $bubble); diff --git a/doc/message-structure.md b/doc/message-structure.md index 91508d41a..68a8c7a2e 100644 --- a/doc/message-structure.md +++ b/doc/message-structure.md @@ -9,7 +9,6 @@ property | type | description -----------|---------------------------|------------------------------------------------------------------------------- message | string | The log message. When the `PsrLogMessageProcessor` is used this string may contain placeholders that will be replaced by variables from the context, e.g., "User {username} logged in" with `['username' => 'John']` as context will be written as "User John logged in". level | Monolog\Level case | Severity of the log message. See log levels described in [01-usage.md](01-usage.md#log-levels). -levelName | Monolog\LevelName case | String representation of log level. context | array | Arbitrary data passed with the construction of the message. For example the username of the current user or their IP address. channel | string | The channel this message was logged to. This is the name that was passed when the logger was created with `new Logger($channel)`. datetime | Monolog\DateTimeImmutable | Date and time when the message was logged. Class extends `\DateTimeImmutable`. @@ -22,4 +21,4 @@ and can be filled by processors. The reason processors write to `extra` and not All properties except `extra` are read-only. > Note: For BC reasons with Monolog 1 and 2 which used arrays, `LogRecord` implements `ArrayAccess` so you can access the above properties -> using `$record['message']` for example, with the notable exception of `levelName` which must be referred to as `level_name` for BC. +> using `$record['message']` for example, with the notable exception of `level->getName()` which must be referred to as `level_name` for BC. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 663b27a5c..ac582e230 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -82,11 +82,11 @@ parameters: - message: "#^Variable property access on \\$this\\(Monolog\\\\LogRecord\\)\\.$#" - count: 5 + count: 4 path: src/Monolog/LogRecord.php - - message: "#^Parameter \\#1 \\$level \\('alert'\\|'critical'\\|'debug'\\|'emergency'\\|'error'\\|'info'\\|'notice'\\|'warning'\\|Monolog\\\\Level\\|Monolog\\\\LevelName\\) of method Monolog\\\\Logger\\:\\:log\\(\\) should be contravariant with parameter \\$level \\(mixed\\) of method Psr\\\\Log\\\\LoggerInterface\\:\\:log\\(\\)$#" + message: "#^Parameter \\#1 \\$level \\('alert'\\|'critical'\\|'debug'\\|'emergency'\\|'error'\\|'info'\\|'notice'\\|'warning'\\|Monolog\\\\Level\\) of method Monolog\\\\Logger\\:\\:log\\(\\) should be contravariant with parameter \\$level \\(mixed\\) of method Psr\\\\Log\\\\LoggerInterface\\:\\:log\\(\\)$#" count: 1 path: src/Monolog/Logger.php diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 8e66f2234..b8f7be522 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -39,7 +39,7 @@ public function format(LogRecord $record): array { $tags = [ '#logs', - '#' . strtolower($record->levelName->value), + '#' . $record->level->toPsrLogLevel(), '#' . $record->channel, ]; @@ -50,7 +50,7 @@ public function format(LogRecord $record): array $subject = sprintf( 'in %s: %s - %s', $this->source, - $record->levelName->value, + $record->level->getName(), $this->getShortMessage($record->message) ); diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index ddfd28fbd..9bd2c1604 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -60,7 +60,7 @@ public function format(LogRecord $record): string { $tag = $record->channel; if ($this->levelTag) { - $tag .= '.' . strtolower($record->levelName->value); + $tag .= '.' . $record->level->toPsrLogLevel(); } $message = [ @@ -71,7 +71,7 @@ public function format(LogRecord $record): string if (!$this->levelTag) { $message['level'] = $record->level->value; - $message['level_name'] = $record->levelName->value; + $message['level_name'] = $record->level->getName(); } return Utils::jsonEncode([$tag, $record->datetime->getTimestamp(), $message]); diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 77901aa3d..bf1c61da3 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -85,7 +85,7 @@ protected function addTitle(string $title, Level $level): string */ public function format(LogRecord $record): string { - $output = $this->addTitle($record->levelName->value, $record->level); + $output = $this->addTitle($record->level->getName(), $record->level); $output .= '
'; $output .= $this->addRow('Message', $record->message); diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 92344dd7c..3399a54e2 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Psr\Log\LogLevel; @@ -29,12 +28,12 @@ abstract class AbstractHandler extends Handler implements ResettableInterface protected bool $bubble = true; /** - * @param int|string|Level|LevelName|LogLevel::* $level The minimum logging level at which this handler will be triggered + * @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 * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true) { $this->setLevel($level); $this->bubble = $bubble; @@ -51,11 +50,11 @@ public function isHandling(LogRecord $record): bool /** * Sets minimum logging level at which this handler will be triggered. * - * @param Level|LevelName|LogLevel::* $level Level or level name + * @param Level|LogLevel::* $level Level or level name * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function setLevel(int|string|Level|LevelName $level): self + public function setLevel(int|string|Level $level): self { $this->level = Logger::toMonologLevel($level); diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 0315d981a..49e7da5b4 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -14,7 +14,6 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; -use Monolog\LevelName; /** * Common syslog functionality @@ -61,7 +60,7 @@ protected function toSyslogPriority(Level $level): int /** * @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|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(string|int $facility = \LOG_USER, int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 700c3f02a..5e361b836 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -14,7 +14,6 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; -use Monolog\LevelName; use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; @@ -30,7 +29,7 @@ class AmqpHandler extends AbstractProcessingHandler * @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(AMQPExchange|AMQPChannel $exchange, ?string $exchangeName = null, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + 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; @@ -103,7 +102,7 @@ public function handleBatch(array $records): void */ protected function getRoutingKey(LogRecord $record): string { - $routingKey = sprintf('%s.%s', $record->levelName->value, $record->channel); + $routingKey = sprintf('%s.%s', $record->level->name, $record->channel); return strtolower($routingKey); } diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 3bdd09bba..ff89faa8a 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -47,7 +46,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa * @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|LevelName $level = Level::Debug, bool $bubble = true, bool $flushOnOverflow = false) + public function __construct(HandlerInterface $handler, int $bufferLimit = 0, int|string|Level $level = Level::Debug, bool $bubble = true, bool $flushOnOverflow = false) { parent::__construct($level, $bubble); $this->handler = $handler; diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index f6914bd02..e2b634988 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\ChromePHPFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; use Monolog\DateTimeImmutable; @@ -63,7 +62,7 @@ class ChromePHPHandler extends AbstractProcessingHandler protected static bool $sendHeaders = true; - public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); if (!function_exists('json_encode')) { diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index 8437ccecc..8d9c10e76 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -49,7 +48,7 @@ class CouchDBHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true) { $this->options = array_merge([ 'host' => 'localhost', diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 1f8ea3843..28294d68c 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -39,7 +38,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|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(string $url, int|string|Level $level = Level::Debug, bool $bubble = true) { $urlInfo = parse_url($url); diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 4ba371c52..355491219 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -50,13 +49,13 @@ class DeduplicationHandler extends BufferHandler /** * @param HandlerInterface $handler Handler. * @param string $deduplicationStore The file/path where the deduplication log should be kept - * @param int|string|Level|LevelName|LogLevel::* $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes + * @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 * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $deduplicationLevel + * @phpstan-param value-of|value-of|Level|LogLevel::* $deduplicationLevel */ - public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, int|string|Level|LevelName $deduplicationLevel = Level::Error, int $time = 60, bool $bubble = true) + public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, int|string|Level $deduplicationLevel = Level::Error, int $time = 60, bool $bubble = true) { parent::__construct($handler, 0, Level::Debug, $bubble, false); @@ -112,7 +111,7 @@ private function isDuplicate(LogRecord $record): bool for ($i = count($store) - 1; $i >= 0; $i--) { list($timestamp, $level, $message) = explode(':', $store[$i], 3); - if ($level === $record->levelName->value && $message === $expectedMessage && $timestamp > $timestampValidity) { + if ($level === $record->level->getName() && $message === $expectedMessage && $timestamp > $timestampValidity) { return true; } @@ -162,6 +161,6 @@ private function collectLogs(): void private function appendRecord(LogRecord $record): void { - file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->levelName->value . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); + file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->level->getName() . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); } } diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index fad4ac9db..eab9f1089 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -15,7 +15,6 @@ use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; use Doctrine\CouchDB\CouchDBClient; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -27,7 +26,7 @@ class DoctrineCouchDBHandler extends AbstractProcessingHandler { private CouchDBClient $client; - public function __construct(CouchDBClient $client, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(CouchDBClient $client, int|string|Level $level = Level::Debug, bool $bubble = true) { $this->client = $client; parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index e23632fe6..f1c5a9590 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -17,7 +17,6 @@ use Aws\DynamoDb\Marshaler; use Monolog\Formatter\ScalarFormatter; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -36,7 +35,7 @@ class DynamoDbHandler extends AbstractProcessingHandler protected Marshaler $marshaler; - public function __construct(DynamoDbClient $client, string $table, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(DynamoDbClient $client, string $table, int|string|Level $level = Level::Debug, bool $bubble = true) { $this->marshaler = new Marshaler; diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 6c064d711..d9b85b4d0 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -17,7 +17,6 @@ use Monolog\Level; use Elastica\Client; use Elastica\Exception\ExceptionInterface; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -62,7 +61,7 @@ class ElasticaHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(Client $client, array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(Client $client, array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 0a4fed35a..c288824aa 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -11,7 +11,6 @@ namespace Monolog\Handler; -use Monolog\LevelName; use Elastic\Elasticsearch\Response\Elasticsearch; use Throwable; use RuntimeException; @@ -77,7 +76,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler * * @phpstan-param InputOptions $options */ - public function __construct(Client|Client8 $client, array $options = [], int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(Client|Client8 $client, array $options = [], int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index d52e92603..477d7e45a 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -35,7 +34,7 @@ class ErrorLogHandler extends AbstractProcessingHandler * @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|LevelName $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false) + public function __construct(int $messageType = self::OPERATING_SYSTEM, int|string|Level $level = Level::Debug, bool $bubble = true, bool $expandNewlines = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 60a8b418f..00381ab4d 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -13,7 +13,6 @@ use Closure; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; @@ -56,14 +55,14 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @param Closure|HandlerInterface $handler Handler or factory Closure($record|null, $filterHandler). - * @param int|string|Level|LevelName|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided - * @param int|string|Level|LevelName|LogLevel::* $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array + * @param int|string|Level|array $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 * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel + * @phpstan-param value-of|value-of|Level|LogLevel::*|array|value-of|Level|LogLevel::*> $minLevelOrList + * @phpstan-param value-of|value-of|Level|LogLevel::* $maxLevel */ - public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency, bool $bubble = true) + public function __construct(Closure|HandlerInterface $handler, int|string|Level|array $minLevelOrList = Level::Debug, int|string|Level $maxLevel = Level::Emergency, bool $bubble = true) { $this->handler = $handler; $this->bubble = $bubble; @@ -79,13 +78,13 @@ public function getAcceptedLevels(): array } /** - * @param int|string|Level|LevelName|LogLevel::*|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided - * @param int|string|Level|LevelName|LogLevel::* $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array + * @param int|string|Level|LogLevel::*|array $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 * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|array|value-of|Level|LevelName|LogLevel::*> $minLevelOrList - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $maxLevel + * @phpstan-param value-of|value-of|Level|LogLevel::*|array|value-of|Level|LogLevel::*> $minLevelOrList + * @phpstan-param value-of|value-of|Level|LogLevel::* $maxLevel */ - public function setAcceptedLevels(int|string|Level|LevelName|array $minLevelOrList = Level::Debug, int|string|Level|LevelName $maxLevel = Level::Emergency): self + public function setAcceptedLevels(int|string|Level|array $minLevelOrList = Level::Debug, int|string|Level $maxLevel = Level::Emergency): self { if (is_array($minLevelOrList)) { $acceptedLevels = array_map(Logger::toMonologLevel(...), $minLevelOrList); diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 0aafa7b21..383e19af9 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -12,7 +12,6 @@ namespace Monolog\Handler\FingersCrossed; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -47,13 +46,13 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private array $channelToActionLevel; /** - * @param int|string|Level|LevelName|LogLevel::* $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $channelToActionLevel An array that maps channel names to action levels. + * @param int|string|Level|LogLevel::* $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $channelToActionLevel An array that maps channel names to action levels. * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $defaultActionLevel - * @phpstan-param array|value-of|Level|LevelName|LogLevel::*> $channelToActionLevel + * @phpstan-param value-of|value-of|Level|LogLevel::* $defaultActionLevel + * @phpstan-param array|value-of|Level|LogLevel::*> $channelToActionLevel */ - public function __construct(int|string|Level|LevelName $defaultActionLevel, array $channelToActionLevel = []) + public function __construct(int|string|Level $defaultActionLevel, array $channelToActionLevel = []) { $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel); $this->channelToActionLevel = array_map(Logger::toMonologLevel(...), $channelToActionLevel); diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 2b4e9ec71..c3ca2967a 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -12,7 +12,6 @@ namespace Monolog\Handler\FingersCrossed; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; use Monolog\Logger; use Psr\Log\LogLevel; @@ -27,11 +26,11 @@ class ErrorLevelActivationStrategy implements ActivationStrategyInterface private Level $actionLevel; /** - * @param int|string|Level|LevelName $actionLevel Level or name or value + * @param int|string|Level $actionLevel Level or name or value * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $actionLevel + * @phpstan-param value-of|value-of|Level|LogLevel::* $actionLevel */ - public function __construct(int|string|Level|LevelName $actionLevel) + public function __construct(int|string|Level $actionLevel) { $this->actionLevel = Logger::toMonologLevel($actionLevel); } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 5e88dbc54..ce2a3a8e1 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -15,7 +15,6 @@ use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; @@ -68,16 +67,16 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * @phpstan-param (Closure(LogRecord|null, HandlerInterface): HandlerInterface)|HandlerInterface $handler * * @param Closure|HandlerInterface $handler Handler or factory Closure($record|null, $fingersCrossedHandler). - * @param int|string|Level|LevelName|LogLevel::* $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated + * @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|LevelName|LogLevel::*|null $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * @param int|string|Level|LogLevel::*|null $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $passthruLevel + * @phpstan-param value-of|value-of|Level|LogLevel::*|ActivationStrategyInterface $activationStrategy + * @phpstan-param value-of|value-of|Level|LogLevel::* $passthruLevel */ - public function __construct(Closure|HandlerInterface $handler, int|string|Level|LevelName|ActivationStrategyInterface $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, int|string|Level|LevelName|null $passthruLevel = null) + 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) { if (null === $activationStrategy) { $activationStrategy = new ErrorLevelActivationStrategy(Level::Warning); diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index ed35f6d12..ba5bb975d 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -15,7 +15,6 @@ use Monolog\Level; use Monolog\Formatter\GelfMessageFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -34,7 +33,7 @@ class GelfHandler extends AbstractProcessingHandler /** * @param PublisherInterface $publisher a gelf publisher object */ - public function __construct(PublisherInterface $publisher, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(PublisherInterface $publisher, int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index bbf28c1da..ee7f81f6a 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -36,7 +35,7 @@ class IFTTTHandler extends AbstractProcessingHandler * @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|LevelName $level = Level::Error, bool $bubble = true) + public function __construct(string $eventName, string $secretKey, int|string|Level $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the IFTTTHandler'); diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 51ec6e1ab..2d8e66f18 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -14,7 +14,6 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; -use Monolog\LevelName; use function array_key_exists; use CurlHandle; use Monolog\LogRecord; @@ -49,7 +48,7 @@ class LogglyHandler extends AbstractProcessingHandler * * @throws MissingExtensionException If the curl extension is missing */ - public function __construct(string $token, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(string $token, int|string|Level $level = Level::Debug, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler'); diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index f1351b50e..0f923bc52 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Swift; use Swift_Message; @@ -32,7 +31,7 @@ class MandrillHandler extends MailHandler * @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|LevelName $level = Level::Error, bool $bubble = true) + public function __construct(string $apiKey, callable|Swift_Message $message, int|string|Level $level = Level::Error, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 7ca9f3232..33ab68c6d 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -17,7 +17,6 @@ use Monolog\Level; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\MongoDBFormatter; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -48,7 +47,7 @@ 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|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(Client|Manager $mongodb, string $database, string $collection, int|string|Level $level = Level::Debug, bool $bubble = true) { if ($mongodb instanceof Client) { $this->collection = $mongodb->selectCollection($database, $collection); diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index 1bd5a0e89..d4c9d8010 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -13,7 +13,6 @@ use Monolog\Level; use Monolog\Formatter\LineFormatter; -use Monolog\LevelName; /** * NativeMailerHandler uses the mail() function to send the emails @@ -67,7 +66,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|LevelName $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70) + public function __construct(string|array $to, string $subject, string $from, int|string|Level $level = Level::Error, bool $bubble = true, int $maxColumnWidth = 70) { parent::__construct($level, $bubble); $this->to = (array) $to; diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 7c660e083..b8cb3785b 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\Formatter\NormalizerFormatter; use Monolog\Formatter\FormatterInterface; @@ -33,7 +32,7 @@ class NewRelicHandler extends AbstractProcessingHandler * @inheritDoc */ public function __construct( - int|string|Level|LevelName $level = Level::Error, + int|string|Level $level = Level::Error, bool $bubble = true, /** diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 58579cd7d..1aa84e4f8 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Psr\Log\LogLevel; use Monolog\Logger; use Monolog\LogRecord; @@ -30,11 +29,11 @@ class NullHandler extends Handler private Level $level; /** - * @param string|int|Level|LevelName $level The minimum logging level at which this handler will be triggered + * @param string|int|Level $level The minimum logging level at which this handler will be triggered * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function __construct(string|int|Level|LevelName $level = Level::Debug) + public function __construct(string|int|Level $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index c2bf2b626..a53d26e29 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use PhpConsole\Connector; use PhpConsole\Handler as VendorPhpConsoleHandler; @@ -121,7 +120,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler * @throws \RuntimeException * @phpstan-param InputOptions $options */ - public function __construct(array $options = [], ?Connector $connector = null, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(array $options = [], ?Connector $connector = null, int|string|Level $level = Level::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'); @@ -289,7 +288,7 @@ private function getRecordTags(LogRecord $record): array } } - return [$tags ?? strtolower($record->levelName->value), $filteredContext]; + return [$tags ?? $record->level->toPsrLogLevel(), $filteredContext]; } /** diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index c6cb654e2..9edc9ac54 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -59,7 +58,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|LevelName $level = Level::Debug, bool $bubble = true, ?string $cwd = null) + public function __construct(string $command, int|string|Level $level = Level::Debug, bool $bubble = true, ?string $cwd = null) { if ($command === '') { throw new \InvalidArgumentException('The command argument must be a non-empty string.'); diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 3f1f097f9..6599a83b4 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Psr\Log\LoggerInterface; use Monolog\Formatter\FormatterInterface; use Monolog\LogRecord; @@ -38,7 +37,7 @@ class PsrHandler extends AbstractHandler implements FormattableHandlerInterface /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied */ - public function __construct(LoggerInterface $logger, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(LoggerInterface $logger, int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); @@ -56,9 +55,9 @@ public function handle(LogRecord $record): bool if ($this->formatter !== null) { $formatted = $this->formatter->format($record); - $this->logger->log(strtolower($record->levelName->value), (string) $formatted, $record->context); + $this->logger->log($record->level->toPsrLogLevel(), (string) $formatted, $record->context); } else { - $this->logger->log(strtolower($record->levelName->value), $record->message, $record->context); + $this->logger->log($record->level->toPsrLogLevel(), $record->message, $record->context); } return false === $this->bubble; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 81eb84801..118f5760a 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\Utils; use Psr\Log\LogLevel; @@ -88,25 +87,25 @@ class PushoverHandler extends SocketHandler * @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|LevelName|LogLevel::* $highPriorityLevel The minimum logging level at which this handler will start + * @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|LevelName|LogLevel::* $emergencyLevel The minimum logging level at which this handler will start + * @param int|string|Level|LogLevel::* $emergencyLevel The minimum logging level at which this handler will start * sending "emergency" requests to the Pushover API * * * @phpstan-param string|array $users - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $highPriorityLevel - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $emergencyLevel + * @phpstan-param value-of|value-of|Level|LogLevel::* $highPriorityLevel + * @phpstan-param value-of|value-of|Level|LogLevel::* $emergencyLevel */ public function __construct( string $token, $users, ?string $title = null, - int|string|Level|LevelName $level = Level::Critical, + int|string|Level $level = Level::Critical, bool $bubble = true, bool $useSSL = true, - int|string|Level|LevelName $highPriorityLevel = Level::Critical, - int|string|Level|LevelName $emergencyLevel = Level::Emergency, + int|string|Level $highPriorityLevel = Level::Critical, + int|string|Level $emergencyLevel = Level::Emergency, int $retry = 30, int $expire = 25200, bool $persistent = false, @@ -208,11 +207,11 @@ protected function write(LogRecord $record): void } /** - * @param int|string|Level|LevelName|LogLevel::* $level + * @param int|string|Level|LogLevel::* $level * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function setHighPriorityLevel(int|string|Level|LevelName $level): self + public function setHighPriorityLevel(int|string|Level $level): self { $this->highPriorityLevel = Logger::toMonologLevel($level); @@ -220,11 +219,11 @@ public function setHighPriorityLevel(int|string|Level|LevelName $level): self } /** - * @param int|string|Level|LevelName|LogLevel::* $level + * @param int|string|Level|LogLevel::* $level * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function setEmergencyLevel(int|string|Level|LevelName $level): self + public function setEmergencyLevel(int|string|Level $level): self { $this->emergencyLevel = Logger::toMonologLevel($level); diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 44362566f..5eee5dc69 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; use Predis\Client as Predis; use Redis; @@ -42,7 +41,7 @@ class RedisHandler extends AbstractProcessingHandler * @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|LevelName $level = Level::Debug, bool $bubble = true, int $capSize = 0) + public function __construct(Predis|Redis $redis, string $key, int|string|Level $level = Level::Debug, bool $bubble = true, int $capSize = 0) { $this->redisClient = $redis; $this->redisKey = $key; diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index 6c903515a..960128283 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; use Predis\Client as Predis; use Redis; @@ -40,7 +39,7 @@ class RedisPubSubHandler extends AbstractProcessingHandler * @param Predis|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|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(Predis|Redis $redis, string $key, int|string|Level $level = Level::Debug, bool $bubble = true) { $this->redisClient = $redis; $this->channelKey = $key; diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index a0fe5469a..1d124723b 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Rollbar\RollbarLogger; use Throwable; use Monolog\LogRecord; @@ -47,7 +46,7 @@ class RollbarHandler extends AbstractProcessingHandler /** * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token */ - public function __construct(RollbarLogger $rollbarLogger, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) + public function __construct(RollbarLogger $rollbarLogger, int|string|Level $level = Level::Error, bool $bubble = true) { $this->rollbarLogger = $rollbarLogger; @@ -87,7 +86,7 @@ protected function write(LogRecord $record): void $context = $record->context; $context = array_merge($context, $record->extra, [ 'level' => $this->toRollbarLevel($record->level), - 'monolog_level' => $record->levelName, + 'monolog_level' => $record->level->getName(), 'channel' => $record->channel, 'datetime' => $record->datetime->format('U'), ]); diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 6228d49d3..6da211c71 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -13,7 +13,6 @@ use InvalidArgumentException; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -44,7 +43,7 @@ class RotatingFileHandler extends StreamHandler * @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|LevelName $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct(string $filename, int $maxFiles = 0, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { $this->filename = Utils::canonicalizePath($filename); $this->maxFiles = $maxFiles; diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index 9a6823b10..6228a02f2 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; /** * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html @@ -54,7 +53,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|LevelName $level = Level::Error, bool $bubble = true) + public function __construct(string $apiUser, string $apiKey, string $from, string|array $to, string $subject, int|string|Level $level = Level::Error, bool $bubble = true) { if (!extension_loaded('curl')) { throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler'); diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 83dd8327f..b4512a601 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -13,7 +13,6 @@ use Aws\Sqs\SqsClient; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -32,7 +31,7 @@ class SqsHandler extends AbstractProcessingHandler private SqsClient $client; private string $queueUrl; - public function __construct(SqsClient $sqsClient, string $queueUrl, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(SqsClient $sqsClient, string $queueUrl, int|string|Level $level = Level::Debug, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 099f7fd0c..0bc18ef12 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -45,7 +44,7 @@ class StreamHandler extends AbstractProcessingHandler * * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) + public function __construct($stream, int|string|Level $level = Level::Debug, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/SymfonyMailerHandler.php b/src/Monolog/Handler/SymfonyMailerHandler.php index 4062aae29..842b6577f 100644 --- a/src/Monolog/Handler/SymfonyMailerHandler.php +++ b/src/Monolog/Handler/SymfonyMailerHandler.php @@ -13,7 +13,6 @@ use Closure; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\LogRecord; use Monolog\Utils; @@ -40,7 +39,7 @@ class SymfonyMailerHandler extends MailHandler * @param MailerInterface|TransportInterface $mailer The mailer to use * @param Closure|Email $email An email template, the subject/body will be replaced */ - public function __construct($mailer, Email|Closure $email, int|string|Level|LevelName $level = Level::Error, bool $bubble = true) + public function __construct($mailer, Email|Closure $email, int|string|Level $level = Level::Error, bool $bubble = true) { parent::__construct($level, $bubble); diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index d761f0d93..0816a0119 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -38,7 +37,7 @@ class SyslogHandler extends AbstractSyslogHandler * @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|LevelName $level = Level::Debug, bool $bubble = true, int $logopts = 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) { parent::__construct($facility, $level, $bubble); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index a308c2c23..3d30fbd42 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -14,7 +14,6 @@ use DateTimeInterface; use Monolog\Level; use Monolog\Handler\SyslogUdp\UdpSocket; -use Monolog\LevelName; use Monolog\Utils; use Monolog\LogRecord; @@ -53,7 +52,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler * * @phpstan-param self::RFC* $rfc */ - public function __construct(string $host, int $port = 514, string|int $facility = LOG_USER, int|string|Level|LevelName $level = Level::Debug, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) + 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) { if (!extension_loaded('sockets')) { throw new MissingExtensionException('The sockets extension is required to use the SyslogUdpHandler'); diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index b645d1ed2..1884f83fc 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -104,11 +103,11 @@ public function setSkipReset(bool $skipReset): void } /** - * @param int|string|Level|LevelName|LogLevel::* $level Logging level value or name + * @param int|string|Level|LogLevel::* $level Logging level value or name * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function hasRecords(int|string|Level|LevelName $level): bool + public function hasRecords(int|string|Level $level): bool { return isset($this->recordsByLevel[Logger::toMonologLevel($level)->value]); } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 791c11f5b..1e71194bc 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -14,7 +14,6 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\NormalizerFormatter; use Monolog\Level; -use Monolog\LevelName; use Monolog\LogRecord; /** @@ -28,7 +27,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler /** * @throws MissingExtensionException */ - public function __construct(int|string|Level|LevelName $level = Level::Debug, bool $bubble = true) + public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true) { if (!function_exists('zend_monitor_custom_event')) { throw new MissingExtensionException( @@ -62,7 +61,7 @@ protected function toZendMonitorLevel(Level $level): int protected function write(LogRecord $record): void { $this->writeZendMonitorCustomEvent( - $record->level->toLevelName()->value, + $record->level->getName(), $record->message, $record->formatted, $this->toZendMonitorLevel($record->level) diff --git a/src/Monolog/Level.php b/src/Monolog/Level.php index a4c295366..5caffdcc3 100644 --- a/src/Monolog/Level.php +++ b/src/Monolog/Level.php @@ -14,7 +14,19 @@ use Psr\Log\LogLevel; /** - * @see LevelName + * 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 ->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 { @@ -68,20 +80,33 @@ enum Level: int */ case Emergency = 600; - public static function fromLevelName(LevelName $name): self + /** + * @param value-of|LogLevel::*|'Debug'|'Info'|'Notice'|'Warning'|'Error'|'Critical'|'Alert'|'Emergency' $name + * @return static + */ + public static function fromName(string $name): self { return match ($name) { - LevelName::Debug => self::Debug, - LevelName::Info => self::Info, - LevelName::Notice => self::Notice, - LevelName::Warning => self::Warning, - LevelName::Error => self::Error, - LevelName::Critical => self::Critical, - LevelName::Alert => self::Alert, - LevelName::Emergency => self::Emergency, + '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 $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 */ @@ -100,9 +125,25 @@ public function isLowerThan(Level $level): bool return $this->value < $level->value; } - public function toLevelName(): LevelName + /** + * 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 + */ + public function getName(): string { - return LevelName::fromLevel($this); + 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', + }; } /** @@ -132,4 +173,15 @@ public function toPsrLogLevel(): string 550, 600, ]; + + public const NAMES = [ + 'DEBUG', + 'INFO', + 'NOTICE', + 'WARNING', + 'ERROR', + 'CRITICAL', + 'ALERT', + 'EMERGENCY', + ]; } diff --git a/src/Monolog/LevelName.php b/src/Monolog/LevelName.php deleted file mode 100644 index e1a3248f7..000000000 --- a/src/Monolog/LevelName.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog; - -/** - * @see Level - */ -enum LevelName: string -{ - case Debug = 'DEBUG'; - case Info = 'INFO'; - case Notice = 'NOTICE'; - case Warning = 'WARNING'; - case Error = 'ERROR'; - case Critical = 'CRITICAL'; - case Alert = 'ALERT'; - case Emergency = 'EMERGENCY'; - - public static function fromLevel(Level $level): self - { - return match ($level) { - Level::Debug => self::Debug, - Level::Info => self::Info, - Level::Notice => self::Notice, - Level::Warning => self::Warning, - Level::Error => self::Error, - Level::Critical => self::Critical, - Level::Alert => self::Alert, - Level::Emergency => self::Emergency, - }; - } - - public function toLevel(): Level - { - return Level::fromLevelName($this); - } - - public const VALUES = [ - 'DEBUG', - 'INFO', - 'NOTICE', - 'WARNING', - 'ERROR', - 'CRITICAL', - 'ALERT', - 'EMERGENCY', - ]; -} diff --git a/src/Monolog/LogRecord.php b/src/Monolog/LogRecord.php index df6d0cf8d..df758c58b 100644 --- a/src/Monolog/LogRecord.php +++ b/src/Monolog/LogRecord.php @@ -26,8 +26,6 @@ class LogRecord implements ArrayAccess 'formatted' => true, ]; - public readonly LevelName $levelName; - public function __construct( public readonly \DateTimeImmutable $datetime, public readonly string $channel, @@ -39,7 +37,6 @@ public function __construct( public array $extra = [], public mixed $formatted = null, ) { - $this->levelName = LevelName::fromLevel($level); } public function offsetSet(mixed $offset, mixed $value): void @@ -80,13 +77,13 @@ public function offsetUnset(mixed $offset): void 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') { - $offset = 'levelName'; + $copy = $this->level->getName(); + } else { + $copy = $this->level->value; } - // avoid returning readonly props by ref as this is illegal - $copy = $this->{$offset}->value; - return $copy; } @@ -101,7 +98,7 @@ public function &offsetGet(mixed $offset): mixed } /** - * @phpstan-return array{message: string, context: mixed[], level: value-of, level_name: value-of, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} + * @phpstan-return array{message: string, context: mixed[], level: value-of, level_name: value-of, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ public function toArray(): array { @@ -109,7 +106,7 @@ public function toArray(): array 'message' => $this->message, 'context' => $this->context, 'level' => $this->level->value, - 'level_name' => $this->levelName->value, + 'level_name' => $this->level->getName(), 'channel' => $this->channel, 'datetime' => $this->datetime, 'extra' => $this->extra, diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 0b378464f..01532519a 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -368,43 +368,39 @@ public function reset(): void /** * Gets the name of the logging level as a string. * - * This still returns a string instead of a LevelName for BC, but new code should not rely on this method. + * This still returns a string instead of a Level for BC, but new code should not rely on this method. * * @throws \Psr\Log\InvalidArgumentException If level is not defined * * @phpstan-param value-of|Level $level - * @phpstan-return value-of + * @phpstan-return value-of * - * @deprecated Use Monolog\Level->toLevelName()->value instead + * @deprecated Since 3.0, use {@see toMonologLevel} or {@see \Monolog\Level->getName()} instead */ public static function getLevelName(int|Level $level): string { - return self::toMonologLevel($level)->toLevelName()->value; + return self::toMonologLevel($level)->getName(); } /** * Converts PSR-3 levels to Monolog ones if necessary * - * @param int|string|Level|LevelName|LogLevel::* $level Level number (monolog) or name (PSR-3) + * @param int|string|Level|LogLevel::* $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public static function toMonologLevel(string|int|Level|LevelName $level): Level + public static function toMonologLevel(string|int|Level $level): Level { if ($level instanceof Level) { return $level; } - if ($level instanceof LevelName) { - return $level->toLevel(); - } - 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(', ', LevelName::VALUES + Level::VALUES)); + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES)); } return $levelEnum; @@ -417,12 +413,12 @@ public static function toMonologLevel(string|int|Level|LevelName $level): Level return constant(Level::class . '::' . $upper); } - throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', LevelName::VALUES + Level::VALUES)); + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES)); } $levelEnum = Level::tryFrom($level); if ($levelEnum === null) { - throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', LevelName::VALUES + Level::VALUES)); + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', Level::NAMES + Level::VALUES)); } return $levelEnum; @@ -431,9 +427,9 @@ public static function toMonologLevel(string|int|Level|LevelName $level): Level /** * Checks whether the Logger has a handler that listens on the given level * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function isHandling(int|string|LevelName|Level $level): bool + public function isHandling(int|string|Level $level): bool { $record = new LogRecord( datetime: new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), @@ -477,7 +473,7 @@ public function getExceptionHandler(): Closure|null * @param string|Stringable $message The log message * @param mixed[] $context The log context * - * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-param Level|LogLevel::* $level */ public function log($level, string|\Stringable $message, array $context = []): void { diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 87c234496..4cbd9c84e 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -12,7 +12,6 @@ namespace Monolog\Processor; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -30,11 +29,11 @@ class GitProcessor implements ProcessorInterface private static $cache = null; /** - * @param int|string|Level|LevelName|LogLevel::* $level The minimum logging level at which this Processor will be triggered + * @param int|string|Level|LogLevel::* $level The minimum logging level at which this Processor will be triggered * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function __construct(int|string|Level|LevelName $level = Level::Debug) + public function __construct(int|string|Level $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index 6f4816382..30e7dfed8 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -12,7 +12,6 @@ namespace Monolog\Processor; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -43,12 +42,12 @@ class IntrospectionProcessor implements ProcessorInterface ]; /** - * @param string|int|Level|LevelName $level The minimum logging level at which this Processor will be triggered + * @param string|int|Level $level The minimum logging level at which this Processor will be triggered * @param string[] $skipClassesPartials * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function __construct(int|string|Level|LevelName $level = Level::Debug, array $skipClassesPartials = [], int $skipStackFramesCount = 0) + public function __construct(int|string|Level $level = Level::Debug, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { $this->level = Logger::toMonologLevel($level); $this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials); diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index 41ba16fa4..47b1e64ff 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -12,7 +12,6 @@ namespace Monolog\Processor; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Psr\Log\LogLevel; use Monolog\LogRecord; @@ -29,11 +28,11 @@ class MercurialProcessor implements ProcessorInterface private static $cache = null; /** - * @param int|string|Level|LevelName $level The minimum logging level at which this Processor will be triggered + * @param int|string|Level $level The minimum logging level at which this Processor will be triggered * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function __construct(int|string|Level|LevelName $level = Level::Debug) + public function __construct(int|string|Level $level = Level::Debug) { $this->level = Logger::toMonologLevel($level); } diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 6c41dc0ab..e6b02b083 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -37,12 +37,12 @@ public function __construct(LoggerInterface $logger) } /** - * @param int|string|Level|LevelName $level Level or level name + * @param int|string|Level $level Level or level name * @return $this * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - public function registerSignalHandler(int $signo, int|string|Level|LevelName $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self + public function registerSignalHandler(int $signo, int|string|Level $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self { if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { return $this; diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index 30ce4da53..473c9556f 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -12,7 +12,6 @@ namespace Monolog\Test; use Monolog\Level; -use Monolog\LevelName; use Monolog\Logger; use Monolog\LogRecord; use Monolog\DateTimeImmutable; @@ -39,9 +38,9 @@ public function tearDown(): void * @param array $context * @param array $extra * - * @phpstan-param value-of|value-of|Level|LevelName|LogLevel::* $level + * @phpstan-param value-of|value-of|Level|LogLevel::* $level */ - protected function getRecord(int|string|LevelName|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|string|Level $level = Level::Warning, string|\Stringable $message = 'test', array $context = [], string $channel = 'test', \DateTimeImmutable $datetime = new DateTimeImmutable(true), array $extra = []): LogRecord { return new LogRecord( message: (string) $message, diff --git a/tests/Monolog/Formatter/LogstashFormatterTest.php b/tests/Monolog/Formatter/LogstashFormatterTest.php index 81683e73f..ffb0ee3bc 100644 --- a/tests/Monolog/Formatter/LogstashFormatterTest.php +++ b/tests/Monolog/Formatter/LogstashFormatterTest.php @@ -12,7 +12,6 @@ namespace Monolog\Formatter; use Monolog\Level; -use Monolog\LevelName; use Monolog\Test\TestCase; class LogstashFormatterTest extends TestCase @@ -36,7 +35,7 @@ public function testDefaultFormatterV1() $this->assertEquals("1", $message['@version']); $this->assertEquals('log', $message['message']); $this->assertEquals('meh', $message['channel']); - $this->assertEquals(LevelName::Error->value, $message['level']); + $this->assertEquals(Level::Error->getName(), $message['level']); $this->assertEquals(Level::Error->value, $message['monolog_level']); $this->assertEquals('test', $message['type']); $this->assertEquals('hostname', $message['host']); diff --git a/tests/Monolog/Formatter/MongoDBFormatterTest.php b/tests/Monolog/Formatter/MongoDBFormatterTest.php index 2a58190d0..9a712e543 100644 --- a/tests/Monolog/Formatter/MongoDBFormatterTest.php +++ b/tests/Monolog/Formatter/MongoDBFormatterTest.php @@ -15,7 +15,6 @@ use MongoDB\BSON\Regex; use MongoDB\BSON\UTCDateTime; use Monolog\Level; -use Monolog\LevelName; use Monolog\Test\TestCase; /** @@ -75,7 +74,7 @@ public function testSimpleFormat() $this->assertEquals('some log message', $formattedRecord['message']); $this->assertEquals([], $formattedRecord['context']); $this->assertEquals(Level::Warning->value, $formattedRecord['level']); - $this->assertEquals(LevelName::Warning->value, $formattedRecord['level_name']); + $this->assertEquals(Level::Warning->getName(), $formattedRecord['level_name']); $this->assertEquals('test', $formattedRecord['channel']); $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $formattedRecord['datetime']); $this->assertEquals('1453410690123', $formattedRecord['datetime']->__toString()); diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index f34b7cc04..2b99d4386 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -11,7 +11,6 @@ namespace Monolog\Formatter; -use Monolog\LevelName; use Monolog\Test\TestCase; use Monolog\Level; @@ -38,7 +37,7 @@ public function testFormat() )); $this->assertEquals([ - 'level_name' => LevelName::Error->value, + 'level_name' => Level::Error->getName(), 'level' => Level::Error->value, 'channel' => 'meh', 'message' => 'foo', @@ -148,7 +147,7 @@ public function testBatchFormat() ]); $this->assertEquals([ [ - 'level_name' => LevelName::Critical->value, + 'level_name' => Level::Critical->getName(), 'level' => Level::Critical->value, 'channel' => 'test', 'message' => 'bar', @@ -157,7 +156,7 @@ public function testBatchFormat() 'extra' => [], ], [ - 'level_name' => LevelName::Warning->value, + 'level_name' => Level::Warning->getName(), 'level' => Level::Warning->value, 'channel' => 'log', 'message' => 'foo', diff --git a/tests/Monolog/Handler/PsrHandlerTest.php b/tests/Monolog/Handler/PsrHandlerTest.php index 919261e13..73d4d923d 100644 --- a/tests/Monolog/Handler/PsrHandlerTest.php +++ b/tests/Monolog/Handler/PsrHandlerTest.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use Monolog\Level; -use Monolog\LevelName; use Monolog\Test\TestCase; use Monolog\Formatter\LineFormatter; @@ -24,7 +23,7 @@ class PsrHandlerTest extends TestCase public function logLevelProvider() { return array_map( - fn (Level $level) => [$level->toLevelName(), $level], + fn (Level $level) => [$level->toPsrLogLevel(), $level], Level::cases() ); } @@ -32,7 +31,7 @@ public function logLevelProvider() /** * @dataProvider logLevelProvider */ - public function testHandlesAllLevels(LevelName $levelName, Level $level) + public function testHandlesAllLevels(string $levelName, Level $level) { $message = 'Hello, world! ' . $level->value; $context = ['foo' => 'bar', 'level' => $level->value]; @@ -40,7 +39,7 @@ public function testHandlesAllLevels(LevelName $levelName, Level $level) $psrLogger = $this->createMock('Psr\Log\NullLogger'); $psrLogger->expects($this->once()) ->method('log') - ->with(strtolower($levelName->value), $message, $context); + ->with($levelName, $message, $context); $handler = new PsrHandler($psrLogger); $handler->handle($this->getRecord($level, $message, context: $context)); @@ -51,12 +50,11 @@ public function testFormatter() $message = 'Hello, world!'; $context = ['foo' => 'bar']; $level = Level::Error; - $levelName = LevelName::Error; $psrLogger = $this->createMock('Psr\Log\NullLogger'); $psrLogger->expects($this->once()) ->method('log') - ->with(strtolower($levelName->value), 'dummy', $context); + ->with($level->toPsrLogLevel(), 'dummy', $context); $handler = new PsrHandler($psrLogger); $handler->setFormatter(new LineFormatter('dummy')); diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index f76b61a55..b19a1b63c 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -12,7 +12,6 @@ namespace Monolog\Handler\Slack; use Monolog\Level; -use Monolog\LevelName; use Monolog\Test\TestCase; /** @@ -227,7 +226,7 @@ public function testMapsLevelToColorAttachmentColor() public function testAddsShortAttachmentWithoutContextAndExtra() { $level = Level::Error; - $levelName = LevelName::fromLevel($level)->value; + $levelName = $level->getName(); $record = new SlackRecord(null, null, true, null, true); $data = $record->getSlackData($this->getRecord($level, 'test', ['test' => 1])); @@ -241,7 +240,7 @@ public function testAddsShortAttachmentWithoutContextAndExtra() public function testAddsShortAttachmentWithContextAndExtra() { $level = Level::Error; - $levelName = LevelName::fromLevel($level)->value; + $levelName = $level->getName(); $context = ['test' => 1]; $extra = ['tags' => ['web']]; $record = new SlackRecord(null, null, true, null, true, true); @@ -274,7 +273,7 @@ public function testAddsShortAttachmentWithContextAndExtra() public function testAddsLongAttachmentWithoutContextAndExtra() { $level = Level::Error; - $levelName = LevelName::fromLevel($level)->value; + $levelName = $level->getName(); $record = new SlackRecord(null, null, true, null); $data = $record->getSlackData($this->getRecord($level, 'test', ['test' => 1])); @@ -296,7 +295,7 @@ public function testAddsLongAttachmentWithoutContextAndExtra() public function testAddsLongAttachmentWithContextAndExtra() { $level = Level::Error; - $levelName = LevelName::fromLevel($level)->value; + $levelName = $level->getName(); $context = ['test' => 1]; $extra = ['tags' => ['web']]; $record = new SlackRecord(null, null, true, null, false, true); diff --git a/tests/Monolog/Handler/SlackWebhookHandlerTest.php b/tests/Monolog/Handler/SlackWebhookHandlerTest.php index 31d23e548..f0c2f2a09 100644 --- a/tests/Monolog/Handler/SlackWebhookHandlerTest.php +++ b/tests/Monolog/Handler/SlackWebhookHandlerTest.php @@ -11,7 +11,6 @@ namespace Monolog\Handler; -use Monolog\LevelName; use Monolog\Test\TestCase; use Monolog\Level; use Monolog\Formatter\LineFormatter; @@ -119,7 +118,7 @@ public function testConstructorFullWithAttachment() 'fields' => [ [ 'title' => 'Level', - 'value' => LevelName::Warning->value, + 'value' => Level::Warning->getName(), 'short' => false, ], ], diff --git a/tests/Monolog/Handler/ZendMonitorHandlerTest.php b/tests/Monolog/Handler/ZendMonitorHandlerTest.php index 6cbd5e56a..c79aa4392 100644 --- a/tests/Monolog/Handler/ZendMonitorHandlerTest.php +++ b/tests/Monolog/Handler/ZendMonitorHandlerTest.php @@ -58,7 +58,7 @@ public function testWrite() $zendMonitor->expects($this->once()) ->method('writeZendMonitorCustomEvent') ->with( - $record->levelName->value, + $record->level->getName(), $record->message, $formatterResult, \ZEND_MONITOR_EVENT_SEVERITY_WARNING From 247918972acd74356b0a91dfaa5adcaec069b6c0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 11:36:00 +0200 Subject: [PATCH 452/498] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d04ab53f8..e374fa78e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### 2.6.0 (2022-05-10) + + * Deprecated `SwiftMailerHandler`, use `SymfonyMailerHandler` instead + * Added `SymfonyMailerHandler` (#1663) + * Added ElasticSearch 8.x support to the ElasticsearchHandler (#1662) + * Added a way to filter/modify stack traces in LineFormatter (#1665) + * Fixed UdpSocket not being able to reopen/reconnect after close() + * Fixed infinite loops if a Handler is triggering logging while handling log records + ### 2.5.0 (2022-04-08) * Added `callType` to IntrospectionProcessor (#1612) From 60ad5183b5e5d6c9d4047e9f3072d36071dcc161 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 10 May 2022 12:39:55 +0200 Subject: [PATCH 453/498] Update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58bd5e44c..975ef0ed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -### 3.0.0-RC2 +### 3.0.0 (2022-05-10) -BC Breaks from RC1 +Changes from RC1 - The `Monolog\LevelName` enum does not exist anymore, use `Monolog\Level->getName()` instead. From 9c1566a971d42ff1acb4756708e8d9a5568bb194 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 8 Jun 2022 21:51:47 +0200 Subject: [PATCH 454/498] Add a way to disable logging loop detection, closes #1681 --- src/Monolog/Logger.php | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 0c2240e27..041189599 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -152,6 +152,13 @@ class Logger implements LoggerInterface, ResettableInterface */ private $logDepth = 0; + /** + * @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 $detectCycles = true; + /** * @psalm-param array $processors * @@ -284,6 +291,13 @@ public function useMicrosecondTimestamps(bool $micro): self return $this; } + public function useLoggingLoopDetection(bool $detectCycles): self + { + $this->detectCycles = $detectCycles; + + return $this; + } + /** * Adds a log record. * @@ -296,7 +310,9 @@ public function useMicrosecondTimestamps(bool $micro): self */ public function addRecord(int $level, string $message, array $context = []): bool { - $this->logDepth += 1; + if ($this->detectCycles) { + $this->logDepth += 1; + } if ($this->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; @@ -349,7 +365,9 @@ public function addRecord(int $level, string $message, array $context = []): boo } } } finally { - $this->logDepth--; + if ($this->detectCycles) { + $this->logDepth--; + } } return null !== $record; From 64854f09da8b2874afa2ee4e0cf4b96b3d52cb07 Mon Sep 17 00:00:00 2001 From: Dmitry Menshikov Date: Thu, 9 Jun 2022 10:04:15 +0300 Subject: [PATCH 455/498] =?UTF-8?q?Correct=20handling=20of=20E=5FUSER=5FER?= =?UTF-8?q?ROR=20as=20fatal=20error=20if=20registerErrorHandl=E2=80=A6=20(?= =?UTF-8?q?#1670)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Correct handling of E_USER_ERROR as fatal error if registerErrorHandler is called with callPrevious, fixes #1669 --- src/Monolog/ErrorHandler.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 16794be65..576f1713f 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -46,8 +46,8 @@ class ErrorHandler private $fatalLevel = LogLevel::ALERT; /** @var ?string */ private $reservedMemory = null; - /** @var ?mixed */ - private $lastFatalTrace; + /** @var ?array{type: int, message: string, file: string, line: int, trace: mixed} */ + private $lastFatalData = null; /** @var int[] */ private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; @@ -223,7 +223,7 @@ public function handleError(int $code, string $message, string $file = '', int $ } else { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); array_shift($trace); // Exclude handleError from trace - $this->lastFatalTrace = $trace; + $this->lastFatalData = ['type' => $code, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace]; } if ($this->previousErrorHandler === true) { @@ -242,12 +242,18 @@ public function handleFatalError(): void { $this->reservedMemory = ''; - $lastError = error_get_last(); + if (is_array($this->lastFatalData)) { + $lastError = $this->lastFatalData; + } else { + $lastError = error_get_last(); + } + if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) { + $trace = $lastError['trace'] ?? null; $this->logger->log( $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], - ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace] + ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $trace] ); if ($this->logger instanceof Logger) { From 417c27dc729c8457e52e170fb75e57a5a9ca8e20 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 9 Jun 2022 10:11:53 +0200 Subject: [PATCH 456/498] Remove return type from ProcessorInterface to fix interop with Monolog 2, fixes #1680 --- src/Monolog/Processor/ProcessorInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index a044f1cdb..ebe41fc20 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -23,5 +23,5 @@ interface ProcessorInterface /** * @return LogRecord The processed record */ - public function __invoke(LogRecord $record): LogRecord; + public function __invoke(LogRecord $record); } From 9992c77e0534f9ca0e11c807b785838b5bad1ff8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 9 Jun 2022 10:17:29 +0200 Subject: [PATCH 457/498] Add warning that docs site is for 3.x, fixes #1679 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ac7ec324d..87c7f664d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ [![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 From eac0c22ad27910ac97a5c33eb588257a0993487f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 9 Jun 2022 10:40:17 +0200 Subject: [PATCH 458/498] Mark TestCase internal until PHPStorm handles this better, fixes #1677 --- src/Monolog/Test/TestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index c4e424967..bc0b425ea 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -22,6 +22,8 @@ * * @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 { From 8ac56aa42bff0f099af28ebe03c43004e9bc0c44 Mon Sep 17 00:00:00 2001 From: Gene Alyson Fortunado Torcende Date: Thu, 9 Jun 2022 16:41:11 +0800 Subject: [PATCH 459/498] RotatingFileHandler to maintain the correct maximum number files when using folder by date (#1671) --- src/Monolog/Handler/RotatingFileHandler.php | 6 +- .../Handler/RotatingFileHandlerTest.php | 98 +++++++++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 2b7c48030..17745d221 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -191,7 +191,11 @@ protected function getGlobPattern(): string $fileInfo = pathinfo($this->filename); $glob = str_replace( ['{filename}', '{date}'], - [$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'], + [$fileInfo['filename'], str_replace( + ['Y', 'y', 'm', 'd'], + ['[0-9][0-9][0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]'], + $this->dateFormat) + ], $fileInfo['dirname'] . '/' . $this->filenameFormat ); if (isset($fileInfo['extension'])) { diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index dd77c853b..1f94adf5e 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -46,11 +46,38 @@ public function tearDown(): void foreach (glob(__DIR__.'/Fixtures/*.rot') as $file) { unlink($file); } + + if ('testRotationWithFolderByDate' === $this->getName(false)) { + foreach (glob(__DIR__.'/Fixtures/[0-9]*') as $folder) { + $this->rrmdir($folder); + } + } + restore_error_handler(); unset($this->lastError); } + private function rrmdir($directory) { + if (! is_dir($directory)) { + throw new InvalidArgumentException("$directory must be a directory"); + } + + if (substr($directory, strlen($directory) - 1, 1) !== '/') { + $directory .= '/'; + } + + foreach (glob($directory . '*', GLOB_MARK) as $path) { + if (is_dir($path)) { + $this->rrmdir($path); + } else { + unlink($path); + } + } + + return rmdir($directory); + } + private function assertErrorWasTriggered($code, $message) { if (empty($this->lastError)) { @@ -141,6 +168,76 @@ public function rotationTests() ]; } + private function createDeep($file) + { + mkdir(dirname($file), 0777, true); + touch($file); + + return $file; + } + + /** + * @dataProvider rotationWithFolderByDateTests + */ + public function testRotationWithFolderByDate($createFile, $dateFormat, $timeCallback) + { + $old1 = $this->createDeep(__DIR__.'/Fixtures/'.date($dateFormat, $timeCallback(-1)).'/foo.rot'); + $old2 = $this->createDeep(__DIR__.'/Fixtures/'.date($dateFormat, $timeCallback(-2)).'/foo.rot'); + $old3 = $this->createDeep(__DIR__.'/Fixtures/'.date($dateFormat, $timeCallback(-3)).'/foo.rot'); + $old4 = $this->createDeep(__DIR__.'/Fixtures/'.date($dateFormat, $timeCallback(-4)).'/foo.rot'); + + $log = __DIR__.'/Fixtures/'.date($dateFormat).'/foo.rot'; + + if ($createFile) { + $this->createDeep($log); + } + + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->setFilenameFormat('{date}/{filename}', $dateFormat); + $handler->handle($this->getRecord()); + + $handler->close(); + + $this->assertTrue(file_exists($log)); + $this->assertTrue(file_exists($old1)); + $this->assertEquals($createFile, file_exists($old2)); + $this->assertEquals($createFile, file_exists($old3)); + $this->assertEquals($createFile, file_exists($old4)); + $this->assertEquals('test', file_get_contents($log)); + } + + public function rotationWithFolderByDateTests() + { + $now = time(); + $dayCallback = function ($ago) use ($now) { + return $now + 86400 * $ago; + }; + $monthCallback = function ($ago) { + return gmmktime(0, 0, 0, (int) (date('n') + $ago), 1, (int) date('Y')); + }; + $yearCallback = function ($ago) { + return gmmktime(0, 0, 0, 1, 1, (int) (date('Y') + $ago)); + }; + + return [ + 'Rotation is triggered when the file of the current day is not present' + => [true, 'Y/m/d', $dayCallback], + 'Rotation is not triggered when the file of the current day is already present' + => [false, 'Y/m/d', $dayCallback], + + 'Rotation is triggered when the file of the current month is not present' + => [true, 'Y/m', $monthCallback], + 'Rotation is not triggered when the file of the current month is already present' + => [false, 'Y/m', $monthCallback], + + 'Rotation is triggered when the file of the current year is not present' + => [true, 'Y', $yearCallback], + 'Rotation is not triggered when the file of the current year is already present' + => [false, 'Y', $yearCallback], + ]; + } + /** * @dataProvider dateFormatProvider */ @@ -205,6 +302,7 @@ public function filenameFormatProvider() ['foobar-{date}', true], ['foo-{date}-bar', true], ['{date}-foobar', true], + ['{date}/{filename}', true], ['foobar', false], ]; } From 24e414c99378c227fff95a6483c85dfff2e79779 Mon Sep 17 00:00:00 2001 From: henning Date: Tue, 7 Jun 2022 16:13:46 +0200 Subject: [PATCH 460/498] Added $datetime parameter to addRecord method to optionally log into the past/future --- src/Monolog/Logger.php | 13 +++++++------ tests/Monolog/LoggerTest.php | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 041189599..099185205 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -301,14 +301,15 @@ public function useLoggingLoopDetection(bool $detectCycles): self /** * Adds a log record. * - * @param int $level The logging level - * @param string $message The log message - * @param mixed[] $context The log context - * @return bool Whether the record has been processed + * @param int $level The logging level + * @param string $message The log message + * @param mixed[] $context The log context + * @param DateTimeImmutable $datetime Optional log date to log into the past or future + * @return bool Whether the record has been processed * * @phpstan-param Level $level */ - public function addRecord(int $level, string $message, array $context = []): bool + public function addRecord(int $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool { if ($this->detectCycles) { $this->logDepth += 1; @@ -338,7 +339,7 @@ public function addRecord(int $level, string $message, array $context = []): boo 'level' => $level, 'level_name' => $levelName, 'channel' => $this->name, - 'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + 'datetime' => $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), 'extra' => [], ]; diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index bec548fd3..0b07a7cf1 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -739,6 +739,28 @@ public function testReset() $this->assertNotSame($uid1, $processorUid1->getUid()); $this->assertNotSame($uid2, $processorUid2->getUid()); } + + /** + * @covers Logger::addRecord + */ + public function testLogWithDateTime() + { + foreach ([true, false] as $microseconds) { + $logger = new Logger(__METHOD__); + + $loggingHandler = new LoggingHandler($logger); + $testHandler = new TestHandler(); + + $logger->pushHandler($loggingHandler); + $logger->pushHandler($testHandler); + + $datetime = (new DateTimeImmutable($microseconds))->modify('2022-03-04 05:06:07'); + $logger->addRecord(Logger::DEBUG, 'test', [], $datetime); + + list($record) = $testHandler->getRecords(); + $this->assertEquals($datetime->format('Y-m-d H:i:s'), $record['datetime']->format('Y-m-d H:i:s')); + } + } } class LoggingHandler implements HandlerInterface From 5579edf28aee1190a798bfa5be8bc16c563bd524 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 9 Jun 2022 10:59:12 +0200 Subject: [PATCH 461/498] Update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e374fa78e..9ae89099a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### 2.7.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) + * 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) + ### 2.6.0 (2022-05-10) * Deprecated `SwiftMailerHandler`, use `SymfonyMailerHandler` instead From 0c375495d40df0207e5833dca333f963b171ff43 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 9 Jun 2022 11:09:00 +0200 Subject: [PATCH 462/498] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e30a904ad..2e466b9a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### 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 From 3cba75ec0926eec177a4a2cd6c977ecddd0fc7c1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 19 Jun 2022 14:12:51 +0200 Subject: [PATCH 463/498] Mark Logger @final to discourage extension --- src/Monolog/Logger.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 39d14a1b0..ce4c442c8 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -28,6 +28,7 @@ * and uses them to store records that are added to it. * * @author Jordi Boggiano + * @final */ class Logger implements LoggerInterface, ResettableInterface { From 100d0f1625988be5cc8595aaf7429d0d9e96b9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Reker=20=E2=9A=A1=EF=B8=8F?= Date: Tue, 21 Jun 2022 22:21:02 +0200 Subject: [PATCH 464/498] is null (#1711) Replaces is_null($var) expression with null === $var. --- src/Monolog/Formatter/GelfMessageFormatter.php | 6 +++--- src/Monolog/Processor/PsrLogMessageProcessor.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 338ea2279..33116a261 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -71,11 +71,11 @@ public function __construct(?string $systemName = null, ?string $extraPrefix = n parent::__construct('U.u'); - $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName; + $this->systemName = (null === $systemName || $systemName === '') ? (string) gethostname() : $systemName; - $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix; + $this->extraPrefix = null === $extraPrefix ? '' : $extraPrefix; $this->contextPrefix = $contextPrefix; - $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength; + $this->maxLength = null === $maxLength ? self::DEFAULT_MAX_LENGTH : $maxLength; } /** diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 329efa223..f2407d563 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -57,7 +57,7 @@ public function __invoke(LogRecord $record): LogRecord continue; } - if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { + if (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) { From 1ae4f609ba1c10f78dd1c7f8e652345db0503ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Fri, 22 Jul 2022 13:03:58 +0200 Subject: [PATCH 465/498] Add basic support to Google Cloud Logging format (#1690) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Google Cloud Logging doesn't show the correct level log when using JsonFormatter, making observability a bit trickier. This applies minor tweaks to the default format, allowing log entries to be properly represented. There are alternative packages to this but they add fields that aren't strictly required - also performing `debug_backtrace()` calls that are usually not desired when in production mode. Signed-off-by: Luís Cobucci --- .../Formatter/GoogleCloudLoggingFormatter.php | 39 ++++++++++++++ .../GoogleCloudLoggingFormatterTest.php | 54 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/Monolog/Formatter/GoogleCloudLoggingFormatter.php create mode 100644 tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php diff --git a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php new file mode 100644 index 000000000..d37d1e0cc --- /dev/null +++ b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\LogRecord; + +/** + * Encodes message information into JSON in a format compatible with Cloud logging. + * + * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry + * + * @author Luís Cobucci + */ +final class GoogleCloudLoggingFormatter extends JsonFormatter +{ + protected function normalizeRecord(LogRecord $record): array + { + $normalized = parent::normalizeRecord($record); + + // Re-key level for GCP logging + $normalized['severity'] = $normalized['level_name']; + $normalized['timestamp'] = $record->datetime->format(DateTimeInterface::RFC3339_EXTENDED); + + // Remove keys that are not used by GCP + unset($normalized['level'], $normalized['level_name'], $normalized['datetime']); + + return $normalized; + } +} diff --git a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php new file mode 100644 index 000000000..e46846aec --- /dev/null +++ b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\Test\TestCase; +use function json_decode; + +class GoogleCloudLoggingFormatterTest extends TestCase +{ + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::normalizeRecord + */ + public function formatProvidesRfc3339Timestamps(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("datetime", $formatted_decoded); + $this->assertArrayHasKey("timestamp", $formatted_decoded); + $this->assertSame($record->datetime->format(DateTimeInterface::RFC3339_EXTENDED), $formatted_decoded["timestamp"]); + } + + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::normalizeRecord + */ + public function formatIntroducesLogSeverity(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("level", $formatted_decoded); + $this->assertArrayNotHasKey("level_name", $formatted_decoded); + $this->assertArrayHasKey("severity", $formatted_decoded); + $this->assertSame($record->level->getName(), $formatted_decoded["severity"]); + } +} From 197f534d42591eb32ebfee60e9c92b5192be39a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Fri, 22 Jul 2022 13:04:51 +0200 Subject: [PATCH 466/498] Add basic support to Google Cloud Logging format (#1719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Google Cloud Logging doesn't show the correct level log when using JsonFormatter, making observability a bit trickier. This applies minor tweaks to the default format, allowing log entries to be properly represented. There are alternative packages to this but they add fields that aren't strictly required - also performing `debug_backtrace()` calls that are usually not desired when in production mode. This is a backport of https://github.com/Seldaek/monolog/pull/1690 Signed-off-by: Luís Cobucci --- .../Formatter/GoogleCloudLoggingFormatter.php | 39 ++++++++++++++ .../GoogleCloudLoggingFormatterTest.php | 54 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/Monolog/Formatter/GoogleCloudLoggingFormatter.php create mode 100644 tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php diff --git a/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php new file mode 100644 index 000000000..0cd287f5e --- /dev/null +++ b/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\LogRecord; + +/** + * Encodes message information into JSON in a format compatible with Cloud logging. + * + * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry + * + * @author Luís Cobucci + */ +final class GoogleCloudLoggingFormatter extends JsonFormatter +{ + /** {@inheritdoc} **/ + public function format(array $record): string + { + // Re-key level for GCP logging + $record['severity'] = $record['level_name']; + $record['timestamp'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED); + + // Remove keys that are not used by GCP + unset($record['level'], $record['level_name'], $record['datetime']); + + return parent::format($record); + } +} + diff --git a/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php new file mode 100644 index 000000000..27aea2cac --- /dev/null +++ b/tests/Monolog/Formatter/GoogleCloudLoggingFormatterTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\Test\TestCase; +use function json_decode; + +class GoogleCloudLoggingFormatterTest extends TestCase +{ + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::format + */ + public function formatProvidesRfc3339Timestamps(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("datetime", $formatted_decoded); + $this->assertArrayHasKey("timestamp", $formatted_decoded); + $this->assertSame($record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED), $formatted_decoded["timestamp"]); + } + + /** + * @test + * + * @covers \Monolog\Formatter\JsonFormatter + * @covers \Monolog\Formatter\GoogleCloudLoggingFormatter::format + */ + public function formatIntroducesLogSeverity(): void + { + $formatter = new GoogleCloudLoggingFormatter(); + $record = $this->getRecord(); + + $formatted_decoded = json_decode($formatter->format($record), true); + $this->assertArrayNotHasKey("level", $formatted_decoded); + $this->assertArrayNotHasKey("level_name", $formatted_decoded); + $this->assertArrayHasKey("severity", $formatted_decoded); + $this->assertSame($record['level_name'], $formatted_decoded["severity"]); + } +} From 3734f190f8f643aaed3bae99a722bae5212ccb2a Mon Sep 17 00:00:00 2001 From: Mikhail Popov Date: Fri, 22 Jul 2022 14:08:34 +0300 Subject: [PATCH 467/498] Add the ability to set or redefine attributes for messages in Rabbit. (#1724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of content_type, content_encoding, message_id, user_id, app_id, delivery_mode, priority, timestamp, expiration, type or reply_to, headers. Co-authored-by: Попов Михаил --- src/Monolog/Handler/AmqpHandler.php | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index e30d784dd..c0b4504ea 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -27,6 +27,29 @@ class AmqpHandler extends AbstractProcessingHandler * @var AMQPExchange|AMQPChannel $exchange */ protected $exchange; + /** @var array */ + private $extraAttributes = []; + + /** + * @return array + */ + public function getExtraAttributes(): array + { + return $this->extraAttributes; + } + + /** + * @param array $extraAttributes One of content_type, content_encoding, + * message_id, user_id, app_id, delivery_mode, + * priority, timestamp, expiration, type + * or reply_to, headers. + * @return AmqpHandler + */ + public function setExtraAttributes(array $extraAttributes): self + { + $this->extraAttributes = $extraAttributes; + return $this; + } /** * @var string @@ -60,14 +83,18 @@ protected function write(array $record): void $routingKey = $this->getRoutingKey($record); if ($this->exchange instanceof AMQPExchange) { + $attributes = [ + 'delivery_mode' => 2, + 'content_type' => 'application/json', + ]; + if ($this->extraAttributes) { + $attributes = array_merge($attributes, $this->extraAttributes); + } $this->exchange->publish( $data, $routingKey, 0, - [ - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ] + $attributes ); } else { $this->exchange->basic_publish( From 11be0a4b30ab3a84c1687e2c1fd4eedf9e800c55 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:15:11 +0200 Subject: [PATCH 468/498] Fix phpstan errors --- src/Monolog/Handler/AmqpHandler.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index c0b4504ea..c4997482e 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -27,11 +27,11 @@ class AmqpHandler extends AbstractProcessingHandler * @var AMQPExchange|AMQPChannel $exchange */ protected $exchange; - /** @var array */ + /** @var array */ private $extraAttributes = []; /** - * @return array + * @return array */ public function getExtraAttributes(): array { @@ -39,10 +39,12 @@ public function getExtraAttributes(): array } /** - * @param array $extraAttributes One of content_type, content_encoding, - * message_id, user_id, app_id, delivery_mode, - * priority, timestamp, expiration, type - * or reply_to, headers. + * Configure extra attributes to pass to the AMQPExchange (if you are using the amqp extension) + * + * @param array $extraAttributes One of content_type, content_encoding, + * message_id, user_id, app_id, delivery_mode, + * priority, timestamp, expiration, type + * or reply_to, headers. * @return AmqpHandler */ public function setExtraAttributes(array $extraAttributes): self From f958fdac0f3ec78af4c5c1cdebd2e5e219a563ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sat, 9 Jul 2022 11:29:07 +0200 Subject: [PATCH 469/498] allow Predis 2.0, closes #1732 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 52cb35f67..d01b8e18a 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5.14", - "predis/predis": "^1.1", + "predis/predis": "^1.1 || ^2.0", "rollbar/rollbar": "^1.3 || ^2 || ^3", "ruflin/elastica": "^7", "swiftmailer/swiftmailer": "^5.3|^6.0", From af8efac0d58e524aead247ce64445a66e6d7c553 Mon Sep 17 00:00:00 2001 From: Max Ageev Date: Thu, 9 Jun 2022 14:23:32 +0300 Subject: [PATCH 470/498] Check if errorMessage contain error "File exists" Fixes #1678, closes #1685 When we try to create directory we got error and find out that error is to the fact that directory already was created for us. If that the case we should not throw exception as it's fine now... If file was deleted after that it's not problem of this funtion. --- src/Monolog/Handler/StreamHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index e6c795699..3550c8c17 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -212,7 +212,7 @@ private function createDir(string $url): void set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status && !is_dir($dir)) { + if (false === $status && !is_dir($dir) && strpos($this->errorMessage, 'File exists') !== false) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } From 6cc788bdec2550f596736c58742de4c447cc64d1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:25:12 +0200 Subject: [PATCH 471/498] Fix build error with lowest deps on php7.4 --- .github/workflows/continuous-integration.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ff2cc1a63..ace0a6429 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -152,6 +152,10 @@ jobs: - name: "Change dependencies" run: "composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^${{ matrix.es-version }}" + - name: "Allow composer plugin to run" + if: "matrix.php-version == '7.4' && matrix.dependencies == 'lowest'" + run: "composer config allow-plugins.ocramius/package-versions true" + - name: "Update dependencies with composer" uses: "ramsey/composer-install@v1" with: @@ -229,6 +233,10 @@ jobs: composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar composer require --no-update --no-interaction --dev elasticsearch/elasticsearch:^8 + - name: "Allow composer plugin to run" + if: "matrix.php-version == '7.4' && matrix.dependencies == 'lowest'" + run: "composer config allow-plugins.ocramius/package-versions true" + - name: "Update dependencies with composer" uses: "ramsey/composer-install@v1" with: From 475bc874091fc1e5ab579d895c27efcd1ddc20a4 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 13:33:21 +0200 Subject: [PATCH 472/498] Fix issues --- src/Monolog/Handler/RedisHandler.php | 4 ++-- src/Monolog/Handler/RedisPubSubHandler.php | 4 ++-- src/Monolog/Handler/StreamHandler.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 938eee6b2..91d16eaf6 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -30,7 +30,7 @@ */ class RedisHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $redisKey; @@ -38,7 +38,7 @@ class RedisHandler extends AbstractProcessingHandler protected $capSize; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The key name to push records to * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index f9fede8ee..7789309c1 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -28,13 +28,13 @@ */ class RedisPubSubHandler extends AbstractProcessingHandler { - /** @var \Predis\Client|\Redis */ + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; /** @var string */ private $channelKey; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The channel key to publish records to */ public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 3550c8c17..651835122 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -212,7 +212,7 @@ private function createDir(string $url): void set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status && !is_dir($dir) && strpos($this->errorMessage, 'File exists') !== false) { + if (false === $status && !is_dir($dir) && strpos((string) $this->errorMessage, 'File exists') === false) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } From ffc2bc2e23f174a7356b74f51e5e57aff713202e Mon Sep 17 00:00:00 2001 From: systemsolutionweb <88460896+systemsolutionweb@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:54:02 -0500 Subject: [PATCH 473/498] Update .gitattributes, closes #1688 --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 52e9cb437..6da920e30 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ /doc export-ignore /tests export-ignore /.* export-ignore -/phpstan.neon.dist export-ignore +/phpstan* export-ignore /phpunit.xml.dist export-ignore /_config.yml export-ignore /UPGRADE.md From 83db4b3f8124f0d1ff0d45872728359022c4c4b6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:18:01 +0200 Subject: [PATCH 474/498] Handle depth to avoid cases where an exception has many too many previous exceptions, fixes #1726 --- src/Monolog/Formatter/LineFormatter.php | 6 ++++++ src/Monolog/Formatter/NormalizerFormatter.php | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index d0b4de94a..69dfee5ce 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -153,6 +153,12 @@ protected function normalizeException(\Throwable $e, int $depth = 0): string if ($previous = $e->getPrevious()) { do { + $depth++; + if ($depth > $this->maxNormalizeDepth) { + $str .= '\n[previous exception] Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; + break; + } + $str .= "\n[previous exception] " . $this->formatException($previous); } while ($previous = $previous->getPrevious()); } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 0c6227150..5441bc0aa 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -198,6 +198,10 @@ protected function normalize($data, int $depth = 0) */ protected function normalizeException(Throwable $e, int $depth = 0) { + if ($depth > $this->maxNormalizeDepth) { + return ['Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization']; + } + if ($e instanceof \JsonSerializable) { return (array) $e->jsonSerialize(); } From 27dc1b2ef734cf4077321886dcbb6d9efbf6b81b Mon Sep 17 00:00:00 2001 From: erikn69 Date: Fri, 22 Jul 2022 07:23:53 -0500 Subject: [PATCH 475/498] Fix utf8_encode deprecation (#1722) --- src/Monolog/Handler/ChromePHPHandler.php | 6 +++--- src/Monolog/Utils.php | 2 +- tests/Monolog/Handler/ChromePHPHandlerTest.php | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index d1a98b8fe..234ecf614 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -149,7 +149,7 @@ protected function send(): void } $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); - $data = base64_encode(utf8_encode($json)); + $data = base64_encode($json); if (strlen($data) > 3 * 1024) { self::$overflowed = true; @@ -163,8 +163,8 @@ protected function send(): void 'extra' => [], ]; self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); - $json = Utils::jsonEncode(self::$json, null, true); - $data = base64_encode(utf8_encode($json)); + $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); + $data = base64_encode($json); } if (trim($data) !== '') { diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 726c98191..360c42199 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -211,7 +211,7 @@ private static function detectAndCleanUtf8(&$data): void $data = preg_replace_callback( '/[\x80-\xFF]+/', function ($m) { - return utf8_encode($m[0]); + return function_exists('mb_convert_encoding') ? mb_convert_encoding($m[0], 'UTF-8', 'ISO-8859-1') : utf8_encode($m[0]); }, $data ); diff --git a/tests/Monolog/Handler/ChromePHPHandlerTest.php b/tests/Monolog/Handler/ChromePHPHandlerTest.php index 1ee581959..cf13dd894 100644 --- a/tests/Monolog/Handler/ChromePHPHandlerTest.php +++ b/tests/Monolog/Handler/ChromePHPHandlerTest.php @@ -38,7 +38,7 @@ public function testHeaders($agent) $handler->handle($this->getRecord(Logger::WARNING)); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -46,7 +46,7 @@ public function testHeaders($agent) 'test', ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler->getHeaders()); @@ -72,7 +72,7 @@ public function testHeadersOverflow() $handler->handle($this->getRecord(Logger::WARNING, str_repeat('b', 2 * 1024))); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -96,7 +96,7 @@ public function testHeadersOverflow() ], ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler->getHeaders()); @@ -115,7 +115,7 @@ public function testConcurrentHandlers() $handler2->handle($this->getRecord(Logger::WARNING)); $expected = [ - 'X-ChromeLogger-Data' => base64_encode(utf8_encode(json_encode([ + 'X-ChromeLogger-Data' => base64_encode(json_encode([ 'version' => '4.0', 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [ @@ -125,7 +125,7 @@ public function testConcurrentHandlers() 'test', ], 'request_uri' => '', - ]))), + ])), ]; $this->assertEquals($expected, $handler2->getHeaders()); From c1c73b07debd6d2f72fe225d9cf9642a88e93dfe Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:25:43 +0200 Subject: [PATCH 476/498] Update issue templates --- .github/ISSUE_TEMPLATE/Bug_Report.md | 2 +- .github/ISSUE_TEMPLATE/Question.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md index 71ce0c2b7..df38260f1 100644 --- a/.github/ISSUE_TEMPLATE/Bug_Report.md +++ b/.github/ISSUE_TEMPLATE/Bug_Report.md @@ -4,6 +4,6 @@ about: Create a bug report labels: Bug --- -Monolog version 1|2 +Monolog version 1|2|3? Write your bug report here. diff --git a/.github/ISSUE_TEMPLATE/Question.md b/.github/ISSUE_TEMPLATE/Question.md index b2810fa36..f62632c48 100644 --- a/.github/ISSUE_TEMPLATE/Question.md +++ b/.github/ISSUE_TEMPLATE/Question.md @@ -4,6 +4,6 @@ about: Ask a question regarding software usage labels: Support --- -Monolog version 1|2 +Monolog version 1|2|3? Write your question here. From ad09e76f97d165a9067af8daf8fd6f4d07d0c133 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:26:06 +0200 Subject: [PATCH 477/498] Add php 8.2 build --- .github/workflows/continuous-integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ace0a6429..e50e004d7 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,6 +20,7 @@ jobs: - "7.4" - "8.0" - "8.1" + - "8.2" dependencies: [highest] From b3ac20ef322e9bc8aa1d13c9943eca8f278ee9f6 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:46:07 +0200 Subject: [PATCH 478/498] Matrix update --- .github/workflows/continuous-integration.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index e50e004d7..6a139279b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -6,7 +6,7 @@ on: jobs: tests: - name: "CI" + name: "CI (PHP ${{ matrix.php-version }}, ${{ matrix.dependencies }} deps)" runs-on: "${{ matrix.operating-system }}" @@ -24,6 +24,8 @@ jobs: dependencies: [highest] + composer-options: "" + operating-system: - "ubuntu-latest" @@ -34,6 +36,10 @@ jobs: - php-version: "8.1" dependencies: lowest operating-system: ubuntu-latest + - php-version: "8.2" + dependencies: highest + operating-system: ubuntu-latest + composer-options: "--ignore-platform-req=php+" steps: - name: "Checkout" @@ -69,9 +75,10 @@ jobs: composer config --no-plugins allow-plugins.ocramius/package-versions true - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" + composer-options: "${{ matrix.composer-options }}" - name: "Run tests" run: "composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose" @@ -158,7 +165,7 @@ jobs: run: "composer config allow-plugins.ocramius/package-versions true" - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" @@ -239,7 +246,7 @@ jobs: run: "composer config allow-plugins.ocramius/package-versions true" - name: "Update dependencies with composer" - uses: "ramsey/composer-install@v1" + uses: "ramsey/composer-install@v2" with: dependency-versions: "${{ matrix.dependencies }}" From 3a1ea88ee0c90dd809d75dd7dcef1d0f59a92216 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:47:49 +0200 Subject: [PATCH 479/498] Fix matrix --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 6a139279b..5fb4c9e0b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -24,7 +24,7 @@ jobs: dependencies: [highest] - composer-options: "" + composer-options: [""] operating-system: - "ubuntu-latest" From 611ff01fa6f9d36c41fb6d0f4c8b0de820a3c2eb Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 14:48:24 +0200 Subject: [PATCH 480/498] Skip php8.2 default build --- .github/workflows/continuous-integration.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 5fb4c9e0b..129d36d83 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,7 +20,6 @@ jobs: - "7.4" - "8.0" - "8.1" - - "8.2" dependencies: [highest] From 9c1fb56f6aa983b959517e57955516bdba771d5d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:00:00 +0200 Subject: [PATCH 481/498] Deprecate CubeHandler and PHPConsoleHandler which are targetting abandoned projects, fixes #1734 --- composer.json | 2 -- src/Monolog/Handler/CubeHandler.php | 3 ++- src/Monolog/Handler/PHPConsoleHandler.php | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index d01b8e18a..ab775ad63 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,6 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "php-console/php-console": "^3.1.3", "phpspec/prophecy": "^1.15", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^8.5.14", @@ -48,7 +47,6 @@ "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "php-console/php-console": "Allow sending log messages to Google Chrome", "ext-mbstring": "Allow to work properly with unicode symbols", "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index fc8f58f1a..3535a4fcd 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -17,8 +17,9 @@ /** * Logs to Cube. * - * @link http://square.github.com/cube/ + * @link https://github.com/square/cube/wiki * @author Wan Chen + * @deprecated Since 2.8.0 and 3.2.0, Cube appears abandoned and thus we will drop this handler in Monolog 4 */ class CubeHandler extends AbstractProcessingHandler { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 6e209b190..23a1d1178 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -25,7 +25,7 @@ * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely * * Usage: - * 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef + * 1. Install Google Chrome extension [now dead and removed from the chrome store] * 2. See overview https://github.com/barbushin/php-console#overview * 3. Install PHP Console library https://github.com/barbushin/php-console#installation * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png) @@ -39,6 +39,7 @@ * @author Sergey Barbushin https://www.linkedin.com/in/barbushin * * @phpstan-import-type Record from \Monolog\Logger + * @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4 */ class PHPConsoleHandler extends AbstractProcessingHandler { From 6fdeea463cc61a112c0fa969ceec6f576d181b07 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:07:44 +0200 Subject: [PATCH 482/498] Fix build --- phpstan.neon.dist | 3 +++ tests/Monolog/Formatter/NormalizerFormatterTest.php | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4a368cd2b..d368b288e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,9 @@ parameters: - src/ # - tests/ + excludePaths: + - 'src/Monolog/Handler/PHPConsoleHandler.php' + ignoreErrors: - '#zend_monitor_|ZEND_MONITOR_#' - '#MongoDB\\(Client|Collection)#' diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 00cc1fb90..181065eda 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -369,8 +369,9 @@ public function testExceptionTraceWithArgs() $record = ['context' => ['exception' => $e]]; $result = $formatter->format($record); + $offset = PHP_VERSION_ID >= 80200 ? 12 : 10; $this->assertSame( - __FILE__.':'.(__LINE__-9), + __FILE__.':'.(__LINE__ - $offset), $result['context']['exception']['trace'][0] ); } From 34635fdcf5c1ef6da113c84aee5401d01aa0a13f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:08:12 +0200 Subject: [PATCH 483/498] Add docs --- tests/Monolog/Formatter/NormalizerFormatterTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 181065eda..162f34b31 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -369,7 +369,8 @@ public function testExceptionTraceWithArgs() $record = ['context' => ['exception' => $e]]; $result = $formatter->format($record); - $offset = PHP_VERSION_ID >= 80200 ? 12 : 10; + // See https://github.com/php/php-src/issues/8810 fixed in PHP 8.2 + $offset = PHP_VERSION_ID >= 80200 ? 13 : 11; $this->assertSame( __FILE__.':'.(__LINE__ - $offset), $result['context']['exception']['trace'][0] From 1e6a4e106c0aa8c52cfb219017834d48f3f012a0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:10:54 +0200 Subject: [PATCH 484/498] Remove deprecated handlers from docs --- doc/02-handlers-formatters-processors.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 72c5da013..d16e674a7 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -51,7 +51,6 @@ [php-amqplib](https://github.com/php-amqplib/php-amqplib) library. - [_GelfHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/GelfHandler.php): Logs records to a [Graylog2](http://www.graylog2.org) server. Requires package [graylog2/gelf-php](https://github.com/bzikarsky/gelf-php). -- [_CubeHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/CubeHandler.php): Logs records to a [Cube](http://square.github.com/cube/) server. - [_ZendMonitorHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/ZendMonitorHandler.php): Logs records to the Zend Monitor present in Zend Server. - [_NewRelicHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/NewRelicHandler.php): Logs records to a [NewRelic](http://newrelic.com/) application. - [_LogglyHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/LogglyHandler.php): Logs records to a [Loggly](http://www.loggly.com/) account. @@ -72,8 +71,6 @@ inline `console` messages within Chrome. - [_BrowserConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/BrowserConsoleHandler.php): Handler to send logs to browser's Javascript `console` with no browser extension required. Most browsers supporting `console` API are supported. -- [_PHPConsoleHandler_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/PHPConsoleHandler.php): Handler for [PHP Console](https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef), providing - inline `console` and notification popup messages within Chrome. ### Log to databases From 284482a726da916e2562425ac5223826db924dd0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:12:01 +0200 Subject: [PATCH 485/498] More test fixes --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 129d36d83..cf50545ab 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -87,7 +87,7 @@ jobs: run: | composer remove --no-update --dev graylog2/gelf-php ruflin/elastica elasticsearch/elasticsearch rollbar/rollbar composer require --no-update psr/log:^3 - composer update -W + composer update ${{ matrix.composer-options }} composer exec phpunit -- --exclude-group Elasticsearch,Elastica --verbose tests-es-7: From cf0f4b38148bc5ee19e83585b5dea135cbbfe3ca Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 15:27:46 +0200 Subject: [PATCH 486/498] Handle __toString to serialize objects which are not json-serializable in JsonFormatter, fixes #1733 --- src/Monolog/Formatter/JsonFormatter.php | 23 ++++++-- tests/Monolog/Formatter/JsonFormatterTest.php | 56 +++++++++++++++++++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 42735a6b4..b737d82e3 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -178,12 +178,25 @@ protected function normalize($data, int $depth = 0) return $normalized; } - if ($data instanceof \DateTimeInterface) { - return $this->formatDate($data); - } + if (is_object($data)) { + if ($data instanceof \DateTimeInterface) { + return $this->formatDate($data); + } + + if ($data instanceof Throwable) { + return $this->normalizeException($data, $depth); + } + + // if the object has specific json serializability we want to make sure we skip the __toString treatment below + if ($data instanceof \JsonSerializable) { + return $data; + } + + if (method_exists($data, '__toString')) { + return $data->__toString(); + } - if ($data instanceof Throwable) { - return $this->normalizeException($data, $depth); + return $data; } if (is_resource($data)) { diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index 17a3ba823..147021029 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -11,6 +11,7 @@ namespace Monolog\Formatter; +use JsonSerializable; use Monolog\Logger; use Monolog\Test\TestCase; @@ -314,4 +315,59 @@ public function testEmptyContextAndExtraFieldsCanBeIgnored() $record ); } + + public function testFormatObjects() + { + $formatter = new JsonFormatter(); + + $record = $formatter->format(array( + 'level' => 100, + 'level_name' => 'DEBUG', + 'channel' => 'test', + 'message' => 'Testing', + 'context' => array( + 'public' => new TestJsonNormPublic, + 'private' => new TestJsonNormPrivate, + 'withToStringAndJson' => new TestJsonNormWithToStringAndJson, + 'withToString' => new TestJsonNormWithToString, + ), + 'extra' => array(), + )); + + $this->assertSame( + '{"level":100,"level_name":"DEBUG","channel":"test","message":"Testing","context":{"public":{"foo":"fooValue"},"private":{},"withToStringAndJson":["json serialized"],"withToString":"stringified"},"extra":{}}'."\n", + $record + ); + } +} + +class TestJsonNormPublic +{ + public $foo = 'fooValue'; +} + +class TestJsonNormPrivate +{ + private $foo = 'fooValue'; +} + +class TestJsonNormWithToStringAndJson implements JsonSerializable +{ + public function jsonSerialize() + { + return ['json serialized']; + } + + public function __toString() + { + return 'SHOULD NOT SHOW UP'; + } +} + +class TestJsonNormWithToString +{ + public function __toString() + { + return 'stringified'; + } } From 320909a1d1c68f134603469f866a6991c753639f Mon Sep 17 00:00:00 2001 From: Pavel Bychko Date: Sun, 26 Jun 2022 12:34:03 +0300 Subject: [PATCH 487/498] Fix replaceNewlines method to avoid replacing escaped backslashes, closes #1721, fixes #1720 --- src/Monolog/Formatter/LineFormatter.php | 6 +++++- tests/Monolog/Formatter/LineFormatterTest.php | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index 69dfee5ce..b31b2971a 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -186,7 +186,11 @@ protected function replaceNewlines(string $str): string { if ($this->allowInlineLineBreaks) { if (0 === strpos($str, '{')) { - return str_replace(array('\r', '\n'), array("\r", "\n"), $str); + $str = preg_replace('/(?assertRegexp('{^\['.date('Y-m-d').'] core\.CRITICAL: foobar \{"exception":"\[object] \(RuntimeException\(code: 0\): Foo at '.preg_quote(substr($path, 1, -1)).':'.(__LINE__ - 8).'\)\n\[stacktrace]\n#0}', $message); } + public function testInlineLineBreaksRespectsEscapedBackslashes() + { + $formatter = new LineFormatter(null, 'Y-m-d'); + $formatter->allowInlineLineBreaks(); + + self::assertSame('{"test":"foo'."\n".'bar\\\\name-with-n"}', $formatter->stringify(["test" => "foo\nbar\\name-with-n"])); + } + public function testDefFormatWithExceptionAndStacktraceParserFull() { $formatter = new LineFormatter(null, 'Y-m-d'); From a7e5beda577523edfc04ad12433889daccc5c4e9 Mon Sep 17 00:00:00 2001 From: picass0 Date: Fri, 22 Jul 2022 18:17:53 +0400 Subject: [PATCH 488/498] finishing Syslog formatter (#1689) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Syslog formatter * feat: Syslog formatter, app name * update syslogFormatter * Remove legacy syntax Co-authored-by: Dalibor Karlović Co-authored-by: Renat Gabdullin --- src/Monolog/Formatter/SyslogFormatter.php | 67 +++++++++++ src/Monolog/Handler/AbstractSyslogHandler.php | 17 --- .../{ => Syslog}/SyslogUdp/UdpSocket.php | 2 +- src/Monolog/Handler/Syslog/SyslogUtils.php | 22 ++++ src/Monolog/Handler/SyslogHandler.php | 3 +- src/Monolog/Handler/SyslogUdpHandler.php | 5 +- .../Monolog/Formatter/SyslogFormatterTest.php | 113 ++++++++++++++++++ .../Monolog/Handler/SyslogUdpHandlerTest.php | 6 +- tests/Monolog/Handler/UdpSocketTest.php | 6 +- 9 files changed, 214 insertions(+), 27 deletions(-) create mode 100644 src/Monolog/Formatter/SyslogFormatter.php rename src/Monolog/Handler/{ => Syslog}/SyslogUdp/UdpSocket.php (97%) create mode 100644 src/Monolog/Handler/Syslog/SyslogUtils.php create mode 100644 tests/Monolog/Formatter/SyslogFormatterTest.php diff --git a/src/Monolog/Formatter/SyslogFormatter.php b/src/Monolog/Formatter/SyslogFormatter.php new file mode 100644 index 000000000..0d69fabe2 --- /dev/null +++ b/src/Monolog/Formatter/SyslogFormatter.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use Monolog\Handler\Syslog\SyslogUtils; +use Monolog\Level; +use Monolog\LogRecord; + +/** + * Serializes a log message according to RFC 5424 + * + * @author Dalibor Karlović + * @author Renat Gabdullin + */ +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 + */ + 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) + SyslogUtils::toSyslogPriority($level); + } +} diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 49e7da5b4..5f3de1fbd 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -22,23 +22,6 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler { protected int $facility; - /** - * Translates Monolog log levels to syslog log priorities. - */ - protected function toSyslogPriority(Level $level): int - { - return match ($level) { - Level::Debug => \LOG_DEBUG, - Level::Info => \LOG_INFO, - Level::Notice => \LOG_NOTICE, - Level::Warning => \LOG_WARNING, - Level::Error => \LOG_ERR, - Level::Critical => \LOG_CRIT, - Level::Alert => \LOG_ALERT, - Level::Emergency => \LOG_EMERG, - }; - } - /** * List of valid log facility names. * @var array diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php similarity index 97% rename from src/Monolog/Handler/SyslogUdp/UdpSocket.php rename to src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php index 6a4833450..a599753d4 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler\SyslogUdp; +namespace Monolog\Handler\Syslog\SyslogUdp; use Monolog\Utils; use Socket; diff --git a/src/Monolog/Handler/Syslog/SyslogUtils.php b/src/Monolog/Handler/Syslog/SyslogUtils.php new file mode 100644 index 000000000..61981ba43 --- /dev/null +++ b/src/Monolog/Handler/Syslog/SyslogUtils.php @@ -0,0 +1,22 @@ + \LOG_DEBUG, + Level::Info => \LOG_INFO, + Level::Notice => \LOG_NOTICE, + Level::Warning => \LOG_WARNING, + Level::Error => \LOG_ERR, + Level::Critical => \LOG_CRIT, + Level::Alert => \LOG_ALERT, + Level::Emergency => \LOG_EMERG, + }; + } +} diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 0816a0119..63779c4d0 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Handler\Syslog\SyslogUtils; use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; @@ -61,6 +62,6 @@ protected function write(LogRecord $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(SyslogUtils::toSyslogPriority($record->level), (string) $record->formatted); } } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 3d30fbd42..209b3b408 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -13,7 +13,8 @@ use DateTimeInterface; use Monolog\Level; -use Monolog\Handler\SyslogUdp\UdpSocket; +use Monolog\Handler\Syslog\SyslogUdp\UdpSocket; +use Monolog\Handler\Syslog\SyslogUtils; use Monolog\Utils; use Monolog\LogRecord; @@ -70,7 +71,7 @@ protected function write(LogRecord $record): void { $lines = $this->splitMessageIntoLines($record->formatted); - $header = $this->makeCommonSyslogHeader($this->toSyslogPriority($record->level), $record->datetime); + $header = $this->makeCommonSyslogHeader(SyslogUtils::toSyslogPriority($record->level), $record->datetime); foreach ($lines as $line) { $this->socket->write($line, $header); diff --git a/tests/Monolog/Formatter/SyslogFormatterTest.php b/tests/Monolog/Formatter/SyslogFormatterTest.php new file mode 100644 index 000000000..fe8933ea2 --- /dev/null +++ b/tests/Monolog/Formatter/SyslogFormatterTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeImmutable; +use Monolog\Level; +use Monolog\LogRecord; +use PHPUnit\Framework\TestCase; + +class SyslogFormatterTest extends TestCase +{ + /** + * @dataProvider formatDataProvider + * + * @param string $expected + * @param DateTimeImmutable $dateTime + * @param string $channel + * @param Level $level + * @param string $message + * @param string|null $appName + * @param mixed[] $context + * @param mixed[] $extra + * @return void + */ + public function testFormat( + string $expected, + DateTimeImmutable $dateTime, + string $channel, + Level $level, + string $message, + string $appName = null, + array $context = [], + array $extra = [] + ): void { + if ($appName !== null) { + $formatter = new SyslogFormatter($appName); + } else { + $formatter = new SyslogFormatter(); + } + + $record = new LogRecord( + datetime: $dateTime, + channel: $channel, + level: $level, + message: $message, + context: $context, + extra: $extra + ); + + $message = $formatter->format($record); + + $this->assertEquals($expected, $message); + } + + /** + * @return mixed[] + */ + public function formatDataProvider(): array + { + return [ + 'error' => [ + 'expected' => "<11>1 1970-01-01T00:00:00.000000+00:00 " . gethostname() . " - " . getmypid() ." meh - ERROR: log \n", + 'dateTime' => new DateTimeImmutable("@0"), + 'channel' => 'meh', + 'level' => Level::Error, + 'message' => 'log', + ], + 'info' => [ + 'expected' => "<11>1 1970-01-01T00:00:00.000000+00:00 " . gethostname() . " - " . getmypid() ." meh - ERROR: log \n", + 'dateTime' => new DateTimeImmutable("@0"), + 'channel' => 'meh', + 'level' => Level::Error, + 'message' => 'log', + ], + 'with app name' => [ + 'expected' => "<11>1 1970-01-01T00:00:00.000000+00:00 " . gethostname() . " my-app " . getmypid() ." meh - ERROR: log \n", + 'dateTime' => new DateTimeImmutable("@0"), + 'channel' => 'meh', + 'level' => Level::Error, + 'message' => 'log', + 'appName' => 'my-app', + ], + 'with context' => [ + 'expected' => "<11>1 1970-01-01T00:00:00.000000+00:00 " . gethostname() . " - " . getmypid() ." meh - ERROR: log {\"additional-context\":\"test\"} \n", + 'dateTime' => new DateTimeImmutable("@0"), + 'channel' => 'meh', + 'level' => Level::Error, + 'message' => 'log', + 'appName' => null, + 'context' => ['additional-context' => 'test'], + ], + 'with extra' => [ + 'expected' => "<11>1 1970-01-01T00:00:00.000000+00:00 " . gethostname() . " - " . getmypid() ." meh - ERROR: log {\"userId\":1}\n", + 'dateTime' => new DateTimeImmutable("@0"), + 'channel' => 'meh', + 'level' => Level::Error, + 'message' => 'log', + 'appName' => null, + 'context' => [], + 'extra' => ['userId' => 1], + ], + ]; + } +} diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index f27d5ad57..786b758c7 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -35,7 +35,7 @@ public function testWeSplitIntoLines() $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); $time = '2014-01-07T12:34:56+00:00'; - $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); @@ -56,7 +56,7 @@ public function testSplitWorksOnEmptyMsg() $handler = new SyslogUdpHandler("127.0.0.1", 514, "authpriv"); $handler->setFormatter($this->getIdentityFormatter()); - $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); @@ -81,7 +81,7 @@ public function testRfc() $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); - $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('\Monolog\Handler\Syslog\SyslogUdp\UdpSocket') ->setConstructorArgs(['lol', 999]) ->onlyMethods(['write']) ->getMock(); diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index 584779979..d394361b7 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -12,7 +12,7 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; -use Monolog\Handler\SyslogUdp\UdpSocket; +use Monolog\Handler\Syslog\SyslogUdp\UdpSocket; /** * @requires extension sockets @@ -21,7 +21,7 @@ class UdpSocketTest extends TestCase { public function testWeDoNotTruncateShortMessages() { - $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); @@ -35,7 +35,7 @@ public function testWeDoNotTruncateShortMessages() public function testLongMessagesAreTruncated() { - $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); From ffd505543cf54c32b6bb8a133aeb773d4a740547 Mon Sep 17 00:00:00 2001 From: Lusso Luca Date: Fri, 22 Jul 2022 16:46:43 +0200 Subject: [PATCH 489/498] Add RFC 5424 level (7 to 0) support to Logger::log and Logger::addRecord, fixes #1686 (#1723) Co-authored-by: Jordi Boggiano --- src/Monolog/Logger.php | 28 ++++++++++++++++++++++++++-- tests/Monolog/LoggerTest.php | 31 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 099185205..1ab75b9e0 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -111,6 +111,22 @@ class Logger implements LoggerInterface, ResettableInterface self::EMERGENCY => 'EMERGENCY', ]; + /** + * Mapping between levels numbers defined in RFC 5424 and Monolog ones + * + * @phpstan-var array $rfc_5424_levels + */ + private const RFC_5424_LEVELS = [ + 7 => self::DEBUG, + 6 => self::INFO, + 5 => self::NOTICE, + 4 => self::WARNING, + 3 => self::ERROR, + 2 => self::CRITICAL, + 1 => self::ALERT, + 0 => self::EMERGENCY, + ]; + /** * @var string */ @@ -301,7 +317,7 @@ public function useLoggingLoopDetection(bool $detectCycles): self /** * Adds a log record. * - * @param int $level The logging level + * @param int $level The logging level (a Monolog or RFC 5424 level) * @param string $message The log message * @param mixed[] $context The log context * @param DateTimeImmutable $datetime Optional log date to log into the past or future @@ -311,6 +327,10 @@ public function useLoggingLoopDetection(bool $detectCycles): self */ public function addRecord(int $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool { + if (isset(self::RFC_5424_LEVELS[$level])) { + $level = self::RFC_5424_LEVELS[$level]; + } + if ($this->detectCycles) { $this->logDepth += 1; } @@ -520,7 +540,7 @@ public function getExceptionHandler(): ?callable * * This method allows for compatibility with common interfaces. * - * @param mixed $level The log level + * @param mixed $level The log level (a Monolog, PSR-3 or RFC 5424 level) * @param string|Stringable $message The log message * @param mixed[] $context The log context * @@ -532,6 +552,10 @@ public function log($level, $message, array $context = []): void throw new \InvalidArgumentException('$level is expected to be a string or int'); } + if (isset(self::RFC_5424_LEVELS[$level])) { + $level = self::RFC_5424_LEVELS[$level]; + } + $level = static::toMonologLevel($level); $this->addRecord($level, (string) $message, $context); diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 0b07a7cf1..fd99df206 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -62,6 +62,37 @@ public function testConvertPSR3ToMonologLevel() $this->assertEquals(Logger::toMonologLevel('emergency'), 600); } + /** + * @covers Monolog\Logger::addRecord + * @covers Monolog\Logger::log + */ + public function testConvertRFC5424ToMonologLevelInAddRecordAndLog() + { + $logger = new Logger('test'); + $handler = new TestHandler; + $logger->pushHandler($handler); + + foreach ([ + 7 => 100, + 6 => 200, + 5 => 250, + 4 => 300, + 3 => 400, + 2 => 500, + 1 => 550, + 0 => 600, + ] as $rfc5424Level => $monologLevel) { + $handler->reset(); + $logger->addRecord($rfc5424Level, 'test'); + $logger->log($rfc5424Level, 'test'); + $records = $handler->getRecords(); + + self::assertCount(2, $records); + self::assertSame($monologLevel, $records[0]['level']); + self::assertSame($monologLevel, $records[1]['level']); + } + } + /** * @covers Monolog\Logger::getLevelName */ From f7dfa00f084db62b1dec3b9ef683be686cfa31d7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 17:04:34 +0200 Subject: [PATCH 490/498] Add Level::toRFC5424Level method and restore BC to Syslog handlers (broken in #1689) --- src/Monolog/Formatter/SyslogFormatter.php | 4 ++-- src/Monolog/Handler/AbstractSyslogHandler.php | 8 +++++++ src/Monolog/Handler/Syslog/SyslogUtils.php | 22 ------------------- src/Monolog/Handler/SyslogHandler.php | 2 +- .../{Syslog => }/SyslogUdp/UdpSocket.php | 2 +- src/Monolog/Handler/SyslogUdpHandler.php | 8 +++---- src/Monolog/Level.php | 22 +++++++++++++++++++ .../Monolog/Handler/SyslogUdpHandlerTest.php | 6 ++--- tests/Monolog/Handler/UdpSocketTest.php | 6 ++--- 9 files changed, 44 insertions(+), 36 deletions(-) delete mode 100644 src/Monolog/Handler/Syslog/SyslogUtils.php rename src/Monolog/Handler/{Syslog => }/SyslogUdp/UdpSocket.php (97%) diff --git a/src/Monolog/Formatter/SyslogFormatter.php b/src/Monolog/Formatter/SyslogFormatter.php index 0d69fabe2..a2fbf70f3 100644 --- a/src/Monolog/Formatter/SyslogFormatter.php +++ b/src/Monolog/Formatter/SyslogFormatter.php @@ -56,12 +56,12 @@ private function formatExtra(LogRecord $record): array $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) + SyslogUtils::toSyslogPriority($level); + return (self::SYSLOG_FACILITY_USER * 8) + $level->toRFC5424Level(); } } diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index 5f3de1fbd..695a1c07f 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -40,6 +40,14 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler 'uucp' => \LOG_UUCP, ]; + /** + * Translates Monolog log levels to syslog log priorities. + */ + protected function toSyslogPriority(Level $level): int + { + return $level->toRFC5424Level(); + } + /** * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant */ diff --git a/src/Monolog/Handler/Syslog/SyslogUtils.php b/src/Monolog/Handler/Syslog/SyslogUtils.php deleted file mode 100644 index 61981ba43..000000000 --- a/src/Monolog/Handler/Syslog/SyslogUtils.php +++ /dev/null @@ -1,22 +0,0 @@ - \LOG_DEBUG, - Level::Info => \LOG_INFO, - Level::Notice => \LOG_NOTICE, - Level::Warning => \LOG_WARNING, - Level::Error => \LOG_ERR, - Level::Critical => \LOG_CRIT, - Level::Alert => \LOG_ALERT, - Level::Emergency => \LOG_EMERG, - }; - } -} diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 63779c4d0..8c24b0a4d 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -62,6 +62,6 @@ protected function write(LogRecord $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(SyslogUtils::toSyslogPriority($record->level), (string) $record->formatted); + syslog($this->toSyslogPriority($record->level), (string) $record->formatted); } } diff --git a/src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php similarity index 97% rename from src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php rename to src/Monolog/Handler/SyslogUdp/UdpSocket.php index a599753d4..6a4833450 100644 --- a/src/Monolog/Handler/Syslog/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler\Syslog\SyslogUdp; +namespace Monolog\Handler\SyslogUdp; use Monolog\Utils; use Socket; diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 209b3b408..2b47b3b1e 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -12,11 +12,11 @@ namespace Monolog\Handler; use DateTimeInterface; -use Monolog\Level; -use Monolog\Handler\Syslog\SyslogUdp\UdpSocket; use Monolog\Handler\Syslog\SyslogUtils; -use Monolog\Utils; +use Monolog\Handler\SyslogUdp\UdpSocket; +use Monolog\Level; use Monolog\LogRecord; +use Monolog\Utils; /** * A Handler for logging to a remote syslogd server. @@ -71,7 +71,7 @@ protected function write(LogRecord $record): void { $lines = $this->splitMessageIntoLines($record->formatted); - $header = $this->makeCommonSyslogHeader(SyslogUtils::toSyslogPriority($record->level), $record->datetime); + $header = $this->makeCommonSyslogHeader($this->toSyslogPriority($record->level), $record->datetime); foreach ($lines as $line) { $this->socket->write($line, $header); diff --git a/src/Monolog/Level.php b/src/Monolog/Level.php index 5caffdcc3..ab04cf4d4 100644 --- a/src/Monolog/Level.php +++ b/src/Monolog/Level.php @@ -23,6 +23,7 @@ * * - 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 @@ -147,6 +148,8 @@ public function getName(): string } /** + * Returns the PSR-3 level matching this instance + * * @phpstan-return \Psr\Log\LogLevel::* */ public function toPsrLogLevel(): string @@ -163,6 +166,25 @@ public function toPsrLogLevel(): string }; } + /** + * 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, diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 786b758c7..f27d5ad57 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -35,7 +35,7 @@ public function testWeSplitIntoLines() $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); $time = '2014-01-07T12:34:56+00:00'; - $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); @@ -56,7 +56,7 @@ public function testSplitWorksOnEmptyMsg() $handler = new SyslogUdpHandler("127.0.0.1", 514, "authpriv"); $handler->setFormatter($this->getIdentityFormatter()); - $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->onlyMethods(['write']) ->setConstructorArgs(['lol']) ->getMock(); @@ -81,7 +81,7 @@ public function testRfc() $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); - $socket = $this->getMockBuilder('\Monolog\Handler\Syslog\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') ->setConstructorArgs(['lol', 999]) ->onlyMethods(['write']) ->getMock(); diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index d394361b7..986a3ddb8 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -11,8 +11,8 @@ namespace Monolog\Handler; +use Monolog\Handler\SyslogUdp\UdpSocket; use Monolog\Test\TestCase; -use Monolog\Handler\Syslog\SyslogUdp\UdpSocket; /** * @requires extension sockets @@ -21,7 +21,7 @@ class UdpSocketTest extends TestCase { public function testWeDoNotTruncateShortMessages() { - $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); @@ -35,7 +35,7 @@ public function testWeDoNotTruncateShortMessages() public function testLongMessagesAreTruncated() { - $socket = $this->getMockBuilder('Monolog\Handler\Syslog\SyslogUdp\UdpSocket') + $socket = $this->getMockBuilder('Monolog\Handler\SyslogUdp\UdpSocket') ->onlyMethods(['send']) ->setConstructorArgs(['lol']) ->getMock(); From 4b4fad947637586e36afef92cf1e4d1746cc1687 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 20:49:07 +0200 Subject: [PATCH 491/498] Fix serialization to include private properties, fixes #1727, fixes phpro/grumphp#1020 --- src/Monolog/Handler/Handler.php | 11 ++++++++++- tests/Monolog/Handler/NullHandlerTest.php | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/Handler.php b/src/Monolog/Handler/Handler.php index afef2fd74..34b4935dd 100644 --- a/src/Monolog/Handler/Handler.php +++ b/src/Monolog/Handler/Handler.php @@ -48,6 +48,15 @@ public function __sleep() { $this->close(); - return array_keys(get_object_vars($this)); + $reflClass = new \ReflectionClass($this); + + $keys = []; + foreach ($reflClass->getProperties() as $reflProp) { + if (!$reflProp->isStatic()) { + $keys[] = $reflProp->getName(); + } + } + + return $keys; } } diff --git a/tests/Monolog/Handler/NullHandlerTest.php b/tests/Monolog/Handler/NullHandlerTest.php index b7e482bac..61666d803 100644 --- a/tests/Monolog/Handler/NullHandlerTest.php +++ b/tests/Monolog/Handler/NullHandlerTest.php @@ -30,4 +30,15 @@ public function testHandleLowerLevelRecord() $handler = new NullHandler(Logger::WARNING); $this->assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); } + + public function testSerializeRestorePrivate() + { + $handler = new NullHandler(Logger::WARNING); + self::assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + self::assertTrue($handler->handle($this->getRecord(Logger::WARNING))); + + $handler = unserialize(serialize($handler)); + self::assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); + self::assertTrue($handler->handle($this->getRecord(Logger::WARNING))); + } } From 5f839e0e63498bd6ef7054a2607cfd376e3e4c3f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 20:50:29 +0200 Subject: [PATCH 492/498] Clean up unneeded use statements, refs #1689 --- src/Monolog/Formatter/SyslogFormatter.php | 1 - src/Monolog/Handler/SyslogHandler.php | 1 - src/Monolog/Handler/SyslogUdpHandler.php | 1 - 3 files changed, 3 deletions(-) diff --git a/src/Monolog/Formatter/SyslogFormatter.php b/src/Monolog/Formatter/SyslogFormatter.php index a2fbf70f3..6ed7e92ef 100644 --- a/src/Monolog/Formatter/SyslogFormatter.php +++ b/src/Monolog/Formatter/SyslogFormatter.php @@ -11,7 +11,6 @@ namespace Monolog\Formatter; -use Monolog\Handler\Syslog\SyslogUtils; use Monolog\Level; use Monolog\LogRecord; diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 8c24b0a4d..0816a0119 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -11,7 +11,6 @@ namespace Monolog\Handler; -use Monolog\Handler\Syslog\SyslogUtils; use Monolog\Level; use Monolog\Utils; use Monolog\LogRecord; diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 2b47b3b1e..abb8be9b2 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -12,7 +12,6 @@ namespace Monolog\Handler; use DateTimeInterface; -use Monolog\Handler\Syslog\SyslogUtils; use Monolog\Handler\SyslogUdp\UdpSocket; use Monolog\Level; use Monolog\LogRecord; From 60d9aab60e6c27a3059c3e490ec0acfef4b5b255 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 22 Jul 2022 20:55:12 +0200 Subject: [PATCH 493/498] Fix tests --- tests/Monolog/Handler/NullHandlerTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Monolog/Handler/NullHandlerTest.php b/tests/Monolog/Handler/NullHandlerTest.php index a5f12b4fa..59434b49c 100644 --- a/tests/Monolog/Handler/NullHandlerTest.php +++ b/tests/Monolog/Handler/NullHandlerTest.php @@ -33,12 +33,12 @@ public function testHandleLowerLevelRecord() public function testSerializeRestorePrivate() { - $handler = new NullHandler(Logger::WARNING); - self::assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); - self::assertTrue($handler->handle($this->getRecord(Logger::WARNING))); + $handler = new NullHandler(Level::Warning); + self::assertFalse($handler->handle($this->getRecord(Level::Debug))); + self::assertTrue($handler->handle($this->getRecord(Level::Warning))); $handler = unserialize(serialize($handler)); - self::assertFalse($handler->handle($this->getRecord(Logger::DEBUG))); - self::assertTrue($handler->handle($this->getRecord(Logger::WARNING))); + self::assertFalse($handler->handle($this->getRecord(Level::Debug))); + self::assertTrue($handler->handle($this->getRecord(Level::Warning))); } } From 720488632c590286b88b80e62aa3d3d551ad4a50 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Jul 2022 13:55:47 +0200 Subject: [PATCH 494/498] Update changelog --- CHANGELOG.md | 14 ++++++++++++++ doc/02-handlers-formatters-processors.md | 1 + 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ae89099a..7f9db2b07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### 2.8.0 (2022-07-24) + + * Deprecated `CubeHandler` and `PHPConsoleHandler` as both projects are abandoned and those should not be used anymore (#1734) + * Added RFC 5424 level (`7` to `0`) support to `Logger::log` and `Logger::addRecord` to increase interoperability (#1723) + * 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) + ### 2.7.0 (2022-06-09) * Added `$datetime` parameter to `Logger::addRecord` as low level API to allow logging into the past or future (#1682) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index d16e674a7..305180ed4 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -156,6 +156,7 @@ - [_MongoDBFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/MongoDBFormatter.php): Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler. - [_LogmaticFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. - [_FluentdFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FluentdFormatter.php): Used to format log records to [Fluentd](https://www.fluentd.org/) logs, only useful with the SocketHandler. +- [_GoogleCloudLoggingFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php): Used to format log records for Google Cloud Logging. It works like a JsonFormatter with some minor tweaks. ## Processors From 305444bc6fb6c89e490f4b34fa6e979584d7fa81 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 24 Jul 2022 14:00:55 +0200 Subject: [PATCH 495/498] Update changelog --- CHANGELOG.md | 16 ++++++++++++++++ doc/02-handlers-formatters-processors.md | 1 + 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30490bb65..fa0acea36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +### 3.2.0 (2022-07-24) + + * 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) diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index 305180ed4..b799006a0 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -157,6 +157,7 @@ - [_LogmaticFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/LogmaticFormatter.php): Used to format log records to [Logmatic](http://logmatic.io/) messages, only useful for the LogmaticHandler. - [_FluentdFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/FluentdFormatter.php): Used to format log records to [Fluentd](https://www.fluentd.org/) logs, only useful with the SocketHandler. - [_GoogleCloudLoggingFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php): Used to format log records for Google Cloud Logging. It works like a JsonFormatter with some minor tweaks. +- [_SyslogFormatter_](https://github.com/Seldaek/monolog/blob/main/src/Monolog/Formatter/SyslogFormatter.php): Used to format log records in RFC 5424 / syslog format. This can be used to output a syslog-style file that can then be consumed by tools like [lnav](https://lnav.org/). ## Processors From 620dca1126eb2384ccbd7c159b6a6ed8ecabbba4 Mon Sep 17 00:00:00 2001 From: pafernandez-oesia <96843912+pafernandez-oesia@users.noreply.github.com> Date: Tue, 2 Aug 2022 13:47:03 +0200 Subject: [PATCH 496/498] Update BrowserConsoleHandler console output method (#1739) Instead of using console.log for all log levels, it uses debug, info, warn and error methods depending on the log level. This makes filtering logs easier in the browser console and highlights error level messages. --- src/Monolog/Handler/BrowserConsoleHandler.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index fa383f1c2..3c985b749 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -14,6 +14,7 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Utils; +use Monolog\Logger; use function count; use function headers_list; @@ -177,7 +178,7 @@ private static function generateScript(): string $extra = static::dump('Extra', $record['extra']); if (empty($context) && empty($extra)) { - $script[] = static::call_array('log', static::handleStyles($record['formatted'])); + $script[] = static::call_array(static::getConsoleMethodForLevel($record['level']), static::handleStyles($record['formatted'])); } else { $script = array_merge( $script, @@ -192,6 +193,20 @@ private static function generateScript(): string return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } + private static function getConsoleMethodForLevel($level) + { + 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[] */ From 132eace138aa8cddcc31a4b7331cbc7effde63ba Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 2 Aug 2022 15:03:47 +0300 Subject: [PATCH 497/498] Fix build --- src/Monolog/Handler/BrowserConsoleHandler.php | 2 +- .../Handler/BrowserConsoleHandlerTest.php | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 3c985b749..95bbfed42 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -193,7 +193,7 @@ private static function generateScript(): string return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } - private static function getConsoleMethodForLevel($level) + private static function getConsoleMethodForLevel(int $level): string { return [ Logger::DEBUG => 'debug', diff --git a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php index 5bda6b00c..cd02c5ea3 100644 --- a/tests/Monolog/Handler/BrowserConsoleHandlerTest.php +++ b/tests/Monolog/Handler/BrowserConsoleHandlerTest.php @@ -41,7 +41,7 @@ public function testStyling() $expected = << Date: Tue, 16 Aug 2022 17:08:23 +0200 Subject: [PATCH 498/498] Fix bug with level in GitProcessor --- src/Monolog/Processor/GitProcessor.php | 2 +- tests/Monolog/Processor/GitProcessorTest.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 4cbd9c84e..5a70ac2e2 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -44,7 +44,7 @@ public function __construct(int|string|Level $level = Level::Debug) public function __invoke(LogRecord $record): LogRecord { // return if the level is not high enough - if ($record->level < $this->level) { + if ($record->level->isLowerThan($this->level)) { return $record; } diff --git a/tests/Monolog/Processor/GitProcessorTest.php b/tests/Monolog/Processor/GitProcessorTest.php index 4b0e1b0cd..a8fc3d007 100644 --- a/tests/Monolog/Processor/GitProcessorTest.php +++ b/tests/Monolog/Processor/GitProcessorTest.php @@ -11,6 +11,7 @@ namespace Monolog\Processor; +use Monolog\Level; use Monolog\Test\TestCase; class GitProcessorTest extends TestCase @@ -26,4 +27,15 @@ public function testProcessor() $this->assertArrayHasKey('git', $record->extra); $this->assertTrue(!is_array($record->extra['git']['branch'])); } + + /** + * @covers Monolog\Processor\GitProcessor::__invoke + */ + public function testProcessorWithLevel() + { + $processor = new GitProcessor(Level::Error); + $record = $processor($this->getRecord()); + + $this->assertArrayNotHasKey('git', $record->extra); + } }