diff options
Diffstat (limited to 'src/Monolog/Handler')
69 files changed, 1284 insertions, 687 deletions
diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index 758a425..ea79ec9 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,26 +12,18 @@ namespace Monolog\Handler; use Monolog\Logger; -use Monolog\Formatter\FormatterInterface; -use Monolog\Formatter\LineFormatter; /** - * Base Handler class providing the Handler structure + * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano <j.boggiano@seld.be> */ -abstract class AbstractHandler implements HandlerInterface +abstract class AbstractHandler extends Handler { protected $level = Logger::DEBUG; protected $bubble = true; /** - * @var FormatterInterface - */ - protected $formatter; - 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 */ @@ -44,84 +36,18 @@ abstract class AbstractHandler implements HandlerInterface /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return $record['level'] >= $this->level; } /** - * {@inheritdoc} - */ - public function handleBatch(array $records) - { - foreach ($records as $record) { - $this->handle($record); - } - } - - /** - * Closes the handler. - * - * This will be called automatically when the object is destroyed - */ - public function close() - { - } - - /** - * {@inheritdoc} - */ - public function pushProcessor($callback) - { - if (!is_callable($callback)) { - throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); - } - array_unshift($this->processors, $callback); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function popProcessor() - { - if (!$this->processors) { - throw new \LogicException('You tried to pop from an empty processor stack.'); - } - - return array_shift($this->processors); - } - - /** - * {@inheritdoc} - */ - public function setFormatter(FormatterInterface $formatter) - { - $this->formatter = $formatter; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getFormatter() - { - if (!$this->formatter) { - $this->formatter = $this->getDefaultFormatter(); - } - - return $this->formatter; - } - - /** * Sets minimum logging level at which this handler will be triggered. * * @param int|string $level Level or level name * @return self */ - public function setLevel($level) + public function setLevel($level): self { $this->level = Logger::toMonologLevel($level); @@ -133,7 +59,7 @@ abstract class AbstractHandler implements HandlerInterface * * @return int */ - public function getLevel() + public function getLevel(): int { return $this->level; } @@ -145,7 +71,7 @@ abstract class AbstractHandler implements HandlerInterface * false means that bubbling is not permitted. * @return self */ - public function setBubble($bubble) + public function setBubble(bool $bubble): self { $this->bubble = $bubble; @@ -158,29 +84,8 @@ abstract class AbstractHandler implements HandlerInterface * @return Boolean true means that this handler allows bubbling. * false means that bubbling is not permitted. */ - public function getBubble() + public function getBubble(): bool { return $this->bubble; } - - public function __destruct() - { - try { - $this->close(); - } catch (\Exception $e) { - // do nothing - } catch (\Throwable $e) { - // do nothing - } - } - - /** - * Gets the default formatter. - * - * @return FormatterInterface - */ - protected function getDefaultFormatter() - { - return new LineFormatter(); - } } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 6f18f72..654e671 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -19,18 +19,23 @@ namespace Monolog\Handler; * @author Jordi Boggiano <j.boggiano@seld.be> * @author Christophe Coevoet <stof@notk.org> */ -abstract class AbstractProcessingHandler extends AbstractHandler +abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + use FormattableHandlerTrait; + /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; } - $record = $this->processRecord($record); + if ($this->processors) { + $record = $this->processRecord($record); + } $record['formatted'] = $this->getFormatter()->format($record); @@ -46,21 +51,4 @@ abstract class AbstractProcessingHandler extends AbstractHandler * @return void */ abstract protected function write(array $record); - - /** - * Processes a record. - * - * @param array $record - * @return array - */ - protected function processRecord(array $record) - { - if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - } - - return $record; - } } diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index e2b2832..d6fc41e 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; /** @@ -24,7 +25,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * Translates Monolog log levels to syslog log priorities. */ - protected $logLevels = array( + protected $logLevels = [ Logger::DEBUG => LOG_DEBUG, Logger::INFO => LOG_INFO, Logger::NOTICE => LOG_NOTICE, @@ -33,12 +34,12 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler Logger::CRITICAL => LOG_CRIT, Logger::ALERT => LOG_ALERT, Logger::EMERGENCY => LOG_EMERG, - ); + ]; /** * List of valid log facility names. */ - protected $facilities = array( + protected $facilities = [ 'auth' => LOG_AUTH, 'authpriv' => LOG_AUTHPRIV, 'cron' => LOG_CRON, @@ -50,7 +51,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler 'syslog' => LOG_SYSLOG, 'user' => LOG_USER, 'uucp' => LOG_UUCP, - ); + ]; /** * @param mixed $facility @@ -82,7 +83,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler } // convert textual description of facility to syslog constant - if (array_key_exists(strtolower($facility), $this->facilities)) { + if (is_string($facility) && array_key_exists(strtolower($facility), $this->facilities)) { $facility = $this->facilities[strtolower($facility)]; } elseif (!in_array($facility, array_values($this->facilities), true)) { throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given'); @@ -94,7 +95,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * {@inheritdoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); } diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index e5a46bc..6e39a11 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Channel\AMQPChannel; @@ -31,18 +32,18 @@ class AmqpHandler extends AbstractProcessingHandler /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use - * @param string $exchangeName + * @param string $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only * @param int $level * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) + public function __construct($exchange, $exchangeName = null, $level = Logger::DEBUG, $bubble = true) { - if ($exchange instanceof AMQPExchange) { - $exchange->setName($exchangeName); - } elseif ($exchange instanceof AMQPChannel) { + if ($exchange instanceof AMQPChannel) { $this->exchangeName = $exchangeName; - } else { + } elseif (!$exchange instanceof AMQPExchange) { throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required'); + } elseif ($exchangeName) { + @trigger_error('The $exchangeName parameter can only be passed when using PhpAmqpLib, if using an AMQPExchange instance configure it beforehand', E_USER_DEPRECATED); } $this->exchange = $exchange; @@ -62,10 +63,10 @@ class AmqpHandler extends AbstractProcessingHandler $data, $routingKey, 0, - array( + [ 'delivery_mode' => 2, 'content_type' => 'application/json', - ) + ] ); } else { $this->exchange->basic_publish( @@ -113,12 +114,7 @@ class AmqpHandler extends AbstractProcessingHandler */ protected function getRoutingKey(array $record) { - $routingKey = sprintf( - '%s.%s', - // TODO 2.0 remove substr call - substr($record['level_name'], 0, 4), - $record['channel'] - ); + $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']); return strtolower($routingKey); } @@ -131,17 +127,17 @@ class AmqpHandler extends AbstractProcessingHandler { return new AMQPMessage( (string) $data, - array( + [ 'delivery_mode' => 2, 'content_type' => 'application/json', - ) + ] ); } /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index b3a21bd..4879d24 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; /** * Handler sending logs to browser's javascript console with no browser extension required @@ -21,7 +22,7 @@ use Monolog\Formatter\LineFormatter; class BrowserConsoleHandler extends AbstractProcessingHandler { protected static $initialized = false; - protected static $records = array(); + protected static $records = []; /** * {@inheritDoc} @@ -32,7 +33,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler * * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%'); } @@ -78,7 +79,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler */ public static function reset() { - self::$records = array(); + self::$records = []; } /** @@ -87,7 +88,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler protected function registerShutdownFunction() { if (PHP_SAPI !== 'cli') { - register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send')); + register_shutdown_function(['Monolog\Handler\BrowserConsoleHandler', 'send']); } } @@ -132,7 +133,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function generateScript() { - $script = array(); + $script = []; foreach (self::$records as $record) { $context = self::dump('Context', $record['context']); $extra = self::dump('Extra', $record['extra']); @@ -141,10 +142,10 @@ class BrowserConsoleHandler extends AbstractProcessingHandler $script[] = self::call_array('log', self::handleStyles($record['formatted'])); } else { $script = array_merge($script, - array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))), + [self::call_array('groupCollapsed', self::handleStyles($record['formatted']))], $context, $extra, - array(self::call('groupEnd')) + [self::call('groupEnd')] ); } } @@ -154,7 +155,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function handleStyles($formatted) { - $args = array(self::quote('font-weight: normal')); + $args = [self::quote('font-weight: normal')]; $format = '%c' . $formatted; preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); @@ -173,8 +174,8 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function handleCustomStyles($style, $string) { - static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey'); - static $labels = array(); + static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; + static $labels = []; return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) { if (trim($m[1]) === 'autolabel') { @@ -193,7 +194,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler private static function dump($title, array $dict) { - $script = array(); + $script = []; $dict = array_filter($dict); if (empty($dict)) { return $script; diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 72f8953..5ce6c39 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -21,13 +21,15 @@ use Monolog\Logger; * * @author Christophe Coevoet <stof@notk.org> */ -class BufferHandler extends AbstractHandler +class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface { + use ProcessableHandlerTrait; + protected $handler; protected $bufferSize = 0; protected $bufferLimit; protected $flushOnOverflow; - protected $buffer = array(); + protected $buffer = []; protected $initialized = false; /** @@ -48,7 +50,7 @@ class BufferHandler extends AbstractHandler /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($record['level'] < $this->level) { return false; @@ -56,7 +58,7 @@ class BufferHandler extends AbstractHandler if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors - register_shutdown_function(array($this, 'close')); + register_shutdown_function([$this, 'close']); $this->initialized = true; } @@ -70,9 +72,7 @@ class BufferHandler extends AbstractHandler } if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } $this->buffer[] = $record; @@ -112,6 +112,6 @@ class BufferHandler extends AbstractHandler public function clear() { $this->bufferSize = 0; - $this->buffer = array(); + $this->buffer = []; } } diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 785cb0c..4c6be69 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\ChromePHPFormatter; +use Monolog\Formatter\FormatterInterface; use Monolog\Logger; /** @@ -32,7 +33,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+) */ @@ -49,11 +50,11 @@ class ChromePHPHandler extends AbstractProcessingHandler */ protected static $overflowed = false; - protected static $json = array( + protected static $json = [ 'version' => self::VERSION, - 'columns' => array('label', 'log', 'backtrace', 'type'), - 'rows' => array(), - ); + 'columns' => ['label', 'log', 'backtrace', 'type'], + 'rows' => [], + ]; protected static $sendHeaders = true; @@ -74,7 +75,7 @@ class ChromePHPHandler extends AbstractProcessingHandler */ public function handleBatch(array $records) { - $messages = array(); + $messages = []; foreach ($records as $record) { if ($record['level'] < $this->level) { @@ -93,7 +94,7 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new ChromePHPFormatter(); } @@ -131,7 +132,7 @@ class ChromePHPHandler extends AbstractProcessingHandler return; } - self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + self::$json['request_uri'] = $_SERVER['REQUEST_URI'] ?? ''; } $json = @json_encode(self::$json); @@ -139,15 +140,15 @@ class ChromePHPHandler extends AbstractProcessingHandler if (strlen($data) > 240 * 1024) { self::$overflowed = true; - $record = array( + $record = [ 'message' => 'Incomplete logs, chrome header size limit reached', - 'context' => array(), + 'context' => [], 'level' => Logger::WARNING, 'level_name' => Logger::getLevelName(Logger::WARNING), 'channel' => 'monolog', - 'datetime' => new \DateTime(), - 'extra' => array(), - ); + 'datetime' => new \DateTimeImmutable(), + 'extra' => [], + ]; self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); $json = @json_encode(self::$json); $data = base64_encode(utf8_encode($json)); @@ -173,39 +174,13 @@ class ChromePHPHandler extends AbstractProcessingHandler /** * Verifies if the headers are accepted by the current user agent - * - * @return Boolean */ - protected function headersAccepted() + protected function headersAccepted(): bool { if (empty($_SERVER['HTTP_USER_AGENT'])) { return false; } - return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']); - } - - /** - * BC getter for the sendHeaders property that has been made static - */ - public function __get($property) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - return static::$sendHeaders; - } - - /** - * BC setter for the sendHeaders property that has been made static - */ - public function __set($property, $value) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - static::$sendHeaders = $value; + return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']) === 1; } } diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index cc98697..e0603f3 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\JsonFormatter; use Monolog\Logger; @@ -23,15 +24,15 @@ class CouchDBHandler extends AbstractProcessingHandler { private $options; - public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true) + public function __construct(array $options = [], $level = Logger::DEBUG, $bubble = true) { - $this->options = array_merge(array( + $this->options = array_merge([ 'host' => 'localhost', 'port' => 5984, 'dbname' => 'logger', 'username' => null, 'password' => null, - ), $options); + ], $options); parent::__construct($level, $bubble); } @@ -47,17 +48,17 @@ class CouchDBHandler extends AbstractProcessingHandler } $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; - $context = stream_context_create(array( - 'http' => array( + $context = stream_context_create([ + 'http' => [ 'method' => 'POST', 'content' => $record['formatted'], 'ignore_errors' => true, 'max_redirects' => 0, 'header' => 'Content-type: application/json', - ), - )); + ], + ]); - if (false === @file_get_contents($url, null, $context)) { + if (false === @file_get_contents($url, false, $context)) { throw new \RuntimeException(sprintf('Could not connect to %s', $url)); } } @@ -65,7 +66,7 @@ class CouchDBHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); } diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 96b3ca0..ab6e007 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -26,7 +26,7 @@ class CubeHandler extends AbstractProcessingHandler private $scheme; private $host; private $port; - private $acceptedSchemes = array('http', 'udp'); + private $acceptedSchemes = ['http', 'udp']; /** * Create a Cube handler @@ -105,7 +105,7 @@ class CubeHandler extends AbstractProcessingHandler { $date = $record['datetime']; - $data = array('time' => $date->format('Y-m-d\TH:i:s.uO')); + $data = ['time' => $date->format('Y-m-d\TH:i:s.uO')]; unset($record['datetime']); if (isset($record['context']['type'])) { @@ -141,10 +141,10 @@ class CubeHandler extends AbstractProcessingHandler } curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); - curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array( + curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen('['.$data.']'), - )); + ]); Curl\Util::execute($this->httpConnection, 5, false); } diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 48d30b3..b0bec3d 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -13,7 +13,7 @@ namespace Monolog\Handler\Curl; class Util { - private static $retriableErrorCodes = array( + private static $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, CURLE_HTTP_NOT_FOUND, @@ -21,7 +21,7 @@ class Util CURLE_OPERATION_TIMEOUTED, CURLE_HTTP_POST_ERROR, CURLE_SSL_CONNECT_ERROR, - ); + ]; /** * Executes a CURL request with optional retries and exception on failure diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 7778c22..235b3b8 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -81,7 +81,6 @@ class DeduplicationHandler extends BufferHandler foreach ($this->buffer as $record) { if ($record['level'] >= $this->deduplicationLevel) { - $passthru = $passthru || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); @@ -139,13 +138,13 @@ class DeduplicationHandler extends BufferHandler $handle = fopen($this->deduplicationStore, 'rw+'); flock($handle, LOCK_EX); - $validLogs = array(); + $validLogs = []; $timestampValidity = time() - $this->time; while (!feof($handle)) { $log = fgets($handle); - if (substr($log, 0, 10) >= $timestampValidity) { + if ($log && substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index b91ffec..13a08ee 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Logger; use Monolog\Formatter\NormalizerFormatter; +use Monolog\Formatter\FormatterInterface; use Doctrine\CouchDB\CouchDBClient; /** @@ -38,7 +39,7 @@ class DoctrineCouchDBHandler extends AbstractProcessingHandler $this->client->postDocument($record['formatted']); } - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter; } diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 237b71f..a6991fa 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Aws\Sdk; use Aws\DynamoDb\DynamoDbClient; +use Monolog\Formatter\FormatterInterface; use Aws\DynamoDb\Marshaler; use Monolog\Formatter\ScalarFormatter; use Monolog\Logger; @@ -80,10 +81,10 @@ class DynamoDbHandler extends AbstractProcessingHandler $formatted = $this->client->formatAttributes($filtered); } - $this->client->putItem(array( + $this->client->putItem([ 'TableName' => $this->table, 'Item' => $formatted, - )); + ]); } /** @@ -100,7 +101,7 @@ class DynamoDbHandler extends AbstractProcessingHandler /** * {@inheritdoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new ScalarFormatter(self::DATE_FORMAT); } diff --git a/src/Monolog/Handler/ElasticSearchHandler.php b/src/Monolog/Handler/ElasticSearchHandler.php index 8196740..fbb999f 100644 --- a/src/Monolog/Handler/ElasticSearchHandler.php +++ b/src/Monolog/Handler/ElasticSearchHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -43,7 +43,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler /** * @var array Handler config options */ - protected $options = array(); + protected $options = []; /** * @param Client $client Elastica Client object @@ -51,16 +51,16 @@ class ElasticSearchHandler extends AbstractProcessingHandler * @param int $level The minimum logging level at which this handler will be triggered * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true) + public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, $bubble = true) { parent::__construct($level, $bubble); $this->client = $client; $this->options = array_merge( - array( + [ 'index' => 'monolog', // Elastic index name 'type' => 'record', // Elastic document type 'ignore_error' => false, // Suppress Elastica exceptions - ), + ], $options ); } @@ -70,13 +70,13 @@ class ElasticSearchHandler extends AbstractProcessingHandler */ protected function write(array $record) { - $this->bulkSend(array($record['formatted'])); + $this->bulkSend([$record['formatted']]); } /** * {@inheritdoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { if ($formatter instanceof ElasticaFormatter) { return parent::setFormatter($formatter); @@ -96,7 +96,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new ElasticaFormatter($this->options['index'], $this->options['type']); } diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 1447a58..2c80139 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; use Monolog\Logger; /** @@ -51,16 +52,16 @@ class ErrorLogHandler extends AbstractProcessingHandler */ public static function getAvailableTypes() { - return array( + return [ self::OPERATING_SYSTEM, self::SAPI, - ); + ]; } /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%'); } @@ -70,13 +71,14 @@ class ErrorLogHandler extends AbstractProcessingHandler */ protected function write(array $record) { - if ($this->expandNewlines) { - $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); - foreach ($lines as $line) { - error_log($line, $this->messageType); - } - } else { + if (!$this->expandNewlines) { error_log((string) $record['formatted'], $this->messageType); + return; + } + + $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); + foreach ($lines as $line) { + error_log($line, $this->messageType); } } } diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 2a0f7fd..da0634a 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -21,8 +21,10 @@ use Monolog\Logger; * @author Hennadiy Verkh * @author Jordi Boggiano <j.boggiano@seld.be> */ -class FilterHandler extends AbstractHandler +class FilterHandler extends Handler implements ProcessableHandlerInterface { + use ProcessableHandlerTrait; + /** * Handler or factory callable($record, $this) * @@ -64,7 +66,7 @@ class FilterHandler extends AbstractHandler /** * @return array */ - public function getAcceptedLevels() + public function getAcceptedLevels(): array { return array_flip($this->acceptedLevels); } @@ -90,7 +92,7 @@ class FilterHandler extends AbstractHandler /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return isset($this->acceptedLevels[$record['level']]); } @@ -98,7 +100,7 @@ class FilterHandler extends AbstractHandler /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; @@ -113,9 +115,7 @@ class FilterHandler extends AbstractHandler } if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } $this->handler->handle($record); @@ -128,7 +128,7 @@ class FilterHandler extends AbstractHandler */ public function handleBatch(array $records) { - $filtered = array(); + $filtered = []; foreach ($records as $record) { if ($this->isHandling($record)) { $filtered[] = $record; diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index c3e42ef..f9cab61 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 2a2a64d..63a14cb 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -42,7 +42,7 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any * @param array $channelToActionLevel An array that maps channel names to action levels. */ - public function __construct($defaultActionLevel, $channelToActionLevel = array()) + public function __construct($defaultActionLevel, $channelToActionLevel = []) { $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel); $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); diff --git a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 6e63085..d0ebd84 100644 --- a/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index d1dcaac..f0151d1 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -27,13 +27,15 @@ use Monolog\Logger; * * @author Jordi Boggiano <j.boggiano@seld.be> */ -class FingersCrossedHandler extends AbstractHandler +class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface { + use ProcessableHandlerTrait; + protected $handler; protected $activationStrategy; protected $buffering = true; protected $bufferSize; - protected $buffer = array(); + protected $buffer = []; protected $stopBuffering; protected $passthruLevel; @@ -74,7 +76,7 @@ class FingersCrossedHandler extends AbstractHandler /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return true; } @@ -96,18 +98,16 @@ class FingersCrossedHandler extends AbstractHandler } } $this->handler->handleBatch($this->buffer); - $this->buffer = array(); + $this->buffer = []; } /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } if ($this->buffering) { @@ -137,7 +137,7 @@ class FingersCrossedHandler extends AbstractHandler }); if (count($this->buffer) > 0) { $this->handler->handleBatch($this->buffer); - $this->buffer = array(); + $this->buffer = []; } } } @@ -157,7 +157,7 @@ class FingersCrossedHandler extends AbstractHandler */ public function clear() { - $this->buffer = array(); + $this->buffer = []; $this->reset(); } } diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index fee4795..ac7230c 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\WildfireFormatter; +use Monolog\Formatter\FormatterInterface; /** * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. @@ -60,26 +61,24 @@ class FirePHPHandler extends AbstractProcessingHandler * @param string $message Log message * @return array Complete header string ready for the client as key and message as value */ - protected function createHeader(array $meta, $message) + protected function createHeader(array $meta, string $message): array { $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); - return array($header => $message); + return [$header => $message]; } /** * Creates message header from record * * @see createHeader() - * @param array $record - * @return string */ - protected function createRecordHeader(array $record) + protected function createRecordHeader(array $record): array { // Wildfire is extensible to support multiple protocols & plugins in a single request, // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. return $this->createHeader( - array(1, 1, 1, self::$messageIndex++), + [1, 1, 1, self::$messageIndex++], $record['formatted'] ); } @@ -87,7 +86,7 @@ class FirePHPHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new WildfireFormatter(); } @@ -103,9 +102,9 @@ class FirePHPHandler extends AbstractProcessingHandler { // Initial payload consists of required headers for Wildfire return array_merge( - $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI), - $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI), - $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI) + $this->createHeader(['Protocol', 1], self::PROTOCOL_URI), + $this->createHeader([1, 'Structure', 1], self::STRUCTURE_URI), + $this->createHeader([1, 'Plugin', 1], self::PLUGIN_URI) ); } @@ -168,28 +167,4 @@ class FirePHPHandler extends AbstractProcessingHandler return isset($_SERVER['HTTP_X_FIREPHP_VERSION']); } - - /** - * BC getter for the sendHeaders property that has been made static - */ - public function __get($property) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - return static::$sendHeaders; - } - - /** - * BC setter for the sendHeaders property that has been made static - */ - public function __set($property, $value) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - static::$sendHeaders = $value; - } } diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index c43c013..748100b 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Logger; @@ -63,7 +64,7 @@ class FleepHookHandler extends SocketHandler * * @return LineFormatter */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter(null, null, true, true); } @@ -117,9 +118,9 @@ class FleepHookHandler extends SocketHandler */ private function buildContent($record) { - $dataArray = array( + $dataArray = [ 'message' => $record['formatted'], - ); + ]; return http_build_query($dataArray); } diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index dd9a361..67d1291 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -53,7 +53,7 @@ class FlowdockHandler extends SocketHandler /** * {@inheritdoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { if (!$formatter instanceof FlowdockFormatter) { throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); @@ -65,9 +65,9 @@ class FlowdockHandler extends SocketHandler /** * Gets the default formatter. * - * @return FormatterInterface + * @suppress PhanTypeMissingReturn */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); } diff --git a/src/Monolog/Handler/FormattableHandlerInterface.php b/src/Monolog/Handler/FormattableHandlerInterface.php new file mode 100644 index 0000000..fc1693c --- /dev/null +++ b/src/Monolog/Handler/FormattableHandlerInterface.php @@ -0,0 +1,37 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; + +/** + * Interface to describe loggers that have a formatter + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +interface FormattableHandlerInterface +{ + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + * @return HandlerInterface self + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface; + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(): FormatterInterface; +} diff --git a/src/Monolog/Handler/FormattableHandlerTrait.php b/src/Monolog/Handler/FormattableHandlerTrait.php new file mode 100644 index 0000000..2b7e56f --- /dev/null +++ b/src/Monolog/Handler/FormattableHandlerTrait.php @@ -0,0 +1,60 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; + +/** + * Helper trait for implementing FormattableInterface + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +trait FormattableHandlerTrait +{ + /** + * @var FormatterInterface + */ + protected $formatter; + + /** + * {@inheritdoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->formatter = $formatter; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getFormatter(): FormatterInterface + { + if (!$this->formatter) { + $this->formatter = $this->getDefaultFormatter(); + } + + return $this->formatter; + } + + /** + * Gets the default formatter. + * + * @return FormatterInterface + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new LineFormatter(); + } +} diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index d3847d8..b5c3a8c 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,12 +11,10 @@ namespace Monolog\Handler; -use Gelf\IMessagePublisher; use Gelf\PublisherInterface; -use Gelf\Publisher; -use InvalidArgumentException; use Monolog\Logger; use Monolog\Formatter\GelfMessageFormatter; +use Monolog\Formatter\FormatterInterface; /** * Handler to send messages to a Graylog2 (http://www.graylog2.org) server @@ -27,23 +25,19 @@ use Monolog\Formatter\GelfMessageFormatter; class GelfHandler extends AbstractProcessingHandler { /** - * @var Publisher the publisher object that sends the message to the server + * @var PublisherInterface|null the publisher object that sends the message to the server */ protected $publisher; /** - * @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object - * @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 PublisherInterface $publisher a publisher object + * @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($publisher, $level = Logger::DEBUG, $bubble = true) + public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, $bubble = true) { parent::__construct($level, $bubble); - if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) { - throw new InvalidArgumentException('Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance'); - } - $this->publisher = $publisher; } @@ -66,7 +60,7 @@ class GelfHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new GelfMessageFormatter(); } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 663f5a9..ef1485f 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -18,8 +18,10 @@ use Monolog\Formatter\FormatterInterface; * * @author Lenar Lõhmus <lenar@city.ee> */ -class GroupHandler extends AbstractHandler +class GroupHandler extends Handler implements ProcessableHandlerInterface { + use ProcessableHandlerTrait; + protected $handlers; /** @@ -41,7 +43,7 @@ class GroupHandler extends AbstractHandler /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { @@ -55,12 +57,10 @@ class GroupHandler extends AbstractHandler /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -76,7 +76,7 @@ class GroupHandler extends AbstractHandler public function handleBatch(array $records) { if ($this->processors) { - $processed = array(); + $processed = []; foreach ($records as $record) { foreach ($this->processors as $processor) { $processed[] = call_user_func($processor, $record); diff --git a/src/Monolog/Handler/Handler.php b/src/Monolog/Handler/Handler.php new file mode 100644 index 0000000..347e7b7 --- /dev/null +++ b/src/Monolog/Handler/Handler.php @@ -0,0 +1,53 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base Handler class providing basic close() support as well as handleBatch + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +abstract class Handler implements HandlerInterface +{ + /** + * {@inheritdoc} + */ + public function handleBatch(array $records) + { + foreach ($records as $record) { + $this->handle($record); + } + } + + /** + * {@inheritdoc} + */ + public function close() + { + } + + public function __destruct() + { + try { + $this->close(); + } catch (\Throwable $e) { + // do nothing + } + } + + public function __sleep() + { + $this->close(); + + return array_keys(get_object_vars($this)); + } +} diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index d920c4b..472fd31 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,8 +11,6 @@ namespace Monolog\Handler; -use Monolog\Formatter\FormatterInterface; - /** * Interface that all Monolog Handlers must implement * @@ -33,7 +31,7 @@ interface HandlerInterface * * @return Boolean */ - public function isHandling(array $record); + public function isHandling(array $record): bool; /** * Handles a record. @@ -49,7 +47,7 @@ interface HandlerInterface * @return Boolean true means that this handler handled the record, and that bubbling is not permitted. * false means the record was either not processed or that this handler allows bubbling. */ - public function handle(array $record); + public function handle(array $record): bool; /** * Handles a set of records at once. @@ -59,32 +57,12 @@ interface HandlerInterface public function handleBatch(array $records); /** - * Adds a processor in the stack. - * - * @param callable $callback - * @return self - */ - public function pushProcessor($callback); - - /** - * Removes the processor on top of the stack and returns it. - * - * @return callable - */ - public function popProcessor(); - - /** - * Sets the formatter. + * Closes the handler. * - * @param FormatterInterface $formatter - * @return self - */ - public function setFormatter(FormatterInterface $formatter); - - /** - * Gets the formatter. + * This will be called automatically when the object is destroyed if you extend Monolog\Handler\Handler * - * @return FormatterInterface + * Implementations have to be idempotent (i.e. it should be possible to call close several times without breakage) + * and ideally handlers should be able to reopen themselves on handle() after they have been closed. */ - public function getFormatter(); + public function close(); } diff --git a/src/Monolog/Handler/HandlerWrapper.php b/src/Monolog/Handler/HandlerWrapper.php index e540d80..28fe57d 100644 --- a/src/Monolog/Handler/HandlerWrapper.php +++ b/src/Monolog/Handler/HandlerWrapper.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -30,7 +30,7 @@ use Monolog\Formatter\FormatterInterface; * * @author Alexey Karapetov <alexey@karapetov.com> */ -class HandlerWrapper implements HandlerInterface +class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface { /** * @var HandlerInterface @@ -49,7 +49,7 @@ class HandlerWrapper implements HandlerInterface /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return $this->handler->isHandling($record); } @@ -57,7 +57,7 @@ class HandlerWrapper implements HandlerInterface /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { return $this->handler->handle($record); } @@ -73,36 +73,58 @@ class HandlerWrapper implements HandlerInterface /** * {@inheritdoc} */ - public function pushProcessor($callback) + public function close() { - $this->handler->pushProcessor($callback); + return $this->handler->close(); + } - return $this; + /** + * {@inheritdoc} + */ + public function pushProcessor(callable $callback): HandlerInterface + { + if ($this->handler instanceof ProcessableHandlerInterface) { + $this->handler->pushProcessor($callback); + + return $this; + } + + throw new \LogicException('The wrapped handler does not implement ' . ProcessableHandlerInterface::class); } /** * {@inheritdoc} */ - public function popProcessor() + public function popProcessor(): callable { - return $this->handler->popProcessor(); + if ($this->handler instanceof ProcessableHandlerInterface) { + return $this->handler->popProcessor(); + } + + throw new \LogicException('The wrapped handler does not implement ' . ProcessableHandlerInterface::class); } /** * {@inheritdoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->handler->setFormatter($formatter); + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); + } - return $this; + throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); } /** * {@inheritdoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->handler->getFormatter(); + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter($formatter); + } + + throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); } } diff --git a/src/Monolog/Handler/HipChatHandler.php b/src/Monolog/Handler/HipChatHandler.php index 73049f3..98441f3 100644 --- a/src/Monolog/Handler/HipChatHandler.php +++ b/src/Monolog/Handler/HipChatHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -16,12 +16,13 @@ use Monolog\Logger; /** * Sends notifications through the hipchat api to a hipchat room * + * This handler only supports the API v2 + * * Notes: * API token - HipChat API token * Room - HipChat Room Id or name, where messages are sent * Name - Name used to send the message (from) * notify - Should the message trigger a notification in the clients - * version - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2) * * @author Rafael Dohms <rafael@doh.ms> * @see https://www.hipchat.com/docs/api @@ -29,16 +30,6 @@ use Monolog\Logger; class HipChatHandler extends SocketHandler { /** - * Use API version 1 - */ - const API_V1 = 'v1'; - - /** - * Use API version v2 - */ - const API_V2 = 'v2'; - - /** * The maximum allowed length for the name used in the "from" field. */ const MAXIMUM_NAME_LENGTH = 15; @@ -79,28 +70,18 @@ class HipChatHandler extends SocketHandler private $host; /** - * @var string + * @param string $token HipChat API Token + * @param string $room The room that should be alerted of the message (Id or Name) + * @param string $name Name used in the "from" field. + * @param bool $notify Trigger a notification in clients or not + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $useSSL Whether to connect via SSL. + * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) + * @param string $host The HipChat server hostname. */ - private $version; - - /** - * @param string $token HipChat API Token - * @param string $room The room that should be alerted of the message (Id or Name) - * @param string $name Name used in the "from" field. - * @param bool $notify Trigger a notification in clients or not - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param bool $useSSL Whether to connect via SSL. - * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) - * @param string $host The HipChat server hostname. - * @param string $version The HipChat API version (default HipChatHandler::API_V1) - */ - public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1) + public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com') { - if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { - throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); - } - $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80'; parent::__construct($connectionString, $level, $bubble); @@ -110,7 +91,6 @@ class HipChatHandler extends SocketHandler $this->room = $room; $this->format = $format; $this->host = $host; - $this->version = $version; } /** @@ -134,14 +114,12 @@ class HipChatHandler extends SocketHandler */ private function buildContent($record) { - $dataArray = array( - 'notify' => $this->version == self::API_V1 ? - ($this->notify ? 1 : 0) : - ($this->notify ? 'true' : 'false'), + $dataArray = [ + 'notify' => $this->notify ? 'true' : 'false', 'message' => $record['formatted'], 'message_format' => $this->format, 'color' => $this->getAlertColor($record['level']), - ); + ]; if (!$this->validateStringLength($dataArray['message'], static::MAXIMUM_MESSAGE_LENGTH)) { if (function_exists('mb_substr')) { @@ -151,14 +129,9 @@ class HipChatHandler extends SocketHandler } } - // if we are using the legacy API then we need to send some additional information - if ($this->version == self::API_V1) { - $dataArray['room_id'] = $this->room; - } - // append the sender name if it is set // always append it if we use the v1 api (it is required in v1) - if ($this->version == self::API_V1 || $this->name !== null) { + if ($this->name !== null) { $dataArray['from'] = (string) $this->name; } @@ -173,13 +146,9 @@ class HipChatHandler extends SocketHandler */ private function buildHeader($content) { - if ($this->version == self::API_V1) { - $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n"; - } else { - // needed for rooms with special (spaces, etc) characters in the name - $room = rawurlencode($this->room); - $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n"; - } + // needed for rooms with special (spaces, etc) characters in the name + $room = rawurlencode($this->room); + $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n"; $header .= "Host: {$this->host}\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; @@ -259,9 +228,9 @@ class HipChatHandler extends SocketHandler private function combineRecords($records) { $batchRecord = null; - $batchRecords = array(); - $messages = array(); - $formattedMessages = array(); + $batchRecords = []; + $messages = []; + $formattedMessages = []; $level = 0; $levelName = null; $datetime = null; @@ -283,12 +252,12 @@ class HipChatHandler extends SocketHandler $formattedMessages[] = $this->getFormatter()->format($record); $formattedMessageStr = implode('', $formattedMessages); - $batchRecord = array( + $batchRecord = [ 'message' => $messageStr, 'formatted' => $formattedMessageStr, - 'context' => array(), - 'extra' => array(), - ); + 'context' => [], + 'extra' => [], + ]; if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) { // Pop the last message and implode the remaining messages @@ -298,8 +267,8 @@ class HipChatHandler extends SocketHandler $batchRecord['formatted'] = implode('', $formattedMessages); $batchRecords[] = $batchRecord; - $messages = array($lastMessage); - $formattedMessages = array($lastFormattedMessage); + $messages = [$lastMessage]; + $formattedMessages = [$lastFormattedMessage]; $batchRecord = null; } @@ -313,11 +282,11 @@ class HipChatHandler extends SocketHandler foreach ($batchRecords as &$batchRecord) { $batchRecord = array_merge( $batchRecord, - array( + [ 'level' => $level, 'level_name' => $levelName, 'datetime' => $datetime, - ) + ] ); } diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index d60a3c8..46792ee 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -48,11 +48,11 @@ class IFTTTHandler extends AbstractProcessingHandler */ public function write(array $record) { - $postData = array( + $postData = [ "value1" => $record["channel"], "value2" => $record["level_name"], "value3" => $record["message"], - ); + ]; $postString = json_encode($postData); $ch = curl_init(); @@ -60,9 +60,9 @@ class IFTTTHandler extends AbstractProcessingHandler curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postString); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( + curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", - )); + ]); Curl\Util::execute($ch); } diff --git a/src/Monolog/Handler/LogEntriesHandler.php b/src/Monolog/Handler/LogEntriesHandler.php index 494c605..c74b9d2 100644 --- a/src/Monolog/Handler/LogEntriesHandler.php +++ b/src/Monolog/Handler/LogEntriesHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index bcd62e1..544e7c7 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LogglyFormatter; /** @@ -29,7 +30,7 @@ class LogglyHandler extends AbstractProcessingHandler protected $token; - protected $tag = array(); + protected $tag = []; public function __construct($token, $level = Logger::DEBUG, $bubble = true) { @@ -44,14 +45,14 @@ class LogglyHandler extends AbstractProcessingHandler public function setTag($tag) { - $tag = !empty($tag) ? $tag : array(); - $this->tag = is_array($tag) ? $tag : array($tag); + $tag = !empty($tag) ? $tag : []; + $this->tag = is_array($tag) ? $tag : [$tag]; } public function addTag($tag) { if (!empty($tag)) { - $tag = is_array($tag) ? $tag : array($tag); + $tag = is_array($tag) ? $tag : [$tag]; $this->tag = array_unique(array_merge($this->tag, $tag)); } } @@ -78,7 +79,7 @@ class LogglyHandler extends AbstractProcessingHandler { $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token); - $headers = array('Content-Type: application/json'); + $headers = ['Content-Type: application/json']; if (!empty($this->tag)) { $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag); @@ -95,7 +96,7 @@ class LogglyHandler extends AbstractProcessingHandler Curl\Util::execute($ch); } - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LogglyFormatter(); } diff --git a/src/Monolog/Handler/LogmaticHandler.php b/src/Monolog/Handler/LogmaticHandler.php new file mode 100644 index 0000000..9747220 --- /dev/null +++ b/src/Monolog/Handler/LogmaticHandler.php @@ -0,0 +1,88 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LogmaticFormatter; + +/** + * @author Julien Breux <julien.breux@gmail.com> + */ +class LogmaticHandler extends SocketHandler +{ + /** + * @var string + */ + private $logToken; + + /** + * @var string + */ + private $hostname; + + /** + * @var string + */ + private $appname; + + /** + * @param string $token Log token supplied by Logmatic. + * @param string $hostname Host name supplied by Logmatic. + * @param string $appname Application name supplied by Logmatic. + * @param bool $useSSL Whether or not SSL encryption should be used. + * @param int|string $level The minimum logging level to trigger this handler. + * @param bool $bubble Whether or not messages that are handled should bubble up the stack. + * + * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing + */ + public function __construct(string $token, string $hostname = '', string $appname = '', bool $useSSL = true, $level = Logger::DEBUG, bool $bubble = true) + { + if ($useSSL && !extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP extension is required to use SSL encrypted connection for LogmaticHandler'); + } + + $endpoint = $useSSL ? 'ssl://api.logmatic.io:10515' : 'api.logmatic.io:10514'; + $endpoint .= '/v1/'; + + parent::__construct($endpoint, $level, $bubble); + + $this->logToken = $token; + $this->hostname = $hostname; + $this->appname = $appname; + } + + /** + * {@inheritdoc} + */ + protected function generateDataStream($record): string + { + return $this->logToken . ' ' . $record['formatted']; + } + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + $formatter = new LogmaticFormatter(); + + if (!empty($this->hostname)) { + $formatter->setHostname($this->hostname); + } + if (!empty($this->appname)) { + $formatter->setAppname($this->appname); + } + + return $formatter; + } +} diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 9e23283..634fbc1 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,6 +11,9 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\HtmlFormatter; + /** * Base class for all mail handlers * @@ -23,7 +26,7 @@ abstract class MailHandler extends AbstractProcessingHandler */ public function handleBatch(array $records) { - $messages = array(); + $messages = []; foreach ($records as $record) { if ($record['level'] < $this->level) { @@ -43,14 +46,14 @@ abstract class MailHandler extends AbstractProcessingHandler * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content */ - abstract protected function send($content, array $records); + abstract protected function send(string $content, array $records); /** * {@inheritdoc} */ protected function write(array $record) { - $this->send((string) $record['formatted'], array($record)); + $this->send((string) $record['formatted'], [$record]); } protected function getHighestRecord(array $records) @@ -64,4 +67,19 @@ abstract class MailHandler extends AbstractProcessingHandler return $highestRecord; } + + protected function isHtmlBody($body) + { + return substr($body, 0, 1) === '<'; + } + + /** + * Gets the default formatter. + * + * @return FormatterInterface + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new HtmlFormatter(); + } } diff --git a/src/Monolog/Handler/MandrillHandler.php b/src/Monolog/Handler/MandrillHandler.php index ab95924..066c649 100644 --- a/src/Monolog/Handler/MandrillHandler.php +++ b/src/Monolog/Handler/MandrillHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -46,10 +46,15 @@ class MandrillHandler extends MailHandler /** * {@inheritdoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records) { + $mime = null; + if ($this->isHtmlBody($content)) { + $mime = 'text/html'; + } + $message = clone $this->message; - $message->setBody($content); + $message->setBody($content, $mime); $message->setDate(time()); $ch = curl_init(); @@ -57,11 +62,11 @@ class MandrillHandler extends MailHandler curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'key' => $this->apiKey, 'raw_message' => (string) $message, 'async' => false, - ))); + ])); Curl\Util::execute($ch); } diff --git a/src/Monolog/Handler/MissingExtensionException.php b/src/Monolog/Handler/MissingExtensionException.php index 4724a7e..1554b34 100644 --- a/src/Monolog/Handler/MissingExtensionException.php +++ b/src/Monolog/Handler/MissingExtensionException.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index 56fe755..f302d31 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,49 +11,75 @@ namespace Monolog\Handler; +use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Manager; +use MongoDB\Client; use Monolog\Logger; -use Monolog\Formatter\NormalizerFormatter; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\MongoDBFormatter; /** * Logs to a MongoDB database. * - * usage example: + * Usage example: * - * $log = new Logger('application'); - * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod"); + * $log = new \Monolog\Logger('application'); + * $client = new \MongoDB\Client('mongodb://localhost:27017'); + * $mongodb = new \Monolog\Handler\MongoDBHandler($client, 'logs', 'prod'); * $log->pushHandler($mongodb); * - * @author Thomas Tourlourat <thomas@tourlourat.com> + * The above examples uses the MongoDB PHP library's client class; however, the + * MongoDB\Driver\Manager class from ext-mongodb is also supported. */ class MongoDBHandler extends AbstractProcessingHandler { - protected $mongoCollection; + private $collection; + private $manager; + private $namespace; - public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true) + /** + * Constructor. + * + * @param Client|Manager $mongodb MongoDB library or driver client + * @param string $database Database name + * @param string $collection Collection name + * @param int $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct($mongodb, $database, $collection, $level = Logger::DEBUG, $bubble = true) { - if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo || $mongo instanceof \MongoDB\Client)) { - throw new \InvalidArgumentException('MongoClient, Mongo or MongoDB\Client instance required'); + if (!($mongodb instanceof Client || $mongodb instanceof Manager)) { + throw new \InvalidArgumentException('MongoDB\Client or MongoDB\Driver\Manager instance required'); } - $this->mongoCollection = $mongo->selectCollection($database, $collection); + if ($mongodb instanceof Client) { + $this->collection = $mongodb->selectCollection($database, $collection); + } else { + $this->manager = $mongodb; + $this->namespace = $database . '.' . $collection; + } parent::__construct($level, $bubble); } protected function write(array $record) { - if ($this->mongoCollection instanceof \MongoDB\Collection) { - $this->mongoCollection->insertOne($record["formatted"]); - } else { - $this->mongoCollection->save($record["formatted"]); + if (isset($this->collection)) { + $this->collection->insertOne($record['formatted']); + } + + if (isset($this->manager, $this->namespace)) { + $bulk = new BulkWrite; + $bulk->insert($record["formatted"]); + $this->manager->executeBulkWrite($this->namespace, $bulk); } } /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { - return new NormalizerFormatter(); + return new MongoDBFormatter; } } diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index d7807fd..b597761 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -38,13 +38,13 @@ class NativeMailerHandler extends MailHandler * Optional headers for the message * @var array */ - protected $headers = array(); + protected $headers = []; /** * Optional parameters for the message * @var array */ - protected $parameters = array(); + protected $parameters = []; /** * The wordwrap length for the message @@ -56,7 +56,7 @@ class NativeMailerHandler extends MailHandler * The Content-type for the message * @var string */ - protected $contentType = 'text/plain'; + protected $contentType; /** * The encoding for the message @@ -75,7 +75,7 @@ class NativeMailerHandler extends MailHandler public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) { parent::__construct($level, $bubble); - $this->to = is_array($to) ? $to : array($to); + $this->to = (array) $to; $this->subject = $subject; $this->addHeader(sprintf('From: %s', $from)); $this->maxColumnWidth = $maxColumnWidth; @@ -115,12 +115,17 @@ class NativeMailerHandler extends MailHandler /** * {@inheritdoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records) { - $content = wordwrap($content, $this->maxColumnWidth); + $contentType = $this->getContentType() ?: ($this->isHtmlBody($content) ? 'text/html' : 'text/plain'); + + if ($contentType !== 'text/html') { + $content = wordwrap($content, $this->maxColumnWidth); + } + $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n"); - $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n"; - if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) { + $headers .= 'Content-type: ' . $contentType . '; charset=' . $this->getEncoding() . "\r\n"; + if ($contentType === 'text/html' && false === strpos($headers, 'MIME-Version:')) { $headers .= 'MIME-Version: 1.0' . "\r\n"; } diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 6718e9e..fb03778 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Logger; use Monolog\Formatter\NormalizerFormatter; +use Monolog\Formatter\FormatterInterface; /** * Class to record a log on a NewRelic application. @@ -195,7 +196,7 @@ class NewRelicHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter(); } diff --git a/src/Monolog/Handler/NoopHandler.php b/src/Monolog/Handler/NoopHandler.php new file mode 100644 index 0000000..8ee2b4c --- /dev/null +++ b/src/Monolog/Handler/NoopHandler.php @@ -0,0 +1,40 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * No-op + * + * This handler handles anything, but does nothing, and does not stop bubbling to the rest of the stack. + * This can be used for testing, or to disable a handler when overriding a configuration without + * influencing the rest of the stack. + * + * @author Roel Harbers <roelharbers@gmail.com> + */ +class NoopHandler extends Handler +{ + /** + * {@inheritdoc} + */ + public function isHandling(array $record): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function handle(array $record): bool + { + return false; + } +} diff --git a/src/Monolog/Handler/NullHandler.php b/src/Monolog/Handler/NullHandler.php index 4b84588..93678e8 100644 --- a/src/Monolog/Handler/NullHandler.php +++ b/src/Monolog/Handler/NullHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -21,20 +21,30 @@ use Monolog\Logger; * * @author Jordi Boggiano <j.boggiano@seld.be> */ -class NullHandler extends AbstractHandler +class NullHandler extends Handler { + private $level; + /** * @param int $level The minimum logging level at which this handler will be triggered */ - public function __construct($level = Logger::DEBUG) + public function __construct(int $level = Logger::DEBUG) + { + $this->level = $level; + } + + /** + * {@inheritdoc} + */ + public function isHandling(array $record): bool { - parent::__construct($level, false); + return $record['level'] >= $this->level; } /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($record['level'] < $this->level) { return false; diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 1f2076a..c2b7b3e 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,11 +11,11 @@ namespace Monolog\Handler; -use Exception; use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; use Monolog\Logger; use PhpConsole\Connector; -use PhpConsole\Handler; +use PhpConsole\Handler as VendorPhpConsoleHandler; use PhpConsole\Helper; /** @@ -32,17 +32,17 @@ use PhpConsole\Helper; * $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler())); * \Monolog\ErrorHandler::register($logger); * echo $undefinedVar; - * $logger->addDebug('SELECT * FROM users', array('db', 'time' => 0.012)); + * $logger->debug('SELECT * FROM users', array('db', 'time' => 0.012)); * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin */ class PHPConsoleHandler extends AbstractProcessingHandler { - private $options = array( + private $options = [ 'enabled' => true, // bool Is PHP Console server enabled - 'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with... - 'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled + 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... + 'debugTagsKeysInContext' => [0, 'tag'], // bool Is PHP Console server enabled 'useOwnErrorsHandler' => false, // bool Enable errors handling 'useOwnExceptionsHandler' => false, // bool Enable exceptions handling 'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths @@ -51,7 +51,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'headersLimit' => null, // int|null Set headers size limit for your web-server 'password' => null, // string|null Protect PHP Console connection by password 'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed - 'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') + 'ipMasks' => [], // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') 'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required) 'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings 'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level @@ -60,22 +60,22 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON 'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug 'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) - ); + ]; /** @var Connector */ private $connector; /** - * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details - * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param int $level - * @param bool $bubble - * @throws Exception + * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details + * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) + * @param int $level + * @param bool $bubble + * @throws \RuntimeException */ - public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true) + public function __construct(array $options = [], Connector $connector = null, $level = Logger::DEBUG, $bubble = true) { if (!class_exists('PhpConsole\Connector')) { - throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); + throw new \RuntimeException('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); } parent::__construct($level, $bubble); $this->options = $this->initOptions($options); @@ -86,7 +86,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); if ($wrongOptions) { - throw new Exception('Unknown options: ' . implode(', ', $wrongOptions)); + throw new \RuntimeException('Unknown options: ' . implode(', ', $wrongOptions)); } return array_replace($this->options, $options); @@ -107,7 +107,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler if ($this->options['enabled'] && $connector->isActiveClient()) { if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) { - $handler = Handler::getInstance(); + $handler = VendorPhpConsoleHandler::getInstance(); $handler->setHandleErrors($this->options['useOwnErrorsHandler']); $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']); $handler->start(); @@ -157,7 +157,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler return $this->options; } - public function handle(array $record) + public function handle(array $record): bool { if ($this->options['enabled'] && $this->connector->isActiveClient()) { return parent::handle($record); @@ -176,7 +176,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler { if ($record['level'] < Logger::NOTICE) { $this->handleDebugRecord($record); - } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) { + } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $this->handleExceptionRecord($record); } else { $this->handleErrorRecord($record); @@ -203,10 +203,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler $context = $record['context']; $this->connector->getErrorsDispatcher()->dispatchError( - isset($context['code']) ? $context['code'] : null, - isset($context['message']) ? $context['message'] : $record['message'], - isset($context['file']) ? $context['file'] : null, - isset($context['line']) ? $context['line'] : null, + $context['code'] ?? null, + $context['message'] ?? $record['message'], + $context['file'] ?? null, + $context['line'] ?? null, $this->options['classesPartialsTraceIgnore'] ); } @@ -235,7 +235,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('%message%'); } diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php new file mode 100644 index 0000000..8cf6087 --- /dev/null +++ b/src/Monolog/Handler/ProcessHandler.php @@ -0,0 +1,202 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Stores to STDIN of any process, specified by a command. + * + * Usage example: + * <pre> + * $log = new Logger('myLogger'); + * $log->pushHandler(new ProcessHandler('/usr/bin/php /var/www/monolog/someScript.php')); + * </pre> + * + * @author Kolja Zuelsdorf <koljaz@web.de> + */ +class ProcessHandler extends AbstractProcessingHandler +{ + /** + * Holds the process to receive data on its STDIN. + * + * @var resource|bool|null + */ + private $process; + + /** + * @var string + */ + private $command; + + /** + * @var string + */ + private $cwd; + + /** + * @var array + */ + private $pipes = []; + + /** + * @var array + */ + const DESCRIPTOR_SPEC = [ + 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from + 1 => ['pipe', 'w'], // STDOUT is a pipe that the child will write to + 2 => ['pipe', 'w'], // STDERR is a pipe to catch the any errors + ]; + + /** + * @param string $command Command for the process to start. Absolute paths are recommended, + * especially if you do not use the $cwd parameter. + * @param string|int $level The minimum logging level at which this handler will be triggered. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not. + * @param string $cwd "Current working directory" (CWD) for the process to be executed in. + * @throws \InvalidArgumentException + */ + public function __construct(string $command, $level = Logger::DEBUG, bool $bubble = true, string $cwd = null) + { + if ($command === '') { + throw new \InvalidArgumentException('The command argument must be a non-empty string.'); + } + if ($cwd === '') { + throw new \InvalidArgumentException('The optional CWD argument must be a non-empty string or null.'); + } + + parent::__construct($level, $bubble); + + $this->command = $command; + $this->cwd = $cwd; + } + + /** + * Writes the record down to the log of the implementing handler + * + * @param array $record + * @throws \UnexpectedValueException + * @return void + */ + protected function write(array $record) + { + $this->ensureProcessIsStarted(); + + $this->writeProcessInput($record['formatted']); + + $errors = $this->readProcessErrors(); + if (empty($errors) === false) { + throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors)); + } + } + + /** + * Makes sure that the process is actually started, and if not, starts it, + * assigns the stream pipes, and handles startup errors, if any. + * + * @return void + */ + private function ensureProcessIsStarted() + { + if (is_resource($this->process) === false) { + $this->startProcess(); + + $this->handleStartupErrors(); + } + } + + /** + * Starts the actual process and sets all streams to non-blocking. + * + * @return void + */ + private function startProcess() + { + $this->process = proc_open($this->command, self::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); + + foreach ($this->pipes as $pipe) { + stream_set_blocking($pipe, false); + } + } + + /** + * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any. + * + * @throws \UnexpectedValueException + * @return void + */ + private function handleStartupErrors() + { + $selected = $this->selectErrorStream(); + if (false === $selected) { + throw new \UnexpectedValueException('Something went wrong while selecting a stream.'); + } + + $errors = $this->readProcessErrors(); + + if (is_resource($this->process) === false || empty($errors) === false) { + throw new \UnexpectedValueException( + sprintf('The process "%s" could not be opened: ' . $errors, $this->command) + ); + } + } + + /** + * Selects the STDERR stream. + * + * @return int|bool + */ + protected function selectErrorStream() + { + $empty = []; + $errorPipes = [$this->pipes[2]]; + + return stream_select($errorPipes, $empty, $empty, 1); + } + + /** + * Reads the errors of the process, if there are any. + * + * @codeCoverageIgnore + * @return string Empty string if there are no errors. + */ + protected function readProcessErrors() + { + return stream_get_contents($this->pipes[2]); + } + + /** + * Writes to the input stream of the opened process. + * + * @codeCoverageIgnore + * @param $string + * @return void + */ + protected function writeProcessInput($string) + { + fwrite($this->pipes[0], (string) $string); + } + + /** + * {@inheritdoc} + */ + public function close() + { + if (is_resource($this->process)) { + foreach ($this->pipes as $pipe) { + fclose($pipe); + } + proc_close($this->process); + $this->process = null; + } + } +} diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php new file mode 100644 index 0000000..9556f98 --- /dev/null +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -0,0 +1,36 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Interface to describe loggers that have processors + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +interface ProcessableHandlerInterface +{ + /** + * Adds a processor in the stack. + * + * @param callable $callback + * @return HandlerInterface self + */ + public function pushProcessor(callable $callback): HandlerInterface; + + /** + * Removes the processor on top of the stack and returns it. + * + * @throws \LogicException In case the processor stack is empty + * @return callable + */ + public function popProcessor(): callable; +} diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php new file mode 100644 index 0000000..bba940e --- /dev/null +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -0,0 +1,62 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Helper trait for implementing ProcessableInterface + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +trait ProcessableHandlerTrait +{ + /** + * @var callable[] + */ + protected $processors = []; + + /** + * {@inheritdoc} + */ + public function pushProcessor(callable $callback): HandlerInterface + { + array_unshift($this->processors, $callback); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function popProcessor(): callable + { + if (!$this->processors) { + throw new \LogicException('You tried to pop from an empty processor stack.'); + } + + return array_shift($this->processors); + } + + /** + * Processes a record. + * + * @param array $record + * @return array + */ + protected function processRecord(array $record) + { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + + return $record; + } +} diff --git a/src/Monolog/Handler/PsrHandler.php b/src/Monolog/Handler/PsrHandler.php index 1ae8584..415b45f 100644 --- a/src/Monolog/Handler/PsrHandler.php +++ b/src/Monolog/Handler/PsrHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -43,7 +43,7 @@ class PsrHandler extends AbstractHandler /** * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index bba7200..b53ce6c 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -37,7 +37,7 @@ class PushoverHandler extends SocketHandler * @see https://pushover.net/api * @var array */ - private $parameterNames = array( + private $parameterNames = [ 'token' => true, 'user' => true, 'message' => true, @@ -51,18 +51,18 @@ class PushoverHandler extends SocketHandler 'retry' => true, 'expire' => true, 'callback' => true, - ); + ]; /** * Sounds the api supports by default * @see https://pushover.net/api#sounds * @var array */ - private $sounds = array( + private $sounds = [ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb', 'persistent', 'echo', 'updown', 'none', - ); + ]; /** * @param string $token Pushover api token @@ -110,13 +110,13 @@ class PushoverHandler extends SocketHandler $timestamp = $record['datetime']->getTimestamp(); - $dataArray = array( + $dataArray = [ 'token' => $this->token, 'user' => $this->user, 'message' => $message, 'title' => $this->title, 'timestamp' => $timestamp, - ); + ]; if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) { $dataArray['priority'] = 2; diff --git a/src/Monolog/Handler/RavenHandler.php b/src/Monolog/Handler/RavenHandler.php index 53a8b39..1c8e718 100644 --- a/src/Monolog/Handler/RavenHandler.php +++ b/src/Monolog/Handler/RavenHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -27,7 +27,7 @@ class RavenHandler extends AbstractProcessingHandler /** * Translates Monolog log levels to Raven log levels. */ - private $logLevels = array( + private $logLevels = [ Logger::DEBUG => Raven_Client::DEBUG, Logger::INFO => Raven_Client::INFO, Logger::NOTICE => Raven_Client::INFO, @@ -36,7 +36,7 @@ class RavenHandler extends AbstractProcessingHandler Logger::CRITICAL => Raven_Client::FATAL, Logger::ALERT => Raven_Client::FATAL, Logger::EMERGENCY => Raven_Client::FATAL, - ); + ]; /** * @var string should represent the current version of the calling @@ -92,7 +92,7 @@ class RavenHandler extends AbstractProcessingHandler }); // the other ones are added as a context item - $logs = array(); + $logs = []; foreach ($records as $r) { $logs[] = $this->processRecord($r); } @@ -133,10 +133,11 @@ class RavenHandler extends AbstractProcessingHandler */ protected function write(array $record) { + /** @var bool|null|array This is false, unless set below to null or an array of data, when we read the current user context */ $previousUserContext = false; - $options = array(); + $options = []; $options['level'] = $this->logLevels[$record['level']]; - $options['tags'] = array(); + $options['tags'] = []; if (!empty($record['extra']['tags'])) { $options['tags'] = array_merge($options['tags'], $record['extra']['tags']); unset($record['extra']['tags']); @@ -156,7 +157,7 @@ class RavenHandler extends AbstractProcessingHandler $options['logger'] = $record['channel']; } foreach ($this->getExtraParameters() as $key) { - foreach (array('extra', 'context') as $source) { + foreach (['extra', 'context'] as $source) { if (!empty($record[$source][$key])) { $options[$key] = $record[$source][$key]; unset($record[$source][$key]); @@ -179,14 +180,15 @@ class RavenHandler extends AbstractProcessingHandler $options['release'] = $this->release; } - if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $options['extra']['message'] = $record['formatted']; $this->ravenClient->captureException($record['context']['exception'], $options); } else { - $this->ravenClient->captureMessage($record['formatted'], array(), $options); + $this->ravenClient->captureMessage($record['formatted'], [], $options); } - if ($previousUserContext !== false) { + // restore the user context if it was modified + if (!is_bool($previousUserContext)) { $this->ravenClient->user_context($previousUserContext); } } @@ -194,7 +196,7 @@ class RavenHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('[%channel%] %message%'); } @@ -216,11 +218,11 @@ class RavenHandler extends AbstractProcessingHandler */ protected function getExtraParameters() { - return array('checksum', 'release', 'event_id'); + return ['checksum', 'release', 'event_id']; } /** - * @param string $value + * @param string $value * @return self */ public function setRelease($value) diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 590f996..e7ddb44 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; use Monolog\Logger; /** @@ -36,9 +37,9 @@ class RedisHandler extends AbstractProcessingHandler * @param string $key The key name to push records to * @param int $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param int $capSize Number of entries to limit list size to + * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ - public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false) + public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true, int $capSize = 0) { if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { throw new \InvalidArgumentException('Predis\Client or Redis instance required'); @@ -90,7 +91,7 @@ class RedisHandler extends AbstractProcessingHandler /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter(); } diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 6c8a3e3..5b6678e 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -12,7 +12,7 @@ namespace Monolog\Handler; use RollbarNotifier; -use Exception; +use Throwable; use Monolog\Logger; /** @@ -40,7 +40,7 @@ class RollbarHandler extends AbstractProcessingHandler */ protected $rollbarNotifier; - protected $levelMap = array( + protected $levelMap = [ Logger::DEBUG => 'debug', Logger::INFO => 'info', Logger::NOTICE => 'info', @@ -49,7 +49,7 @@ class RollbarHandler extends AbstractProcessingHandler Logger::CRITICAL => 'critical', Logger::ALERT => 'critical', Logger::EMERGENCY => 'critical', - ); + ]; /** * Records whether any log records have been added since the last flush of the rollbar notifier @@ -84,19 +84,19 @@ class RollbarHandler extends AbstractProcessingHandler } $context = $record['context']; - $payload = array(); + $payload = []; if (isset($context['payload'])) { $payload = $context['payload']; unset($context['payload']); } - $context = array_merge($context, $record['extra'], array( + $context = array_merge($context, $record['extra'], [ 'level' => $this->levelMap[$record['level']], 'monolog_level' => $record['level_name'], 'channel' => $record['channel'], 'datetime' => $record['datetime']->format('U'), - )); + ]); - if (isset($context['exception']) && $context['exception'] instanceof Exception) { + if (isset($context['exception']) && $context['exception'] instanceof Throwable) { $payload['level'] = $context['level']; $exception = $context['exception']; unset($context['exception']); diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 3b60b3d..a4a5ba4 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use InvalidArgumentException; use Monolog\Logger; /** @@ -47,7 +48,7 @@ class RotatingFileHandler extends StreamHandler { $this->filename = $filename; $this->maxFiles = (int) $maxFiles; - $this->nextRotation = new \DateTime('tomorrow'); + $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; $this->dateFormat = 'Y-m-d'; @@ -69,18 +70,16 @@ class RotatingFileHandler extends StreamHandler public function setFilenameFormat($filenameFormat, $dateFormat) { if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { - trigger_error( + throw new InvalidArgumentException( 'Invalid date format - format must be one of '. 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '. 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '. - 'date formats using slashes, underscores and/or dots instead of dashes.', - E_USER_DEPRECATED + 'date formats using slashes, underscores and/or dots instead of dashes.' ); } if (substr_count($filenameFormat, '{date}') === 0) { - trigger_error( - 'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.', - E_USER_DEPRECATED + throw new InvalidArgumentException( + 'Invalid filename format - format must contain at least `{date}`, because otherwise rotating is impossible.' ); } $this->filenameFormat = $filenameFormat; @@ -114,7 +113,7 @@ class RotatingFileHandler extends StreamHandler { // update filename $this->url = $this->getTimedFilename(); - $this->nextRotation = new \DateTime('tomorrow'); + $this->nextRotation = new \DateTimeImmutable('tomorrow'); // skip GC of old logs if files are unlimited if (0 === $this->maxFiles) { @@ -136,7 +135,8 @@ class RotatingFileHandler extends StreamHandler if (is_writable($file)) { // suppress errors here as unlink() might fail if two processes // are cleaning up/rotating at the same time - set_error_handler(function ($errno, $errstr, $errfile, $errline) {}); + set_error_handler(function ($errno, $errstr, $errfile, $errline) { + }); unlink($file); restore_error_handler(); } @@ -149,8 +149,8 @@ class RotatingFileHandler extends StreamHandler { $fileInfo = pathinfo($this->filename); $timedFilename = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], date($this->dateFormat)), + ['{filename}', '{date}'], + [$fileInfo['filename'], date($this->dateFormat)], $fileInfo['dirname'] . '/' . $this->filenameFormat ); @@ -165,8 +165,8 @@ class RotatingFileHandler extends StreamHandler { $fileInfo = pathinfo($this->filename); $glob = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], '*'), + ['{filename}', '{date}'], + [$fileInfo['filename'], '*'], $fileInfo['dirname'] . '/' . $this->filenameFormat ); if (!empty($fileInfo['extension'])) { diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 9509ae3..8a25cbb 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -25,8 +25,10 @@ namespace Monolog\Handler; * @author Bryan Davis <bd808@wikimedia.org> * @author Kunal Mehta <legoktm@gmail.com> */ -class SamplingHandler extends AbstractHandler +class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface { + use ProcessableHandlerTrait; + /** * @var callable|HandlerInterface $handler */ @@ -52,12 +54,12 @@ class SamplingHandler extends AbstractHandler } } - public function isHandling(array $record) + public function isHandling(array $record): bool { return $this->handler->isHandling($record); } - public function handle(array $record) + public function handle(array $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { // The same logic as in FingersCrossedHandler @@ -69,9 +71,7 @@ class SamplingHandler extends AbstractHandler } if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + $record = $this->processRecord($record); } $this->handler->handle($record); diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php new file mode 100644 index 0000000..7d82d94 --- /dev/null +++ b/src/Monolog/Handler/SendGridHandler.php @@ -0,0 +1,100 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html + * + * @author Ricardo Fontanelli <ricardo.fontanelli@hotmail.com> + */ +class SendGridHandler extends MailHandler +{ + /** + * The SendGrid API User + * @var string + */ + protected $apiUser; + + /** + * The SendGrid API Key + * @var string + */ + protected $apiKey; + + /** + * The email addresses to which the message will be sent + * @var string + */ + protected $from; + + /** + * The email addresses to which the message will be sent + * @var array + */ + protected $to; + + /** + * The subject of the email + * @var string + */ + protected $subject; + + /** + * @param string $apiUser The SendGrid API User + * @param string $apiKey The SendGrid API Key + * @param string $from The sender of the email + * @param string|array $to The recipients of the email + * @param string $subject The subject of the mail + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, int $level = Logger::ERROR, bool $bubble = true) + { + parent::__construct($level, $bubble); + $this->apiUser = $apiUser; + $this->apiKey = $apiKey; + $this->from = $from; + $this->to = (array) $to; + $this->subject = $subject; + } + + /** + * {@inheritdoc} + */ + protected function send(string $content, array $records) + { + $message = []; + $message['api_user'] = $this->apiUser; + $message['api_key'] = $this->apiKey; + $message['from'] = $this->from; + foreach ($this->to as $recipient) { + $message['to[]'] = $recipient; + } + $message['subject'] = $this->subject; + $message['date'] = date('r'); + + if ($this->isHtmlBody($content)) { + $message['html'] = $content; + } else { + $message['text'] = $content; + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'https://api.sendgrid.com/api/mail.send.json'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($message)); + Curl\Util::execute($ch, 2); + } +} diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 38bc838..d9e6a4c 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -89,7 +89,7 @@ class SlackRecord { $this->channel = $channel; $this->username = $username; - $this->userIcon = trim($userIcon, ':'); + $this->userIcon = $userIcon !== null ? trim($userIcon, ':') : null; $this->useAttachment = $useAttachment; $this->useShortAttachment = $useShortAttachment; $this->includeContextAndExtra = $includeContextAndExtra; @@ -127,7 +127,7 @@ class SlackRecord 'color' => $this->getAttachmentColor($record['level']), 'fields' => array(), 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp() + 'ts' => $record['datetime']->getTimestamp(), ); if ($this->useShortAttachment) { @@ -137,7 +137,6 @@ class SlackRecord $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']); } - if ($this->includeContextAndExtra) { foreach (array('extra', 'context') as $key) { if (empty($record[$key])) { @@ -229,7 +228,7 @@ class SlackRecord /** * Generates attachment field * - * @param string $title + * @param string $title * @param string|array $value\ * * @return array @@ -243,7 +242,7 @@ class SlackRecord return array( 'title' => $title, 'value' => $value, - 'short' => false + 'short' => false, ); } diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 3ac4d83..a99872f 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -197,7 +197,7 @@ class SlackHandler extends SocketHandler return $this->slackRecord->stringify($fields); } - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { parent::setFormatter($formatter); $this->slackRecord->setFormatter($formatter); @@ -205,7 +205,7 @@ class SlackHandler extends SocketHandler return $this; } - public function getFormatter() + public function getFormatter(): FormatterInterface { $formatter = parent::getFormatter(); $this->slackRecord->setFormatter($formatter); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 9a1bbb4..a2ea52a 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -36,16 +36,16 @@ class SlackWebhookHandler extends AbstractProcessingHandler private $slackRecord; /** - * @param string $webhookUrl Slack Webhook URL - * @param string|null $channel Slack channel (encoded ID or name) - * @param string|null $username Name of a bot - * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) - * @param string|null $iconEmoji The emoji name to use (or null) - * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style - * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string $webhookUrl Slack Webhook URL + * @param string|null $channel Slack channel (encoded ID or name) + * @param string|null $username Name of a bot + * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) + * @param string|null $iconEmoji The emoji name to use (or null) + * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style + * @param bool $includeContextAndExtra Whether the attachment should include context and extra data + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, $bubble = true, array $excludeFields = array()) { @@ -97,7 +97,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler Curl\Util::execute($ch); } - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { parent::setFormatter($formatter); $this->slackRecord->setFormatter($formatter); @@ -105,7 +105,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler return $this; } - public function getFormatter() + public function getFormatter(): FormatterInterface { $formatter = parent::getFormatter(); $this->slackRecord->setFormatter($formatter); diff --git a/src/Monolog/Handler/SlackbotHandler.php b/src/Monolog/Handler/SlackbotHandler.php index baead52..dd2db59 100644 --- a/src/Monolog/Handler/SlackbotHandler.php +++ b/src/Monolog/Handler/SlackbotHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -40,11 +40,11 @@ class SlackbotHandler extends AbstractProcessingHandler private $channel; /** - * @param string $slackTeam Slack team slug - * @param string $token Slackbot token - * @param string $channel Slack channel (encoded ID or name) - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $slackTeam Slack team slug + * @param string $token Slackbot token + * @param string $channel Slack channel (encoded ID or name) + * @param int $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true) { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 7a61bf4..e2161ff 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -23,8 +23,11 @@ class SocketHandler extends AbstractProcessingHandler { private $connectionString; private $connectionTimeout; + /** @var resource|null */ private $resource; + /** @var float */ private $timeout = 0; + /** @var float */ private $writingTimeout = 10; private $lastSentBytes = null; private $persistent = false; @@ -149,20 +152,16 @@ class SocketHandler extends AbstractProcessingHandler /** * Get current connection timeout setting - * - * @return float */ - public function getConnectionTimeout() + public function getConnectionTimeout(): float { return $this->connectionTimeout; } /** * Get current in-transfer timeout - * - * @return float */ - public function getTimeout() + public function getTimeout(): float { return $this->timeout; } @@ -172,7 +171,7 @@ class SocketHandler extends AbstractProcessingHandler * * @return float */ - public function getWritingTimeout() + public function getWritingTimeout(): float { return $this->writingTimeout; } @@ -216,7 +215,7 @@ class SocketHandler extends AbstractProcessingHandler $seconds = floor($this->timeout); $microseconds = round(($this->timeout - $seconds) * 1e6); - return stream_set_timeout($this->resource, $seconds, $microseconds); + return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds); } /** diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php new file mode 100644 index 0000000..01c70dc --- /dev/null +++ b/src/Monolog/Handler/SqsHandler.php @@ -0,0 +1,53 @@ +<?php declare(strict_types=1); + +/* + * This file is part of the Monolog package. + * + * (c) Jordi Boggiano <j.boggiano@seld.be> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Aws\Sqs\SqsClient; +use Monolog\Logger; + +/** + * Writes to any sqs queue. + * + * @author Martijn van Calker <git@amvc.nl> + */ +class SqsHandler extends AbstractProcessingHandler +{ + /** @var SqsClient */ + private $client; + /** @var string */ + private $queueUrl; + + public function __construct(SqsClient $sqsClient, $queueUrl, $level = Logger::DEBUG, $bubble = true) + { + parent::__construct($level, $bubble); + + $this->client = $sqsClient; + $this->queueUrl = $queueUrl; + } + + /** + * Writes the record down to the log of the implementing handler. + * + * @param array $record + */ + protected function write(array $record) + { + if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) { + throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string'); + } + + $this->client->sendMessage([ + 'QueueUrl' => $this->queueUrl, + 'MessageBody' => $record['formatted'], + ]); + } +} diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 09a1573..5abbc59 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -22,8 +22,10 @@ use Monolog\Logger; */ class StreamHandler extends AbstractProcessingHandler { + /** @var resource|null */ protected $stream; protected $url; + /** @var string|null */ private $errorMessage; protected $filePermission; protected $useLocking; @@ -96,7 +98,7 @@ class StreamHandler extends AbstractProcessingHandler } $this->createDir(); $this->errorMessage = null; - set_error_handler(array($this, 'customErrorHandler')); + set_error_handler([$this, 'customErrorHandler']); $this->stream = fopen($this->url, 'a'); if ($this->filePermission !== null) { @chmod($this->url, $this->filePermission); @@ -123,7 +125,7 @@ class StreamHandler extends AbstractProcessingHandler /** * Write to stream * @param resource $stream - * @param array $record + * @param array $record */ protected function streamWrite($stream, array $record) { @@ -164,7 +166,7 @@ class StreamHandler extends AbstractProcessingHandler $dir = $this->getDirFromStream($this->url); if (null !== $dir && !is_dir($dir)) { $this->errorMessage = null; - set_error_handler(array($this, 'customErrorHandler')); + set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); if (false === $status) { diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 72f44a5..3359ac8 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Logger; use Monolog\Formatter\LineFormatter; +use Swift_Message; use Swift; /** @@ -26,12 +27,12 @@ class SwiftMailerHandler extends MailHandler private $messageTemplate; /** - * @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 \Swift_Mailer $mailer The mailer to use + * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced + * @param int|string $level The minimum logging level at which this handler will be triggered + * @param 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) + public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, bool $bubble = true) { parent::__construct($level, $bubble); @@ -42,7 +43,7 @@ class SwiftMailerHandler extends MailHandler /** * {@inheritdoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records) { $this->mailer->send($this->buildMessage($content, $records)); } @@ -50,21 +51,21 @@ class SwiftMailerHandler extends MailHandler /** * Creates instance of Swift_Message to be sent * - * @param string $content formatted email body to be sent - * @param array $records Log records that formed the content - * @return \Swift_Message + * @param string $content formatted email body to be sent + * @param array $records Log records that formed the content + * @return Swift_Message */ - protected function buildMessage($content, array $records) + protected function buildMessage(string $content, array $records): Swift_Message { $message = null; - if ($this->messageTemplate instanceof \Swift_Message) { + if ($this->messageTemplate instanceof Swift_Message) { $message = clone $this->messageTemplate; $message->generateId(); } elseif (is_callable($this->messageTemplate)) { $message = call_user_func($this->messageTemplate, $content, $records); } - if (!$message instanceof \Swift_Message) { + if (!$message instanceof Swift_Message) { throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it'); } @@ -73,7 +74,12 @@ class SwiftMailerHandler extends MailHandler $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } - $message->setBody($content); + $mime = null; + if ($this->isHtmlBody($content)) { + $mime = 'text/html'; + } + + $message->setBody($content, $mime); if (version_compare(Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { @@ -82,18 +88,4 @@ class SwiftMailerHandler extends MailHandler return $message; } - - /** - * BC getter, to be removed in 2.0 - */ - public function __get($name) - { - if ($name === 'message') { - trigger_error('SwiftMailerHandler->message is deprecated, use ->buildMessage() instead to retrieve the message', E_USER_DEPRECATED); - - return $this->buildMessage(null, array()); - } - - throw new \InvalidArgumentException('Invalid property '.$name); - } } diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 376bc3b..863fc56 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 3bff085..f1801b3 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -17,6 +17,8 @@ class UdpSocket protected $ip; protected $port; + + /** @var resource|null */ protected $socket; public function __construct($ip, $port = 514) @@ -42,7 +44,7 @@ class UdpSocket protected function send($chunk) { if (!is_resource($this->socket)) { - throw new \LogicException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); + throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); } socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); } diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 4718711..2258f56 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -57,19 +57,19 @@ class SyslogUdpHandler extends AbstractSyslogHandler $this->socket->close(); } - private function splitMessageIntoLines($message) + private function splitMessageIntoLines($message): array { if (is_array($message)) { $message = implode("\n", $message); } - return preg_split('/$\R?^/m', $message, -1, PREG_SPLIT_NO_EMPTY); + return preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); } /** * Make common syslog header (see rfc5424) */ - protected function makeCommonSyslogHeader($severity) + protected function makeCommonSyslogHeader($severity): string { $priority = $severity + $this->facility; @@ -96,7 +96,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler /** * Inject your own socket, mainly used for testing */ - public function setSocket($socket) + public function setSocket(UdpSocket $socket) { $this->socket = $socket; } diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index e39cfc6..3df7b6d 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -65,8 +65,8 @@ namespace Monolog\Handler; */ class TestHandler extends AbstractProcessingHandler { - protected $records = array(); - protected $recordsByLevel = array(); + protected $records = []; + protected $recordsByLevel = []; public function getRecords() { @@ -75,8 +75,8 @@ class TestHandler extends AbstractProcessingHandler public function clear() { - $this->records = array(); - $this->recordsByLevel = array(); + $this->records = []; + $this->recordsByLevel = []; } public function hasRecords($level) @@ -109,12 +109,8 @@ class TestHandler extends AbstractProcessingHandler }, $level); } - public function hasRecordThatPasses($predicate, $level) + public function hasRecordThatPasses(callable $predicate, $level) { - if (!is_callable($predicate)) { - throw new \InvalidArgumentException("Expected a callable for hasRecordThatSucceeds"); - } - if (!isset($this->recordsByLevel[$level])) { return false; } @@ -145,7 +141,7 @@ class TestHandler extends AbstractProcessingHandler if (method_exists($this, $genericMethod)) { $args[] = $level; - return call_user_func_array(array($this, $genericMethod), $args); + return call_user_func_array([$this, $genericMethod], $args); } } diff --git a/src/Monolog/Handler/WhatFailureGroupHandler.php b/src/Monolog/Handler/WhatFailureGroupHandler.php index 2732ba3..42c2336 100644 --- a/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types=1); /* * This file is part of the Monolog package. @@ -22,7 +22,7 @@ class WhatFailureGroupHandler extends GroupHandler /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { foreach ($this->processors as $processor) { @@ -33,8 +33,6 @@ class WhatFailureGroupHandler extends GroupHandler foreach ($this->handlers as $handler) { try { $handler->handle($record); - } catch (\Exception $e) { - // What failure? } catch (\Throwable $e) { // What failure? } @@ -51,8 +49,6 @@ class WhatFailureGroupHandler extends GroupHandler foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); - } catch (\Exception $e) { - // What failure? } catch (\Throwable $e) { // What failure? } diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index f22cf21..c0bceb4 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -1,4 +1,5 @@ -<?php +<?php declare(strict_types=1); + /* * This file is part of the Monolog package. * @@ -10,6 +11,7 @@ namespace Monolog\Handler; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\NormalizerFormatter; use Monolog\Logger; @@ -25,7 +27,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler * * @var array */ - protected $levelMap = array( + protected $levelMap = [ Logger::DEBUG => 1, Logger::INFO => 2, Logger::NOTICE => 3, @@ -34,7 +36,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler Logger::CRITICAL => 6, Logger::ALERT => 7, Logger::EMERGENCY => 0, - ); + ]; /** * Construct @@ -78,7 +80,7 @@ class ZendMonitorHandler extends AbstractProcessingHandler /** * {@inheritdoc} */ - public function getDefaultFormatter() + public function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter(); } |