From 207c91699e8e50a4837b92e17e9919a2bf0573db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Par=C3=A9?= Date: Tue, 27 Jun 2017 23:29:27 +0200 Subject: [PATCH 01/32] Custom exception handler (#500) Add custom exception handler to let the user change the default behavior when Monolog raise an exception while logging a record. --- src/Monolog/Logger.php | 65 ++++++++++++++++++++++++++++----- tests/Monolog/LoggerTest.php | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 8 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 49d00af1..8686c8aa 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -133,6 +133,11 @@ class Logger implements LoggerInterface */ protected $microsecondTimestamps = true; + /** + * @var callable + */ + protected $exceptionHandler; + /** * @param string $name The logging channel * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. @@ -329,16 +334,20 @@ class Logger implements LoggerInterface 'extra' => array(), ); - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - - while ($handler = current($this->handlers)) { - if (true === $handler->handle($record)) { - break; + try { + foreach ($this->processors as $processor) { + $record = call_user_func($processor, $record); } - next($this->handlers); + while ($handler = current($this->handlers)) { + if (true === $handler->handle($record)) { + break; + } + + next($this->handlers); + } + } catch (\Exception $ex) { + $this->handleException($ex, $record); } return true; @@ -501,6 +510,46 @@ class Logger implements LoggerInterface return false; } + /** + * Set a custom exception handler + * + * @param callable $callback + * @return $this + */ + public function setExceptionHandler($callback) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given'); + } + $this->exceptionHandler = $callback; + + return $this; + } + + /** + * @return callable + */ + public function getExceptionHandler() + { + return $this->exceptionHandler; + } + + /** + * Delegates exception management to the custom exception handler, + * or throws the exception if no custom handler is set. + * + * @param Exception $ex + * @param array $record + */ + protected function handleException(\Exception $ex, $record) + { + if ($this->exceptionHandler) { + call_user_func($this->exceptionHandler, $ex, $record); + } else { + throw $ex; + } + } + /** * Adds a log record at an arbitrary level. * diff --git a/tests/Monolog/LoggerTest.php b/tests/Monolog/LoggerTest.php index 1ecc34a0..f938ea02 100644 --- a/tests/Monolog/LoggerTest.php +++ b/tests/Monolog/LoggerTest.php @@ -545,4 +545,73 @@ class LoggerTest extends \PHPUnit_Framework_TestCase 'without microseconds' => array(false, PHP_VERSION_ID >= 70100 ? 'assertNotSame' : 'assertSame'), ); } + + /** + * @covers Monolog\Logger::setExceptionHandler + */ + public function testSetExceptionHandler() + { + $logger = new Logger(__METHOD__); + $this->assertNull($logger->getExceptionHandler()); + $callback = function ($ex) { + }; + $logger->setExceptionHandler($callback); + $this->assertEquals($callback, $logger->getExceptionHandler()); + } + + /** + * @covers Monolog\Logger::setExceptionHandler + * @expectedException InvalidArgumentException + */ + public function testBadExceptionHandlerType() + { + $logger = new Logger(__METHOD__); + $logger->setExceptionHandler(false); + } + + /** + * @covers Monolog\Logger::handleException + * @expectedException Exception + */ + public function testDefaultHandleException() + { + $logger = new Logger(__METHOD__); + $handler = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler->expects($this->any()) + ->method('handle') + ->will($this->throwException(new \Exception('Some handler exception'))) + ; + $logger->pushHandler($handler); + $logger->info('test'); + } + + /** + * @covers Monolog\Logger::handleException + * @covers Monolog\Logger::addRecord + */ + public function testCustomHandleException() + { + $logger = new Logger(__METHOD__); + $that = $this; + $logger->setExceptionHandler(function ($e, $record) use ($that) { + $that->assertEquals($e->getMessage(), 'Some handler exception'); + $that->assertTrue(is_array($record)); + $that->assertEquals($record['message'], 'test'); + }); + $handler = $this->getMock('Monolog\Handler\HandlerInterface'); + $handler->expects($this->any()) + ->method('isHandling') + ->will($this->returnValue(true)) + ; + $handler->expects($this->any()) + ->method('handle') + ->will($this->throwException(new \Exception('Some handler exception'))) + ; + $logger->pushHandler($handler); + $logger->info('test'); + } } From 81db432c02406825fa5a0be2b3decb274b0fcd2e Mon Sep 17 00:00:00 2001 From: gmsantos Date: Sun, 10 Sep 2017 00:10:30 -0300 Subject: [PATCH 02/32] Include insightops handler --- doc/02-handlers-formatters-processors.md | 1 + src/Monolog/Handler/InsightOpsHandler.php | 62 ++++++++++++++ .../Monolog/Handler/InsightOpsHandlerTest.php | 80 +++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/Monolog/Handler/InsightOpsHandler.php create mode 100644 tests/Monolog/Handler/InsightOpsHandlerTest.php diff --git a/doc/02-handlers-formatters-processors.md b/doc/02-handlers-formatters-processors.md index bea968ac..af45913a 100644 --- a/doc/02-handlers-formatters-processors.md +++ b/doc/02-handlers-formatters-processors.md @@ -55,6 +55,7 @@ - _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account. - _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. - _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account. +- _InsightOpsHandler_: Logs records to a [InsightOps](https://www.rapid7.com/products/insightops/) account. ### Logging in development diff --git a/src/Monolog/Handler/InsightOpsHandler.php b/src/Monolog/Handler/InsightOpsHandler.php new file mode 100644 index 00000000..a12e3de5 --- /dev/null +++ b/src/Monolog/Handler/InsightOpsHandler.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\Logger; + +/** + * Inspired on LogEntriesHandler. + * + * @author Robert Kaufmann III + * @author Gabriel Machado + */ +class InsightOpsHandler extends SocketHandler +{ + /** + * @var string + */ + protected $logToken; + + /** + * @param string $token Log token supplied by InsightOps + * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'. + * @param bool $useSSL Whether or not SSL encryption should be used + * @param 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, $bubble = true) + { + if ($useSSL && !extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler'); + } + + $endpoint = $useSSL + ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443' + : $region . '.data.logs.insight.rapid7.com:80'; + + parent::__construct($endpoint, $level, $bubble); + $this->logToken = $token; + } + + /** + * {@inheritdoc} + * + * @param array $record + * @return string + */ + protected function generateDataStream($record) + { + return $this->logToken . ' ' . $record['formatted']; + } +} diff --git a/tests/Monolog/Handler/InsightOpsHandlerTest.php b/tests/Monolog/Handler/InsightOpsHandlerTest.php new file mode 100644 index 00000000..97c18b59 --- /dev/null +++ b/tests/Monolog/Handler/InsightOpsHandlerTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + namespace Monolog\Handler; + + use Monolog\TestCase; + use Monolog\Logger; + +/** + * @author Robert Kaufmann III + * @author Gabriel Machado + */ +class InsightOpsHandlerTest extends TestCase +{ + /** + * @var resource + */ + private $resource; + + /** + * @var LogEntriesHandler + */ + private $handler; + + public function testWriteContent() + { + $this->createHandler(); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); + + fseek($this->resource, 0); + $content = fread($this->resource, 1024); + + $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content); + } + + public function testWriteBatchContent() + { + $this->createHandler(); + $this->handler->handleBatch($this->getMultipleRecords()); + + fseek($this->resource, 0); + $content = fread($this->resource, 1024); + + $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content); + } + + private function createHandler() + { + $useSSL = extension_loaded('openssl'); + $args = array('testToken', 'us', $useSSL, Logger::DEBUG, true); + $this->resource = fopen('php://memory', 'a'); + $this->handler = $this->getMock( + '\Monolog\Handler\InsightOpsHandler', + array('fsockopen', 'streamSetTimeout', 'closeSocket'), + $args + ); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->resource)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + } +} From ecdfdc989718b10d7d3b3a80e40bc551f2f56654 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Sun, 22 Oct 2017 19:09:08 +0200 Subject: [PATCH 03/32] Rename Boolean in phpDocs to bool --- src/Monolog/Handler/AbstractHandler.php | 12 ++++++------ src/Monolog/Handler/AbstractSyslogHandler.php | 6 +++--- src/Monolog/Handler/BufferHandler.php | 4 ++-- src/Monolog/Handler/ChromePHPHandler.php | 6 +++--- src/Monolog/Handler/DeduplicationHandler.php | 2 +- src/Monolog/Handler/ElasticSearchHandler.php | 8 ++++---- src/Monolog/Handler/ErrorLogHandler.php | 8 ++++---- src/Monolog/Handler/FilterHandler.php | 4 ++-- .../FingersCrossed/ActivationStrategyInterface.php | 2 +- src/Monolog/Handler/FingersCrossedHandler.php | 4 ++-- src/Monolog/Handler/FirePHPHandler.php | 2 +- src/Monolog/Handler/GroupHandler.php | 4 ++-- src/Monolog/Handler/HandlerInterface.php | 4 ++-- src/Monolog/Handler/IFTTTHandler.php | 8 ++++---- src/Monolog/Handler/MandrillHandler.php | 2 +- src/Monolog/Handler/PsrHandler.php | 2 +- src/Monolog/Handler/PushoverHandler.php | 4 ++-- src/Monolog/Handler/RavenHandler.php | 2 +- src/Monolog/Handler/RotatingFileHandler.php | 4 ++-- src/Monolog/Handler/SocketHandler.php | 6 +++--- src/Monolog/Handler/StreamHandler.php | 4 ++-- src/Monolog/Handler/SyslogHandler.php | 10 +++++----- src/Monolog/Handler/SyslogUdpHandler.php | 12 ++++++------ src/Monolog/Logger.php | 4 ++-- 24 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 758a425c..bf56549d 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -32,8 +32,8 @@ abstract class AbstractHandler implements HandlerInterface protected $processors = array(); /** - * @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 + * @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) { @@ -141,8 +141,8 @@ abstract class AbstractHandler implements HandlerInterface /** * Sets the bubbling behavior. * - * @param Boolean $bubble true means that this handler allows bubbling. - * false means that bubbling is not permitted. + * @param bool $bubble true means that this handler allows bubbling. + * false means that bubbling is not permitted. * @return self */ public function setBubble($bubble) @@ -155,8 +155,8 @@ abstract class AbstractHandler implements HandlerInterface /** * Gets the bubbling behavior. * - * @return Boolean true means that this handler allows bubbling. - * false means that bubbling is not permitted. + * @return bool true means that this handler allows bubbling. + * false means that bubbling is not permitted. */ public function getBubble() { diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index e2b2832d..8c76aca0 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -53,9 +53,9 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler ); /** - * @param mixed $facility - * @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 + * @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 */ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) { diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 72f89535..c15e28a2 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -34,8 +34,8 @@ class BufferHandler extends AbstractHandler * @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 Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded + * @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) { diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 785cb0c9..ea8ae7fb 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -45,7 +45,7 @@ class ChromePHPHandler extends AbstractProcessingHandler * * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending * - * @var Boolean + * @var bool */ protected static $overflowed = false; @@ -58,8 +58,8 @@ class ChromePHPHandler extends AbstractProcessingHandler protected static $sendHeaders = true; /** - * @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 + * @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) { diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 7778c22a..35b55cb4 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -60,7 +60,7 @@ class DeduplicationHandler extends BufferHandler * @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 int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through - * @param Boolean $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 */ public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true) { diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index 81967406..bb0f83eb 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -46,10 +46,10 @@ class ElasticSearchHandler extends AbstractProcessingHandler protected $options = array(); /** - * @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 Boolean $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 $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 = array(), $level = Logger::DEBUG, $bubble = true) { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 1447a584..b2986b0f 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -28,10 +28,10 @@ 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 Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $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 $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, $bubble = true, $expandNewlines = false) { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 2a0f7fd1..938c1a7e 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -40,7 +40,7 @@ class FilterHandler extends AbstractHandler /** * Whether the messages that are handled can bubble up the stack or not * - * @var Boolean + * @var bool */ protected $bubble; @@ -48,7 +48,7 @@ class FilterHandler extends AbstractHandler * @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 Boolean $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 */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) { diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index c3e42efe..aaca12cc 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -22,7 +22,7 @@ interface ActivationStrategyInterface * Returns whether the given record activates the handler. * * @param array $record - * @return Boolean + * @return bool */ public function isHandlerActivated(array $record); } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index d1dcaacf..d8026be6 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -41,8 +41,8 @@ class FingersCrossedHandler extends AbstractHandler * @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 Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true) + * @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 */ public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null) diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index fee47950..c30b1843 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -158,7 +158,7 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Verifies if the headers are accepted by the current user agent * - * @return Boolean + * @return bool */ protected function headersAccepted() { diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 663f5a92..c38508c2 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -23,8 +23,8 @@ class GroupHandler extends AbstractHandler protected $handlers; /** - * @param array $handlers Array of Handlers. - * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @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) { diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index d920c4ba..8d5a4a09 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -31,7 +31,7 @@ interface HandlerInterface * * @param array $record Partial log record containing only a level key * - * @return Boolean + * @return bool */ public function isHandling(array $record); @@ -46,7 +46,7 @@ interface HandlerInterface * 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. + * @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(array $record); diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index d60a3c82..7f226220 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -30,10 +30,10 @@ 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 Boolean $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 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) { diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index ab95924f..3f0956a9 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -27,7 +27,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 * @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 + * @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) { diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 1ae85845..a99e6ab7 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -31,7 +31,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 Boolean $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 */ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true) { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index bba72005..168a1c7b 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -69,8 +69,8 @@ class PushoverHandler extends SocketHandler * @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 Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not + * @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 * sending "high priority" requests to the Pushover API diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 53a8b391..eb5dda08 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -57,7 +57,7 @@ class RavenHandler extends AbstractProcessingHandler /** * @param Raven_Client $ravenClient * @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 + * @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) { diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 3b60b3d1..c8cdfab6 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -39,9 +39,9 @@ class RotatingFileHandler extends StreamHandler * @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 Boolean $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 * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) - * @param Boolean $useLocking Try to lock log file before doing any writes + * @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) { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 7a61bf4e..73a51311 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -33,9 +33,9 @@ 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 Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @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 */ public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 09a15738..dd4f7109 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -32,9 +32,9 @@ class StreamHandler extends AbstractProcessingHandler /** * @param resource|string $stream * @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 + * @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 Boolean $useLocking Try to lock log file before doing any writes + * @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 diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 376bc3b2..f770c802 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -32,11 +32,11 @@ 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 Boolean $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 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 */ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) { diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 4718711b..e14b378c 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -25,12 +25,12 @@ 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 Boolean $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 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. */ public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php') { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 49d00af1..994bba96 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -281,7 +281,7 @@ class Logger implements LoggerInterface * @param int $level The logging level * @param string $message The log message * @param array $context The log context - * @return Boolean Whether the record has been processed + * @return bool Whether the record has been processed */ public function addRecord($level, $message, array $context = array()) { @@ -484,7 +484,7 @@ class Logger implements LoggerInterface * Checks whether the Logger has a handler that listens on the given level * * @param int $level - * @return Boolean + * @return bool */ public function isHandling($level) { From 18b93feea6281d726d979ec098d49e59dec2f54e Mon Sep 17 00:00:00 2001 From: MilesChou Date: Thu, 30 Nov 2017 13:47:47 +0800 Subject: [PATCH 04/32] Add getter for webhook url in SlackWebhookHandler class Add getter so that the subclass can easy to inherit SlackWebhookHandler class --- src/Monolog/Handler/SlackWebhookHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 9a1bbb44..1ef85fae 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -70,6 +70,11 @@ class SlackWebhookHandler extends AbstractProcessingHandler return $this->slackRecord; } + public function getWebhookUrl() + { + return $this->webhookUrl; + } + /** * {@inheritdoc} * From 2d9c905b76eb6103eb089c2fcde15538593106c7 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Wed, 15 Nov 2017 18:05:17 +1300 Subject: [PATCH 05/32] ENHANCEMENT Ensure 'trace' is captured for non-exceptions Fixes #693 --- src/Monolog/ErrorHandler.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 7bfcd833..b3025738 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -38,6 +38,7 @@ class ErrorHandler private $hasFatalErrorHandler; private $fatalLevel; private $reservedMemory; + private $lastFatalTrace; private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); public function __construct(LoggerInterface $logger) @@ -156,6 +157,13 @@ class ErrorHandler if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) { $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line)); + } else { + // http://php.net/manual/en/function.debug-backtrace.php + // As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added. + // Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'. + $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS); + array_shift($trace); // Exclude handleError from trace + $this->lastFatalTrace = $trace; } if ($this->previousErrorHandler === true) { @@ -177,7 +185,7 @@ class ErrorHandler $this->logger->log( $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], - array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line']) + array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace) ); if ($this->logger instanceof Logger) { From 1e8deb4672c3cb0cd65cd6e6b2c0fbc8c8f5005f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 16 Apr 2018 15:03:26 +0200 Subject: [PATCH 06/32] Drop HHVM in .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b821b452..fa6119c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ php: - 5.6 - 7.0 - 7.1 - - hhvm - nightly matrix: From 1107013b9c3952db74284a7640f1f78581b164c9 Mon Sep 17 00:00:00 2001 From: MilesChou Date: Tue, 24 Apr 2018 23:17:02 +0800 Subject: [PATCH 07/32] Open visibility for slack handlers --- src/Monolog/Handler/SlackHandler.php | 4 ++-- src/Monolog/Handler/SlackWebhookHandler.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 3ac4d836..2c2cc4c0 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -27,13 +27,13 @@ class SlackHandler extends SocketHandler * Slack API token * @var string */ - private $token; + protected $token; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ - private $slackRecord; + protected $slackRecord; /** * @param string $token Slack API token diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 9a1bbb44..19f92cef 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -27,13 +27,13 @@ class SlackWebhookHandler extends AbstractProcessingHandler * Slack Webhook token * @var string */ - private $webhookUrl; + protected $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ - private $slackRecord; + protected $slackRecord; /** * @param string $webhookUrl Slack Webhook URL From 985fdb3eae0ad1085e2ccb291278d69b18d6919a Mon Sep 17 00:00:00 2001 From: MilesChou Date: Wed, 25 Apr 2018 15:51:22 +0800 Subject: [PATCH 08/32] Add getter for webhook and token property --- src/Monolog/Handler/SlackHandler.php | 9 +++++++-- src/Monolog/Handler/SlackWebhookHandler.php | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 2c2cc4c0..45d634f4 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -27,13 +27,13 @@ class SlackHandler extends SocketHandler * Slack API token * @var string */ - protected $token; + private $token; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ - protected $slackRecord; + private $slackRecord; /** * @param string $token Slack API token @@ -75,6 +75,11 @@ class SlackHandler extends SocketHandler return $this->slackRecord; } + public function getToken() + { + return $this->token; + } + /** * {@inheritdoc} * diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 19f92cef..1ef85fae 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -27,13 +27,13 @@ class SlackWebhookHandler extends AbstractProcessingHandler * Slack Webhook token * @var string */ - protected $webhookUrl; + private $webhookUrl; /** * Instance of the SlackRecord util class preparing data for Slack API. * @var SlackRecord */ - protected $slackRecord; + private $slackRecord; /** * @param string $webhookUrl Slack Webhook URL @@ -70,6 +70,11 @@ class SlackWebhookHandler extends AbstractProcessingHandler return $this->slackRecord; } + public function getWebhookUrl() + { + return $this->webhookUrl; + } + /** * {@inheritdoc} * From ccb95c08fdffacfa7a1315d71f12f1c726202342 Mon Sep 17 00:00:00 2001 From: Paul Webster Date: Thu, 3 May 2018 11:15:17 +1200 Subject: [PATCH 09/32] NewRelicHandler - handle Throwable in PHP7 --- src/Monolog/Handler/NewRelicHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 6718e9e0..ed2efa27 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -84,7 +84,7 @@ class NewRelicHandler extends AbstractProcessingHandler unset($record['formatted']['context']['transaction_name']); } - if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { + if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { newrelic_notice_error($record['message'], $record['context']['exception']); unset($record['formatted']['context']['exception']); } else { From a15c1daf9136bda720978775e52ad407db41f353 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Jun 2018 13:35:27 +0200 Subject: [PATCH 10/32] Use late static bindings in BrowserConsoleHandler --- src/Monolog/Handler/BrowserConsoleHandler.php | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index b3a21bd4..0225ee71 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -43,11 +43,11 @@ class BrowserConsoleHandler extends AbstractProcessingHandler protected function write(array $record) { // Accumulate records - self::$records[] = $record; + static::$records[] = $record; // Register shutdown handler if not already done - if (!self::$initialized) { - self::$initialized = true; + if (!static::$initialized) { + static::$initialized = true; $this->registerShutdownFunction(); } } @@ -58,18 +58,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler */ public static function send() { - $format = self::getResponseFormat(); + $format = static::getResponseFormat(); if ($format === 'unknown') { return; } - if (count(self::$records)) { + if (count(static::$records)) { if ($format === 'html') { - self::writeOutput(''); + static::writeOutput(''); } elseif ($format === 'js') { - self::writeOutput(self::generateScript()); + static::writeOutput(static::generateScript()); } - self::reset(); + static::reset(); } } @@ -78,7 +78,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler */ public static function reset() { - self::$records = array(); + static::$records = array(); } /** @@ -133,18 +133,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function generateScript() { $script = array(); - foreach (self::$records as $record) { - $context = self::dump('Context', $record['context']); - $extra = self::dump('Extra', $record['extra']); + foreach (static::$records as $record) { + $context = static::dump('Context', $record['context']); + $extra = static::dump('Extra', $record['extra']); if (empty($context) && empty($extra)) { - $script[] = self::call_array('log', self::handleStyles($record['formatted'])); + $script[] = static::call_array('log', static::handleStyles($record['formatted'])); } else { $script = array_merge($script, - array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))), + array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))), $context, $extra, - array(self::call('groupEnd')) + array(static::call('groupEnd')) ); } } @@ -154,19 +154,19 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function handleStyles($formatted) { - $args = array(self::quote('font-weight: normal')); + $args = array(static::quote('font-weight: normal')); $format = '%c' . $formatted; preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach (array_reverse($matches) as $match) { - $args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0])); + $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $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])); } - array_unshift($args, self::quote($format)); + array_unshift($args, static::quote($format)); return $args; } @@ -198,13 +198,13 @@ class BrowserConsoleHandler extends AbstractProcessingHandler if (empty($dict)) { return $script; } - $script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); + $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title)); foreach ($dict as $key => $value) { $value = json_encode($value); if (empty($value)) { - $value = self::quote(''); + $value = static::quote(''); } - $script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value); + $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value); } return $script; @@ -220,7 +220,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler $args = func_get_args(); $method = array_shift($args); - return self::call_array($method, $args); + return static::call_array($method, $args); } private static function call_array($method, array $args) From 678693e5eff4c360b376d28311fbce15601ab0be Mon Sep 17 00:00:00 2001 From: tnucera Date: Tue, 11 Jul 2017 12:40:56 +0200 Subject: [PATCH 11/32] Add context to fluentd formatter --- src/Monolog/Formatter/FluentdFormatter.php | 1 + tests/Monolog/Formatter/FluentdFormatterTest.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Monolog/Formatter/FluentdFormatter.php b/src/Monolog/Formatter/FluentdFormatter.php index 02632bb5..46a91ffe 100644 --- a/src/Monolog/Formatter/FluentdFormatter.php +++ b/src/Monolog/Formatter/FluentdFormatter.php @@ -62,6 +62,7 @@ class FluentdFormatter implements FormatterInterface $message = array( 'message' => $record['message'], + 'context' => $record['context'], 'extra' => $record['extra'], ); diff --git a/tests/Monolog/Formatter/FluentdFormatterTest.php b/tests/Monolog/Formatter/FluentdFormatterTest.php index 622b2bae..fd36dbcf 100644 --- a/tests/Monolog/Formatter/FluentdFormatterTest.php +++ b/tests/Monolog/Formatter/FluentdFormatterTest.php @@ -40,7 +40,7 @@ class FluentdFormatterTest extends TestCase $formatter = new FluentdFormatter(); $this->assertEquals( - '["test",0,{"message":"test","extra":[],"level":300,"level_name":"WARNING"}]', + '["test",0,{"message":"test","context":[],"extra":[],"level":300,"level_name":"WARNING"}]', $formatter->format($record) ); } @@ -55,7 +55,7 @@ class FluentdFormatterTest extends TestCase $formatter = new FluentdFormatter(true); $this->assertEquals( - '["test.error",0,{"message":"test","extra":[]}]', + '["test.error",0,{"message":"test","context":[],"extra":[]}]', $formatter->format($record) ); } From 68e39bd84f4ba24d9bc36bd44dfaa4dfd75c5c45 Mon Sep 17 00:00:00 2001 From: George Mponos Date: Sun, 18 Mar 2018 11:30:04 +0200 Subject: [PATCH 12/32] Add a record with an object as context --- tests/Monolog/Handler/Slack/SlackRecordTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index e1aa96d7..ae42393c 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -353,6 +353,14 @@ class SlackRecordTest extends TestCase $this->assertSame($record['datetime']->getTimestamp(), $attachment['ts']); } + 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']); + } + public function testExcludeExtraAndContextFields() { $record = $this->getRecord( From 07681ea4ba6fc0cb0077110000369f638863d8e8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 7 Jun 2018 18:23:28 +0200 Subject: [PATCH 13/32] Fix normalization of objects in SlackRecord, closes #1127 --- src/Monolog/Handler/Slack/SlackRecord.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) mode change 100644 => 100755 src/Monolog/Handler/Slack/SlackRecord.php diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php old mode 100644 new mode 100755 index 38bc838a..71b42960 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -229,8 +229,8 @@ class SlackRecord /** * Generates attachment field * - * @param string $title - * @param string|array $value\ + * @param string $title + * @param string|array $value * * @return array */ @@ -257,7 +257,7 @@ class SlackRecord private function generateAttachmentFields(array $data) { $fields = array(); - foreach ($data as $key => $value) { + foreach ($this->normalizerFormatter->format($data) as $key => $value) { $fields[] = $this->generateAttachmentField($key, $value); } From 8c4539f1fea4f37998d95eedc917edb1620b8abf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 7 Jun 2018 18:45:07 +0200 Subject: [PATCH 14/32] More boolean=>bool --- src/Monolog/Handler/ChromePHPHandler.php | 4 +- src/Monolog/Handler/PushoverHandler.php | 2 +- src/Monolog/Handler/SocketHandler.php | 2 +- src/Monolog/Handler/SwiftMailerHandler.php | 2 +- src/Monolog/Logger.php | 126 ++++++++++----------- src/Monolog/Processor/MemoryProcessor.php | 4 +- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index ea8ae7fb..37419a06 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -32,7 +32,7 @@ class ChromePHPHandler extends AbstractProcessingHandler * Header name */ const HEADER_NAME = 'X-ChromeLogger-Data'; - + /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ @@ -174,7 +174,7 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Verifies if the headers are accepted by the current user agent * - * @return Boolean + * @return bool */ protected function headersAccepted() { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 168a1c7b..f27bb3da 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -180,6 +180,6 @@ class PushoverHandler extends SocketHandler */ public function useFormattedMessage($value) { - $this->useFormattedMessage = (boolean) $value; + $this->useFormattedMessage = (bool) $value; } } diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 73a51311..79d49ece 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -87,7 +87,7 @@ class SocketHandler extends AbstractProcessingHandler */ public function setPersistent($persistent) { - $this->persistent = (boolean) $persistent; + $this->persistent = (bool) $persistent; } /** diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 72f44a53..bcba88e6 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -29,7 +29,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 $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 + * @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, $bubble = true) { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 994bba96..db67777f 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -347,9 +347,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the DEBUG level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addDebug($message, array $context = array()) { @@ -359,9 +359,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the INFO level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addInfo($message, array $context = array()) { @@ -371,9 +371,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the NOTICE level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addNotice($message, array $context = array()) { @@ -383,9 +383,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the WARNING level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addWarning($message, array $context = array()) { @@ -395,9 +395,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the ERROR level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addError($message, array $context = array()) { @@ -407,9 +407,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the CRITICAL level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addCritical($message, array $context = array()) { @@ -419,9 +419,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the ALERT level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addAlert($message, array $context = array()) { @@ -431,9 +431,9 @@ class Logger implements LoggerInterface /** * Adds a log record at the EMERGENCY level. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function addEmergency($message, array $context = array()) { @@ -507,9 +507,9 @@ class Logger implements LoggerInterface * 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 - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function log($level, $message, array $context = array()) { @@ -523,9 +523,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function debug($message, array $context = array()) { @@ -537,9 +537,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function info($message, array $context = array()) { @@ -551,9 +551,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function notice($message, array $context = array()) { @@ -565,9 +565,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function warn($message, array $context = array()) { @@ -579,9 +579,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function warning($message, array $context = array()) { @@ -593,9 +593,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function err($message, array $context = array()) { @@ -607,9 +607,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function error($message, array $context = array()) { @@ -621,9 +621,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function crit($message, array $context = array()) { @@ -635,9 +635,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function critical($message, array $context = array()) { @@ -649,9 +649,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function alert($message, array $context = array()) { @@ -663,9 +663,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function emerg($message, array $context = array()) { @@ -677,9 +677,9 @@ class Logger implements LoggerInterface * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return Boolean Whether the record has been processed + * @param string $message The log message + * @param array $context The log context + * @return bool Whether the record has been processed */ public function emergency($message, array $context = array()) { diff --git a/src/Monolog/Processor/MemoryProcessor.php b/src/Monolog/Processor/MemoryProcessor.php index 85f9dc5e..73f132d7 100644 --- a/src/Monolog/Processor/MemoryProcessor.php +++ b/src/Monolog/Processor/MemoryProcessor.php @@ -34,8 +34,8 @@ abstract class MemoryProcessor */ public function __construct($realUsage = true, $useFormatting = true) { - $this->realUsage = (boolean) $realUsage; - $this->useFormatting = (boolean) $useFormatting; + $this->realUsage = (bool) $realUsage; + $this->useFormatting = (bool) $useFormatting; } /** From dfa21a506e9395fe9fe83436bf4c3bb13e093d1c Mon Sep 17 00:00:00 2001 From: Mponos George Date: Thu, 7 Jun 2018 20:17:53 +0300 Subject: [PATCH 15/32] Update .travis.yml (#1120) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fa6119c8..07bad617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 - nightly matrix: From 2aa45553d8770c9b6c66820ad18d3e4b2ac3e5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=B6ller?= Date: Thu, 7 Jun 2018 19:20:58 +0200 Subject: [PATCH 16/32] Fix: Remove VersionEye badge (#1140) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7d8ade52..d7569446 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) [![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) -[![Reference Status](https://www.versioneye.com/php/monolog:monolog/reference_badge.svg)](https://www.versioneye.com/php/monolog:monolog/references) Monolog sends your logs to files, sockets, inboxes, databases and various From c0eeca76fdb1b5410e7af36bbfe5af265eeb5bf6 Mon Sep 17 00:00:00 2001 From: Josh McRae Date: Wed, 16 Aug 2017 13:54:33 +1000 Subject: [PATCH 17/32] Check for directory before throwing 'no existing directory' exception --- 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 dd4f7109..a35b7e4c 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -167,7 +167,7 @@ class StreamHandler extends AbstractProcessingHandler set_error_handler(array($this, 'customErrorHandler')); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status) { + if (false === $status && !is_dir($dir)) { throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir)); } } From 22b92c7c00d495b4a9cb043bc592aa5a3f9065c8 Mon Sep 17 00:00:00 2001 From: Ben Dubuisson Date: Mon, 10 Jul 2017 19:18:17 +1200 Subject: [PATCH 18/32] Fixed message not being passed to client when capturing an exception The raven client expects the message to be at the first level of the data array when passing an exception. see https://github.com/getsentry/sentry-php/blob/master/lib/Raven/Client.php#L795 --- 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 eb5dda08..34ff0091 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -180,7 +180,7 @@ class RavenHandler extends AbstractProcessingHandler } if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { - $options['extra']['message'] = $record['formatted']; + $options['message'] = $record['formatted']; $this->ravenClient->captureException($record['context']['exception'], $options); } else { $this->ravenClient->captureMessage($record['formatted'], array(), $options); From 3035d4a251c989b4795635b33d4cc4e1bb662b7e Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Wed, 12 Jul 2017 07:45:50 +0100 Subject: [PATCH 19/32] Fix WhatFailureGroupHandler::handleBatch when the handler has processors --- .../Handler/WhatFailureGroupHandler.php | 10 ++++++++ .../Handler/WhatFailureGroupHandlerTest.php | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 2732ba3d..6bc4671c 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -48,6 +48,16 @@ class WhatFailureGroupHandler extends GroupHandler */ public function handleBatch(array $records) { + if ($this->processors) { + $processed = array(); + foreach ($records as $record) { + foreach ($this->processors as $processor) { + $processed[] = call_user_func($processor, $record); + } + } + $records = $processed; + } + foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); diff --git a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php index 8d37a1fc..0594a232 100644 --- a/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php +++ b/tests/Monolog/Handler/WhatFailureGroupHandlerTest.php @@ -87,6 +87,29 @@ class WhatFailureGroupHandlerTest extends TestCase $this->assertTrue($records[0]['extra']['foo']); } + /** + * @covers Monolog\Handler\WhatFailureGroupHandler::handleBatch + */ + public function testHandleBatchUsesProcessors() + { + $testHandlers = array(new TestHandler(), new TestHandler()); + $handler = new WhatFailureGroupHandler($testHandlers); + $handler->pushProcessor(function ($record) { + $record['extra']['foo'] = true; + + return $record; + }); + $handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO))); + foreach ($testHandlers as $test) { + $this->assertTrue($test->hasDebugRecords()); + $this->assertTrue($test->hasInfoRecords()); + $this->assertTrue(count($test->getRecords()) === 2); + $records = $test->getRecords(); + $this->assertTrue($records[0]['extra']['foo']); + $this->assertTrue($records[1]['extra']['foo']); + } + } + /** * @covers Monolog\Handler\WhatFailureGroupHandler::handle */ From 6d79e51f91de32c7ea9d85e2a1ad1c92ea34779e Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Jun 2018 20:47:04 +0200 Subject: [PATCH 20/32] Tweaks to exception handler, refs #1012 --- src/Monolog/Logger.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index bb14a026..28e9cf98 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -15,6 +15,7 @@ use Monolog\Handler\HandlerInterface; use Monolog\Handler\StreamHandler; use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; +use Exception; /** * Monolog log channel @@ -346,8 +347,8 @@ class Logger implements LoggerInterface next($this->handlers); } - } catch (\Exception $ex) { - $this->handleException($ex, $record); + } catch (Exception $e) { + $this->handleException($e, $record); } return true; @@ -537,17 +538,14 @@ class Logger implements LoggerInterface /** * Delegates exception management to the custom exception handler, * or throws the exception if no custom handler is set. - * - * @param Exception $ex - * @param array $record */ - protected function handleException(\Exception $ex, $record) + protected function handleException(Exception $e, array $record) { - if ($this->exceptionHandler) { - call_user_func($this->exceptionHandler, $ex, $record); - } else { - throw $ex; + if (!$this->exceptionHandler) { + throw $e; } + + call_user_func($this->exceptionHandler, $e, $record); } /** From 948bb4a6a0ec78b4912332aff3c38bb884017b83 Mon Sep 17 00:00:00 2001 From: Thomas Schulz Date: Mon, 26 Mar 2018 17:45:38 +0200 Subject: [PATCH 21/32] Improve table row output in HtmlFormatter --- src/Monolog/Formatter/HtmlFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 3eec95f6..8faa8030 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -58,7 +58,7 @@ class HtmlFormatter extends NormalizerFormatter $td = '
'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'
'; } - return "\n$th:\n".$td."\n"; + return "\n$th:\n".$td."\n"; } /** From 2893c2b875877ba028029dbfd8b7f757d70b197d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Jun 2018 21:43:50 +0200 Subject: [PATCH 22/32] Specify text color to improve dark theme support, refs #1128 --- src/Monolog/Formatter/HtmlFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 8faa8030..dfc0b4a3 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -58,7 +58,7 @@ class HtmlFormatter extends NormalizerFormatter $td = '
'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'
'; } - return "\n$th:\n".$td."\n"; + return "\n$th:\n".$td."\n"; } /** From 5f8783686e6486a8080980c4662518197f5c89b5 Mon Sep 17 00:00:00 2001 From: Alban Kora Date: Tue, 3 Oct 2017 23:54:38 +0100 Subject: [PATCH 23/32] Fixing file rotation when similar files are present --- src/Monolog/Handler/RotatingFileHandler.php | 2 +- .../Handler/RotatingFileHandlerTest.php | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index c8cdfab6..cc9fd4d3 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -166,7 +166,7 @@ class RotatingFileHandler extends StreamHandler $fileInfo = pathinfo($this->filename); $glob = str_replace( array('{filename}', '{date}'), - array($fileInfo['filename'], '*'), + array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'), $fileInfo['dirname'] . '/' . $this->filenameFormat ); if (!empty($fileInfo['extension'])) { diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index f1feb228..0f99580c 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -191,6 +191,40 @@ class RotatingFileHandlerTest extends TestCase ); } + /** + * @dataProvider rotationWhenSimilarFilesExistTests + */ + public function testRotationWhenSimilarFileNamesExist($dateFormat) + { + touch($old1 = __DIR__.'/Fixtures/foo-foo-'.date($dateFormat).'.rot'); + touch($old2 = __DIR__.'/Fixtures/foo-bar-'.date($dateFormat).'.rot'); + + $log = __DIR__.'/Fixtures/foo-'.date($dateFormat).'.rot'; + + $handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->setFilenameFormat('{filename}-{date}', $dateFormat); + $handler->handle($this->getRecord()); + $handler->close(); + + $this->assertTrue(file_exists($log)); + } + + public function rotationWhenSimilarFilesExistTests() + { + + return [ + 'Rotation is triggered when the file of the current day is not present but similar exists' + => [RotatingFileHandler::FILE_PER_DAY], + + 'Rotation is triggered when the file of the current month is not present but similar exists' + => [RotatingFileHandler::FILE_PER_MONTH], + + 'Rotation is triggered when the file of the current year is not present but similar exists' + => [RotatingFileHandler::FILE_PER_YEAR], + ]; + } + public function testReuseCurrentFile() { $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; From ada5d30511cb9dac9b90f4f501f6dc2a51525f53 Mon Sep 17 00:00:00 2001 From: Minh-Quan TRAN Date: Thu, 17 Aug 2017 17:11:16 +0200 Subject: [PATCH 24/32] If context has exactly 1000 items, do not truncate --- src/Monolog/Formatter/JsonFormatter.php | 5 +-- src/Monolog/Formatter/NormalizerFormatter.php | 3 +- tests/Monolog/Formatter/JsonFormatterTest.php | 36 +++++++++++++++++++ .../Formatter/NormalizerFormatterTest.php | 20 ++++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 0782f149..247122a2 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -145,10 +145,11 @@ class JsonFormatter extends NormalizerFormatter $count = 1; foreach ($data as $key => $value) { - if ($count++ >= 1000) { - $normalized['...'] = 'Over 1000 items, aborting normalization'; + if ($count++ > 1000) { + $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; break; } + $normalized[$key] = $this->normalize($value); } diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index d4414882..e6142b63 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -75,10 +75,11 @@ class NormalizerFormatter implements FormatterInterface $count = 1; foreach ($data as $key => $value) { - if ($count++ >= 1000) { + if ($count++ > 1000) { $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; break; } + $normalized[$key] = $this->normalize($value); } diff --git a/tests/Monolog/Formatter/JsonFormatterTest.php b/tests/Monolog/Formatter/JsonFormatterTest.php index c9445f36..24b06cc9 100644 --- a/tests/Monolog/Formatter/JsonFormatterTest.php +++ b/tests/Monolog/Formatter/JsonFormatterTest.php @@ -180,4 +180,40 @@ class JsonFormatterTest extends TestCase '}'; return $formattedException; } + + 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(), + )); + + $this->assertCount(1000, $res['context'][0]); + $this->assertArrayNotHasKey('...', $res['context'][0]); + } + + 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(), + )); + + $this->assertCount(1001, $res['context'][0]); + $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); + } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 57bcdf98..44c1e660 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -217,6 +217,24 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase $this->assertEquals(@json_encode(array($resource)), $res); } + 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(), + )); + + $this->assertCount(1000, $res['context'][0]); + $this->assertArrayNotHasKey('...', $res['context'][0]); + } + public function testNormalizeHandleLargeArrays() { $formatter = new NormalizerFormatter(); @@ -231,7 +249,7 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase 'extra' => array(), )); - $this->assertCount(1000, $res['context'][0]); + $this->assertCount(1001, $res['context'][0]); $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); } From f6842ac92dcffe9e5bd3684c3ea3984e23c0e84d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Jun 2018 23:19:28 +0200 Subject: [PATCH 25/32] Avoid breaking the gelf handler when closing it, fixes #1016 --- src/Monolog/Handler/GelfHandler.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index d3847d82..71e46693 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -47,14 +47,6 @@ class GelfHandler extends AbstractProcessingHandler $this->publisher = $publisher; } - /** - * {@inheritdoc} - */ - public function close() - { - $this->publisher = null; - } - /** * {@inheritdoc} */ From 06f7bfb0ee4284e48e227880feeec1d87b50955a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 8 Jun 2018 23:41:14 +0200 Subject: [PATCH 26/32] Fix 5.3 build --- tests/Monolog/Handler/RotatingFileHandlerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index 0f99580c..ba61caa9 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -213,7 +213,7 @@ class RotatingFileHandlerTest extends TestCase public function rotationWhenSimilarFilesExistTests() { - return [ + return array( 'Rotation is triggered when the file of the current day is not present but similar exists' => [RotatingFileHandler::FILE_PER_DAY], @@ -222,7 +222,7 @@ class RotatingFileHandlerTest extends TestCase 'Rotation is triggered when the file of the current year is not present but similar exists' => [RotatingFileHandler::FILE_PER_YEAR], - ]; + ); } public function testReuseCurrentFile() From 5de973cd337335c90007ed4038d5775f251e36bf Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 9 Jun 2018 10:23:30 +0200 Subject: [PATCH 27/32] More 5.3 fixes --- tests/Monolog/Handler/RotatingFileHandlerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Monolog/Handler/RotatingFileHandlerTest.php b/tests/Monolog/Handler/RotatingFileHandlerTest.php index ba61caa9..c6f5fac9 100644 --- a/tests/Monolog/Handler/RotatingFileHandlerTest.php +++ b/tests/Monolog/Handler/RotatingFileHandlerTest.php @@ -215,13 +215,13 @@ class RotatingFileHandlerTest extends TestCase return array( 'Rotation is triggered when the file of the current day is not present but similar exists' - => [RotatingFileHandler::FILE_PER_DAY], + => array(RotatingFileHandler::FILE_PER_DAY), 'Rotation is triggered when the file of the current month is not present but similar exists' - => [RotatingFileHandler::FILE_PER_MONTH], + => array(RotatingFileHandler::FILE_PER_MONTH), 'Rotation is triggered when the file of the current year is not present but similar exists' - => [RotatingFileHandler::FILE_PER_YEAR], + => array(RotatingFileHandler::FILE_PER_YEAR), ); } From 120c434db947f91c3844ea9212ce34d08262335a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Mon, 11 Jun 2018 17:22:12 +0200 Subject: [PATCH 28/32] Verify handlers types, fixes #1131 --- 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 28e9cf98..5034ead1 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -147,7 +147,7 @@ class Logger implements LoggerInterface public function __construct($name, array $handlers = array(), array $processors = array()) { $this->name = $name; - $this->handlers = $handlers; + $this->setHandlers($handlers); $this->processors = $processors; } From 6e1793e966a0042367b661010d8b68dabbb5dd45 Mon Sep 17 00:00:00 2001 From: Sergey Zaika Date: Tue, 12 Jun 2018 00:55:44 +0300 Subject: [PATCH 29/32] Getter for SwiftMailerHandler subject formatter --- src/Monolog/Handler/SwiftMailerHandler.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index bcba88e6..ac7b16ff 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\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Swift; @@ -47,6 +48,17 @@ class SwiftMailerHandler extends MailHandler $this->mailer->send($this->buildMessage($content, $records)); } + /** + * Gets the formatter for the Swift_Message subject. + * + * @param string $format The format of the subject + * @return FormatterInterface + */ + protected function getSubjectFormatter($format) + { + return new LineFormatter($format); + } + /** * Creates instance of Swift_Message to be sent * @@ -69,7 +81,7 @@ class SwiftMailerHandler extends MailHandler } if ($records) { - $subjectFormatter = new LineFormatter($message->getSubject()); + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } From 0d993d84d1439466a53c517569174738984cf008 Mon Sep 17 00:00:00 2001 From: Andrew Berry Date: Sun, 17 Jun 2018 11:27:33 -0400 Subject: [PATCH 30/32] Normalization of arrays containing self references (#1050) Backport normalization fix from master to 1.x --- src/Monolog/Formatter/JsonFormatter.php | 8 ++++++-- src/Monolog/Formatter/NormalizerFormatter.php | 8 ++++++-- src/Monolog/Formatter/WildfireFormatter.php | 4 ++-- tests/Monolog/Formatter/NormalizerFormatterTest.php | 9 +++++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 247122a2..b8309b10 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -138,8 +138,12 @@ class JsonFormatter extends NormalizerFormatter * * @return mixed */ - protected function normalize($data) + protected function normalize($data, $depth = 0) { + if ($depth > 9) { + return 'Over 9 levels deep, aborting normalization'; + } + if (is_array($data) || $data instanceof \Traversable) { $normalized = array(); @@ -150,7 +154,7 @@ class JsonFormatter extends NormalizerFormatter break; } - $normalized[$key] = $this->normalize($value); + $normalized[$key] = $this->normalize($value, $depth+1); } return $normalized; diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index e6142b63..91227241 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -55,8 +55,12 @@ class NormalizerFormatter implements FormatterInterface return $records; } - protected function normalize($data) + protected function normalize($data, $depth = 0) { + if ($depth > 9) { + return 'Over 9 levels deep, aborting normalization'; + } + if (null === $data || is_scalar($data)) { if (is_float($data)) { if (is_infinite($data)) { @@ -80,7 +84,7 @@ class NormalizerFormatter implements FormatterInterface break; } - $normalized[$key] = $this->normalize($value); + $normalized[$key] = $this->normalize($value, $depth+1); } return $normalized; diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 654710a8..65dba99c 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -102,12 +102,12 @@ class WildfireFormatter extends NormalizerFormatter throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); } - protected function normalize($data) + protected function normalize($data, $depth = 0) { if (is_object($data) && !$data instanceof \DateTime) { return $data; } - return parent::normalize($data); + return parent::normalize($data, $depth); } } diff --git a/tests/Monolog/Formatter/NormalizerFormatterTest.php b/tests/Monolog/Formatter/NormalizerFormatterTest.php index 44c1e660..b4f82897 100644 --- a/tests/Monolog/Formatter/NormalizerFormatterTest.php +++ b/tests/Monolog/Formatter/NormalizerFormatterTest.php @@ -193,6 +193,15 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase $this->assertEquals(@json_encode(array($foo, $bar)), $res); } + public function testCanNormalizeReferences() + { + $formatter = new NormalizerFormatter(); + $x = array('foo' => 'bar'); + $y = array('x' => &$x); + $x['y'] = &$y; + $formatter->format($y); + } + public function testIgnoresInvalidTypes() { // set up the recursion From 00aca28c8bc4e416ddcf76c26059c1676ed33cd2 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 17 Jun 2018 18:03:59 +0200 Subject: [PATCH 31/32] Fix SlackRecord normalization of fields, closes #1078 --- src/Monolog/Handler/Slack/SlackRecord.php | 4 ++-- tests/Monolog/Handler/Slack/SlackRecordTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 71b42960..e55e0e2e 100755 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -146,7 +146,7 @@ class SlackRecord if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( - ucfirst($key), + $key, $record[$key] ); } else { @@ -241,7 +241,7 @@ class SlackRecord : $value; return array( - 'title' => $title, + 'title' => ucfirst($title), 'value' => $value, 'short' => false ); diff --git a/tests/Monolog/Handler/Slack/SlackRecordTest.php b/tests/Monolog/Handler/Slack/SlackRecordTest.php index ae42393c..b9de7367 100644 --- a/tests/Monolog/Handler/Slack/SlackRecordTest.php +++ b/tests/Monolog/Handler/Slack/SlackRecordTest.php @@ -320,12 +320,12 @@ class SlackRecordTest extends TestCase 'short' => false, ), array( - 'title' => 'tags', + 'title' => 'Tags', 'value' => sprintf('```%s```', json_encode($extra['tags'])), 'short' => false ), array( - 'title' => 'test', + 'title' => 'Test', 'value' => $context['test'], 'short' => false ) @@ -376,12 +376,12 @@ class SlackRecordTest extends TestCase $expected = array( array( - 'title' => 'info', + 'title' => 'Info', 'value' => sprintf('```%s```', json_encode(array('author' => 'Jordi'), $this->jsonPrettyPrintFlag)), 'short' => false ), array( - 'title' => 'tags', + 'title' => 'Tags', 'value' => sprintf('```%s```', json_encode(array('web'))), 'short' => false ), From e8db808dd3e079c194f6f4dbdb06cf5758b0d0f6 Mon Sep 17 00:00:00 2001 From: Klemen Bratec Date: Mon, 18 Jun 2018 11:31:46 +0200 Subject: [PATCH 32/32] Allow setting stream chunk size in SocketHandler (#1129) --- src/Monolog/Handler/SocketHandler.php | 39 +++++++++++++++++++++ tests/Monolog/Handler/SocketHandlerTest.php | 26 ++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 79d49ece..db50d97f 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -27,6 +27,7 @@ class SocketHandler extends AbstractProcessingHandler private $timeout = 0; private $writingTimeout = 10; private $lastSentBytes = null; + private $chunkSize = null; private $persistent = false; private $errno; private $errstr; @@ -127,6 +128,16 @@ class SocketHandler extends AbstractProcessingHandler $this->writingTimeout = (float) $seconds; } + /** + * Set chunk size. Only has effect during connection in the writing cycle. + * + * @param float $bytes + */ + public function setChunkSize($bytes) + { + $this->chunkSize = $bytes; + } + /** * Get current connection string * @@ -177,6 +188,16 @@ class SocketHandler extends AbstractProcessingHandler return $this->writingTimeout; } + /** + * Get current chunk size + * + * @return float + */ + public function getChunkSize() + { + return $this->chunkSize; + } + /** * Check to see if the socket is currently available. * @@ -219,6 +240,16 @@ class SocketHandler extends AbstractProcessingHandler return stream_set_timeout($this->resource, $seconds, $microseconds); } + /** + * Wrapper to allow mocking + * + * @see http://php.net/manual/en/function.stream-set-chunk-size.php + */ + protected function streamSetChunkSize() + { + return stream_set_chunk_size($this->resource, $this->chunkSize); + } + /** * Wrapper to allow mocking */ @@ -268,6 +299,7 @@ class SocketHandler extends AbstractProcessingHandler { $this->createSocketResource(); $this->setSocketTimeout(); + $this->setStreamChunkSize(); } private function createSocketResource() @@ -290,6 +322,13 @@ class SocketHandler extends AbstractProcessingHandler } } + private function setStreamChunkSize() + { + if ($this->chunkSize && !$this->streamSetChunkSize()) { + throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); + } + } + private function writeToSocket($data) { $length = strlen($data); diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index 1f9c1f28..1da987c9 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -77,6 +77,13 @@ class SocketHandlerTest extends TestCase $this->assertEquals(10.25, $this->handler->getWritingTimeout()); } + public function testSetChunkSize() + { + $this->createHandler('localhost:1234'); + $this->handler->setChunkSize(1025); + $this->assertEquals(1025, $this->handler->getChunkSize()); + } + public function testSetConnectionString() { $this->createHandler('tcp://localhost:9090'); @@ -120,6 +127,19 @@ class SocketHandlerTest extends TestCase $this->writeRecord('Hello world'); } + /** + * @expectedException UnexpectedValueException + */ + public function testExceptionIsThrownIfCannotSetChunkSize() + { + $this->setMockHandler(array('streamSetChunkSize')); + $this->handler->setChunkSize(8192); + $this->handler->expects($this->once()) + ->method('streamSetChunkSize') + ->will($this->returnValue(false)); + $this->writeRecord('Hello world'); + } + /** * @expectedException RuntimeException */ @@ -304,6 +324,12 @@ class SocketHandlerTest extends TestCase ->will($this->returnValue(true)); } + if (!in_array('streamSetChunkSize', $methods)) { + $this->handler->expects($this->any()) + ->method('streamSetChunkSize') + ->will($this->returnValue(8192)); + } + $this->handler->setFormatter($this->getIdentityFormatter()); } }