1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-08-04 12:17:35 +02:00

Bump phpstan to level 8

This commit is contained in:
Jordi Boggiano
2021-07-04 14:03:55 +02:00
parent 4ef5da80ad
commit 8b5278d8e1
47 changed files with 262 additions and 101 deletions

View File

@@ -1,5 +1,5 @@
parameters: parameters:
level: 6 level: 8
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false
reportUnmatchedIgnoredErrors: false reportUnmatchedIgnoredErrors: false
@@ -19,7 +19,16 @@ parameters:
paths: paths:
- src/Monolog/Handler/LogglyHandler.php - src/Monolog/Handler/LogglyHandler.php
# blocked until we only support php8+
- '#Parameter \#1 \$socket of function (socket_close|socket_sendto|socket_send) expects Socket, resource\|Socket(\|null)? given\.#'
- '#Parameter \#1 \$handle of function (curl_exec|curl_close|curl_error|curl_errno|curl_setopt) expects CurlHandle, CurlHandle\|resource(\|null)? given\.#'
# blocked by https://github.com/phpstan/phpstan/issues/5091 # blocked by https://github.com/phpstan/phpstan/issues/5091
- '#has unknown class Monolog\\Handler\\Record#' - '#has unknown class Monolog\\Handler\\Record#'
- '#::processRecord#' - '#::processRecord\(\) should return array#'
- '#::processRecord\(\) has invalid type#'
- '#::processRecord\(\) return type has no value type#'
- '#::processRecord\(\) has parameter \$record with no value type#'
- '#::popProcessor\(\) should return callable#'
- '#Parameter \#1 \$ of callable \(callable\(Monolog\\Handler\\Record\): Monolog\\Handler\\Record\)#'
- '#is incompatible with native type array.#' - '#is incompatible with native type array.#'

View File

@@ -65,6 +65,7 @@ class ElasticaFormatter extends NormalizerFormatter
*/ */
public function getType(): string public function getType(): string
{ {
/** @phpstan-ignore-next-line */
return $this->type; return $this->type;
} }
@@ -78,6 +79,7 @@ class ElasticaFormatter extends NormalizerFormatter
$document = new Document(); $document = new Document();
$document->setData($record); $document->setData($record);
if (method_exists($document, 'setType')) { if (method_exists($document, 'setType')) {
/** @phpstan-ignore-next-line */
$document->setType($this->type); $document->setType($this->type);
} }
$document->setIndex($this->index); $document->setIndex($this->index);

View File

@@ -20,6 +20,8 @@ use Monolog\Utils;
* @see http://docs.graylog.org/en/latest/pages/gelf.html * @see http://docs.graylog.org/en/latest/pages/gelf.html
* *
* @author Matt Lehner <mlehner@gmail.com> * @author Matt Lehner <mlehner@gmail.com>
*
* @phpstan-import-type Level from \Monolog\Logger
*/ */
class GelfMessageFormatter extends NormalizerFormatter class GelfMessageFormatter extends NormalizerFormatter
{ {
@@ -49,6 +51,8 @@ class GelfMessageFormatter extends NormalizerFormatter
* Translates Monolog log levels to Graylog2 log priorities. * Translates Monolog log levels to Graylog2 log priorities.
* *
* @var array<int, int> * @var array<int, int>
*
* @phpstan-var array<Level, int>
*/ */
private $logLevels = [ private $logLevels = [
Logger::DEBUG => 7, Logger::DEBUG => 7,
@@ -65,7 +69,7 @@ class GelfMessageFormatter extends NormalizerFormatter
{ {
parent::__construct('U.u'); parent::__construct('U.u');
$this->systemName = (is_null($systemName) || $systemName === '') ? gethostname() : $systemName; $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName;
$this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix; $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix;
$this->contextPrefix = $contextPrefix; $this->contextPrefix = $contextPrefix;
@@ -73,15 +77,18 @@ class GelfMessageFormatter extends NormalizerFormatter
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function format(array $record): Message public function format(array $record): Message
{ {
$context = $extra = [];
if (isset($record['context'])) { if (isset($record['context'])) {
$record['context'] = parent::format($record['context']); /** @var mixed[] $context */
$context = parent::normalize($record['context']);
} }
if (isset($record['extra'])) { if (isset($record['extra'])) {
$record['extra'] = parent::format($record['extra']); /** @var mixed[] $extra */
$extra = parent::normalize($record['extra']);
} }
if (!isset($record['datetime'], $record['message'], $record['level'])) { if (!isset($record['datetime'], $record['message'], $record['level'])) {
@@ -105,31 +112,31 @@ class GelfMessageFormatter extends NormalizerFormatter
if (isset($record['channel'])) { if (isset($record['channel'])) {
$message->setFacility($record['channel']); $message->setFacility($record['channel']);
} }
if (isset($record['extra']['line'])) { if (isset($extra['line'])) {
$message->setLine($record['extra']['line']); $message->setLine($extra['line']);
unset($record['extra']['line']); unset($extra['line']);
} }
if (isset($record['extra']['file'])) { if (isset($extra['file'])) {
$message->setFile($record['extra']['file']); $message->setFile($extra['file']);
unset($record['extra']['file']); unset($extra['file']);
} }
foreach ($record['extra'] as $key => $val) { foreach ($extra as $key => $val) {
$val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
$len = strlen($this->extraPrefix . $key . $val); $len = strlen($this->extraPrefix . $key . $val);
if ($len > $this->maxLength) { if ($len > $this->maxLength) {
$message->setAdditional($this->extraPrefix . $key, Utils::substr($val, 0, $this->maxLength)); $message->setAdditional($this->extraPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength));
continue; continue;
} }
$message->setAdditional($this->extraPrefix . $key, $val); $message->setAdditional($this->extraPrefix . $key, $val);
} }
foreach ($record['context'] as $key => $val) { foreach ($context as $key => $val) {
$val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
$len = strlen($this->contextPrefix . $key . $val); $len = strlen($this->contextPrefix . $key . $val);
if ($len > $this->maxLength) { if ($len > $this->maxLength) {
$message->setAdditional($this->contextPrefix . $key, Utils::substr($val, 0, $this->maxLength)); $message->setAdditional($this->contextPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength));
continue; continue;
} }
@@ -137,8 +144,8 @@ class GelfMessageFormatter extends NormalizerFormatter
} }
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
if (null === $message->getFile() && isset($record['context']['exception']['file'])) { if (null === $message->getFile() && isset($context['exception']['file'])) {
if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) {
$message->setFile($matches[1]); $message->setFile($matches[1]);
$message->setLine($matches[2]); $message->setLine($matches[2]);
} }

View File

@@ -110,6 +110,9 @@ class LineFormatter extends NormalizerFormatter
// remove leftover %extra.xxx% and %context.xxx% if any // remove leftover %extra.xxx% and %context.xxx% if any
if (false !== strpos($output, '%')) { if (false !== strpos($output, '%')) {
$output = preg_replace('/%(?:extra|context)\..+?%/', '', $output); $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
if (null === $output) {
throw new \RuntimeException('Failed to run preg_replace: ' . preg_last_error() . ' / ' . preg_last_error_msg());
}
} }
return $output; return $output;

View File

@@ -52,7 +52,7 @@ class LogstashFormatter extends NormalizerFormatter
// logstash requires a ISO 8601 format date with optional millisecond precision. // logstash requires a ISO 8601 format date with optional millisecond precision.
parent::__construct('Y-m-d\TH:i:s.uP'); parent::__construct('Y-m-d\TH:i:s.uP');
$this->systemName = $systemName === null ? gethostname() : $systemName; $this->systemName = $systemName === null ? (string) gethostname() : $systemName;
$this->applicationName = $applicationName; $this->applicationName = $applicationName;
$this->extraKey = $extraKey; $this->extraKey = $extraKey;
$this->contextKey = $contextKey; $this->contextKey = $contextKey;

View File

@@ -37,23 +37,26 @@ class MongoDBFormatter implements FormatterInterface
$this->maxNestingLevel = max($maxNestingLevel, 0); $this->maxNestingLevel = max($maxNestingLevel, 0);
$this->exceptionTraceAsString = $exceptionTraceAsString; $this->exceptionTraceAsString = $exceptionTraceAsString;
$this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare(phpversion('mongodb'), '1.1.9', '<='); $this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare((string) phpversion('mongodb'), '1.1.9', '<=');
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
* @return scalar[] * @return mixed[]
*/ */
public function format(array $record): array public function format(array $record): array
{ {
return $this->formatArray($record); /** @var mixed[] $res */
$res = $this->formatArray($record);
return $res;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
* @return array<scalar[]> * @return array<mixed[]>
*/ */
public function formatBatch(array $records): array public function formatBatch(array $records): array
{ {
@@ -152,6 +155,7 @@ class MongoDBFormatter implements FormatterInterface
? (int) $milliseconds ? (int) $milliseconds
: (string) $milliseconds; : (string) $milliseconds;
// @phpstan-ignore-next-line
return new UTCDateTime($milliseconds); return new UTCDateTime($milliseconds);
} }
} }

View File

@@ -47,6 +47,8 @@ class NormalizerFormatter implements FormatterInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @param mixed[] $record
*/ */
public function format(array $record) public function format(array $record)
{ {
@@ -123,7 +125,7 @@ class NormalizerFormatter implements FormatterInterface
/** /**
* @param mixed $data * @param mixed $data
* @return scalar|array<scalar> * @return null|scalar|array<array|scalar|null>
*/ */
protected function normalize($data, int $depth = 0) protected function normalize($data, int $depth = 0)
{ {

View File

@@ -22,20 +22,21 @@ class ScalarFormatter extends NormalizerFormatter
/** /**
* {@inheritdoc} * {@inheritdoc}
* *
* @phpstan-return scalar[] $record * @phpstan-return array<string, scalar|null> $record
*/ */
public function format(array $record): array public function format(array $record): array
{ {
$result = [];
foreach ($record as $key => $value) { foreach ($record as $key => $value) {
$record[$key] = $this->normalizeValue($value); $result[$key] = $this->normalizeValue($value);
} }
return $record; return $result;
} }
/** /**
* @param mixed $value * @param mixed $value
* @return string|int|bool|null * @return scalar|null
*/ */
protected function normalizeValue($value) protected function normalizeValue($value)
{ {

View File

@@ -69,6 +69,7 @@ class WildfireFormatter extends NormalizerFormatter
unset($record['extra']['line']); unset($record['extra']['line']);
} }
/** @var mixed[] $record */
$record = $this->normalize($record); $record = $this->normalize($record);
$message = ['message' => $record['message']]; $message = ['message' => $record['message']];
$handleError = false; $handleError = false;
@@ -125,7 +126,7 @@ class WildfireFormatter extends NormalizerFormatter
/** /**
* {@inheritdoc} * {@inheritdoc}
* *
* @return scalar|array<scalar>|object * @return null|scalar|array<array|scalar|null>|object
*/ */
protected function normalize($data, int $depth = 0) protected function normalize($data, int $depth = 0)
{ {

View File

@@ -21,6 +21,7 @@ namespace Monolog\Handler;
* *
* @phpstan-import-type LevelName from \Monolog\Logger * @phpstan-import-type LevelName from \Monolog\Logger
* @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type Record from \Monolog\Logger
* @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed} * @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed}
*/ */
abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
@@ -38,6 +39,7 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc
} }
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }

View File

@@ -94,6 +94,7 @@ class AmqpHandler extends AbstractProcessingHandler
continue; continue;
} }
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
$data = $this->getFormatter()->format($record); $data = $this->getFormatter()->format($record);

View File

@@ -197,7 +197,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey'];
static $labels = []; static $labels = [];
return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) { $style = preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) {
if (trim($m[1]) === 'autolabel') { if (trim($m[1]) === 'autolabel') {
// Format the string as a label with consistent auto assigned background color // Format the string as a label with consistent auto assigned background color
if (!isset($labels[$string])) { if (!isset($labels[$string])) {
@@ -210,6 +210,12 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
return $m[1]; return $m[1];
}, $style); }, $style);
if (null === $style) {
throw new \RuntimeException('Failed to run preg_replace_callback: ' . preg_last_error() . ' / ' . preg_last_error_msg());
}
return $style;
} }
/** /**

View File

@@ -80,6 +80,7 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
} }
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }

View File

@@ -22,6 +22,8 @@ use Monolog\Utils;
* This also works out of the box with Firefox 43+ * This also works out of the box with Firefox 43+
* *
* @author Christophe Coevoet <stof@notk.org> * @author Christophe Coevoet <stof@notk.org>
*
* @phpstan-import-type Record from \Monolog\Logger
*/ */
class ChromePHPHandler extends AbstractProcessingHandler class ChromePHPHandler extends AbstractProcessingHandler
{ {
@@ -87,7 +89,9 @@ class ChromePHPHandler extends AbstractProcessingHandler
if ($record['level'] < $this->level) { if ($record['level'] < $this->level) {
continue; continue;
} }
$messages[] = $this->processRecord($record); /** @var Record $message */
$message = $this->processRecord($record);
$messages[] = $message;
} }
if (!empty($messages)) { if (!empty($messages)) {

View File

@@ -46,7 +46,7 @@ class CubeHandler extends AbstractProcessingHandler
{ {
$urlInfo = parse_url($url); $urlInfo = parse_url($url);
if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { if ($urlInfo === false || !isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) {
throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
} }
@@ -76,11 +76,12 @@ class CubeHandler extends AbstractProcessingHandler
throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
} }
$this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); $udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
if (!$this->udpConnection) { if (false === $udpConnection) {
throw new \LogicException('Unable to create a socket'); throw new \LogicException('Unable to create a socket');
} }
$this->udpConnection = $udpConnection;
if (!socket_connect($this->udpConnection, $this->host, $this->port)) { if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
} }
@@ -98,12 +99,12 @@ class CubeHandler extends AbstractProcessingHandler
throw new MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler'); throw new MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler');
} }
$this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); $httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
if (false === $httpConnection) {
if (!$this->httpConnection) {
throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
} }
$this->httpConnection = $httpConnection;
curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
} }
@@ -150,6 +151,10 @@ class CubeHandler extends AbstractProcessingHandler
$this->connectHttp(); $this->connectHttp();
} }
if (null === $this->httpConnection) {
throw new \LogicException('No connection could be established');
}
curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [
'Content-Type: application/json', 'Content-Type: application/json',

View File

@@ -12,6 +12,7 @@
namespace Monolog\Handler; namespace Monolog\Handler;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LogLevel;
/** /**
* Simple handler wrapper that deduplicates log records across multiple requests * Simple handler wrapper that deduplicates log records across multiple requests
@@ -34,6 +35,8 @@ use Monolog\Logger;
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
* *
* @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Record from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
* @phpstan-import-type Level from \Monolog\Logger
*/ */
class DeduplicationHandler extends BufferHandler class DeduplicationHandler extends BufferHandler
{ {
@@ -43,7 +46,7 @@ class DeduplicationHandler extends BufferHandler
protected $deduplicationStore; protected $deduplicationStore;
/** /**
* @var int * @var Level
*/ */
protected $deduplicationLevel; protected $deduplicationLevel;
@@ -63,6 +66,8 @@ class DeduplicationHandler extends BufferHandler
* @param string|int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes * @param string|int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
* @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*
* @phpstan-param Level|LevelName|LogLevel::* $deduplicationLevel
*/ */
public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true) public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true)
{ {

View File

@@ -79,6 +79,9 @@ class ErrorLogHandler extends AbstractProcessingHandler
} }
$lines = preg_split('{[\r\n]+}', (string) $record['formatted']); $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
if ($lines === false) {
throw new \RuntimeException('Failed to preg_split formatted string: '.preg_last_error().' / '.preg_last_error_msg());
}
foreach ($lines as $line) { foreach ($lines as $line) {
error_log($line, $this->messageType); error_log($line, $this->messageType);
} }

View File

@@ -13,6 +13,15 @@ namespace Monolog\Handler;
use Throwable; use Throwable;
/**
* Forwards records to at most one handler
*
* If a handler fails, the exception is suppressed and the record is forwarded to the next handler.
*
* As soon as one handler handles a record successfully, the handling stops there.
*
* @phpstan-import-type Record from \Monolog\Logger
*/
class FallbackGroupHandler extends GroupHandler class FallbackGroupHandler extends GroupHandler
{ {
/** /**
@@ -21,6 +30,7 @@ class FallbackGroupHandler extends GroupHandler
public function handle(array $record): bool public function handle(array $record): bool
{ {
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }
foreach ($this->handlers as $handler) { foreach ($this->handlers as $handler) {
@@ -45,6 +55,7 @@ class FallbackGroupHandler extends GroupHandler
foreach ($records as $record) { foreach ($records as $record) {
$processed[] = $this->processRecord($record); $processed[] = $this->processRecord($record);
} }
/** @var Record[] $records */
$records = $processed; $records = $processed;
} }

View File

@@ -64,6 +64,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* *
* @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList
* @phpstan-param Level|LevelName|LogLevel::* $maxLevel
*/ */
public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true)
{ {
@@ -89,6 +90,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
* @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array
* *
* @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList * @phpstan-param Level|LevelName|LogLevel::*|array<Level|LevelName|LogLevel::*> $minLevelOrList
* @phpstan-param Level|LevelName|LogLevel::* $maxLevel
*/ */
public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self
{ {
@@ -124,6 +126,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
} }
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }

View File

@@ -12,6 +12,7 @@
namespace Monolog\Handler\FingersCrossed; namespace Monolog\Handler\FingersCrossed;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LogLevel;
/** /**
* Channel and Error level based monolog activation strategy. Allows to trigger activation * Channel and Error level based monolog activation strategy. Allows to trigger activation
@@ -35,11 +36,12 @@ use Monolog\Logger;
* *
* @phpstan-import-type Record from \Monolog\Logger * @phpstan-import-type Record from \Monolog\Logger
* @phpstan-import-type Level from \Monolog\Logger * @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
*/ */
class ChannelLevelActivationStrategy implements ActivationStrategyInterface class ChannelLevelActivationStrategy implements ActivationStrategyInterface
{ {
/** /**
* @var int * @var Level
*/ */
private $defaultActionLevel; private $defaultActionLevel;
@@ -53,6 +55,7 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface
* @param array<string, int> $channelToActionLevel An array that maps channel names to action levels. * @param array<string, int> $channelToActionLevel An array that maps channel names to action levels.
* *
* @phpstan-param array<string, Level> $channelToActionLevel * @phpstan-param array<string, Level> $channelToActionLevel
* @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel
*/ */
public function __construct($defaultActionLevel, array $channelToActionLevel = []) public function __construct($defaultActionLevel, array $channelToActionLevel = [])
{ {

View File

@@ -12,21 +12,27 @@
namespace Monolog\Handler\FingersCrossed; namespace Monolog\Handler\FingersCrossed;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LogLevel;
/** /**
* Error level based activation strategy. * Error level based activation strategy.
* *
* @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
*/ */
class ErrorLevelActivationStrategy implements ActivationStrategyInterface class ErrorLevelActivationStrategy implements ActivationStrategyInterface
{ {
/** /**
* @var int * @var Level
*/ */
private $actionLevel; private $actionLevel;
/** /**
* @param int|string $actionLevel Level or name or value * @param int|string $actionLevel Level or name or value
*
* @phpstan-param Level|LevelName|LogLevel::* $actionLevel
*/ */
public function __construct($actionLevel) public function __construct($actionLevel)
{ {

View File

@@ -16,6 +16,7 @@ use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
use Monolog\Logger; use Monolog\Logger;
use Monolog\ResettableInterface; use Monolog\ResettableInterface;
use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\FormatterInterface;
use Psr\Log\LogLevel;
/** /**
* Buffers all records until a certain level is reached * Buffers all records until a certain level is reached
@@ -73,6 +74,9 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true)
* @param int|string $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * @param int|string $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
*
* @phpstan-param Level|LevelName|LogLevel::* $passthruLevel
* @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy
*/ */
public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null) public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null)
{ {
@@ -127,6 +131,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
public function handle(array $record): bool public function handle(array $record): bool
{ {
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }
@@ -152,7 +157,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
{ {
$this->flushBuffer(); $this->flushBuffer();
$this->handler->close(); $this->getHandler()->close();
} }
public function reset() public function reset()

View File

@@ -67,11 +67,15 @@ class FirePHPHandler extends AbstractProcessingHandler
* @param string $message Log message * @param string $message Log message
* *
* @return array<string, string> Complete header string ready for the client as key and message as value * @return array<string, string> Complete header string ready for the client as key and message as value
*
* @phpstan-return non-empty-array<string, string>
*/ */
protected function createHeader(array $meta, string $message): array protected function createHeader(array $meta, string $message): array
{ {
$header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta)); $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta));
// See https://github.com/phpstan/phpstan/issues/5219
// @phpstan-ignore-next-line
return [$header => $message]; return [$header => $message];
} }
@@ -80,6 +84,8 @@ class FirePHPHandler extends AbstractProcessingHandler
* *
* @return array<string, string> * @return array<string, string>
* *
* @phpstan-return non-empty-array<string, string>
*
* @see createHeader() * @see createHeader()
* *
* @phpstan-param FormattedRecord $record * @phpstan-param FormattedRecord $record

View File

@@ -43,8 +43,6 @@ class FleepHookHandler extends SocketHandler
* see https://fleep.io/integrations/webhooks/ * see https://fleep.io/integrations/webhooks/
* *
* @param string $token Webhook token * @param string $token Webhook token
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @throws MissingExtensionException * @throws MissingExtensionException
*/ */
public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true) public function __construct(string $token, $level = Logger::DEBUG, bool $bubble = true)

View File

@@ -37,9 +37,6 @@ class FlowdockHandler extends SocketHandler
protected $apiToken; protected $apiToken;
/** /**
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*
* @throws MissingExtensionException if OpenSSL is missing * @throws MissingExtensionException if OpenSSL is missing
*/ */
public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubble = true) public function __construct(string $apiToken, $level = Logger::DEBUG, bool $bubble = true)

View File

@@ -25,12 +25,12 @@ use Monolog\Formatter\FormatterInterface;
class GelfHandler extends AbstractProcessingHandler class GelfHandler extends AbstractProcessingHandler
{ {
/** /**
* @var PublisherInterface|null the publisher object that sends the message to the server * @var PublisherInterface the publisher object that sends the message to the server
*/ */
protected $publisher; protected $publisher;
/** /**
* @param PublisherInterface $publisher a publisher object * @param PublisherInterface $publisher a gelf publisher object
*/ */
public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true) public function __construct(PublisherInterface $publisher, $level = Logger::DEBUG, bool $bubble = true)
{ {

View File

@@ -18,6 +18,8 @@ use Monolog\ResettableInterface;
* Forwards records to multiple handlers * Forwards records to multiple handlers
* *
* @author Lenar Lõhmus <lenar@city.ee> * @author Lenar Lõhmus <lenar@city.ee>
*
* @phpstan-import-type Record from \Monolog\Logger
*/ */
class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface
{ {
@@ -45,7 +47,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function isHandling(array $record): bool public function isHandling(array $record): bool
{ {
@@ -59,11 +61,12 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function handle(array $record): bool public function handle(array $record): bool
{ {
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }
@@ -75,7 +78,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function handleBatch(array $records): void public function handleBatch(array $records): void
{ {
@@ -84,6 +87,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
foreach ($records as $record) { foreach ($records as $record) {
$processed[] = $this->processRecord($record); $processed[] = $this->processRecord($record);
} }
/** @var Record[] $records */
$records = $processed; $records = $processed;
} }
@@ -113,7 +117,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function setFormatter(FormatterInterface $formatter): HandlerInterface public function setFormatter(FormatterInterface $formatter): HandlerInterface
{ {

View File

@@ -30,8 +30,6 @@ class InsightOpsHandler extends SocketHandler
* @param string $token Log token supplied by InsightOps * @param string $token Log token supplied by InsightOps
* @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'. * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
* @param bool $useSSL Whether or not SSL encryption should be used * @param bool $useSSL Whether or not SSL encryption should be used
* @param string|int $level The minimum logging level to trigger this handler
* @param bool $bubble Whether or not messages that are handled should bubble up the stack.
* *
* @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
*/ */

View File

@@ -26,8 +26,6 @@ class LogEntriesHandler extends SocketHandler
/** /**
* @param string $token Log token supplied by LogEntries * @param string $token Log token supplied by LogEntries
* @param bool $useSSL Whether or not SSL encryption should be used. * @param bool $useSSL Whether or not SSL encryption should be used.
* @param string|int $level The minimum logging level to trigger this handler
* @param bool $bubble Whether or not messages that are handled should bubble up the stack.
* @param string $host Custom hostname to send the data to if needed * @param string $host Custom hostname to send the data to if needed
* *
* @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing

View File

@@ -40,8 +40,6 @@ class LogmaticHandler extends SocketHandler
* @param string $hostname Host name supplied by Logmatic. * @param string $hostname Host name supplied by Logmatic.
* @param string $appname Application name supplied by Logmatic. * @param string $appname Application name supplied by Logmatic.
* @param bool $useSSL Whether or not SSL encryption should be used. * @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 * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
*/ */

View File

@@ -34,7 +34,9 @@ abstract class MailHandler extends AbstractProcessingHandler
if ($record['level'] < $this->level) { if ($record['level'] < $this->level) {
continue; continue;
} }
$messages[] = $this->processRecord($record); /** @var Record $message */
$message = $this->processRecord($record);
$messages[] = $message;
} }
if (!empty($messages)) { if (!empty($messages)) {
@@ -61,7 +63,7 @@ abstract class MailHandler extends AbstractProcessingHandler
} }
/** /**
* @phpstan-param Record[] $records * @phpstan-param non-empty-array<Record> $records
* @phpstan-return Record * @phpstan-return Record
*/ */
protected function getHighestRecord(array $records): array protected function getHighestRecord(array $records): array

View File

@@ -162,7 +162,7 @@ class ProcessHandler extends AbstractProcessingHandler
*/ */
protected function readProcessErrors(): string protected function readProcessErrors(): string
{ {
return stream_get_contents($this->pipes[2]); return (string) stream_get_contents($this->pipes[2]);
} }
/** /**

View File

@@ -13,6 +13,7 @@ namespace Monolog\Handler;
use Monolog\Logger; use Monolog\Logger;
use Monolog\Utils; use Monolog\Utils;
use Psr\Log\LogLevel;
/** /**
* Sends notifications through the pushover api to mobile phones * Sends notifications through the pushover api to mobile phones
@@ -21,6 +22,8 @@ use Monolog\Utils;
* @see https://www.pushover.net/api * @see https://www.pushover.net/api
* *
* @phpstan-import-type FormattedRecord from AbstractProcessingHandler * @phpstan-import-type FormattedRecord from AbstractProcessingHandler
* @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
*/ */
class PushoverHandler extends SocketHandler class PushoverHandler extends SocketHandler
{ {
@@ -28,7 +31,7 @@ class PushoverHandler extends SocketHandler
private $token; private $token;
/** @var array<int|string> */ /** @var array<int|string> */
private $users; private $users;
/** @var ?string */ /** @var string */
private $title; private $title;
/** @var string|int|null */ /** @var string|int|null */
private $user = null; private $user = null;
@@ -80,8 +83,6 @@ class PushoverHandler extends SocketHandler
* @param string $token Pushover api token * @param string $token Pushover api token
* @param string|array $users Pushover user id or array of ids the message will be sent to * @param string|array $users Pushover user id or array of ids the message will be sent to
* @param string|null $title Title sent to the Pushover API * @param string|null $title Title sent to the Pushover API
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
* the pushover.net app owner. OpenSSL is required for this option. * the pushover.net app owner. OpenSSL is required for this option.
* @param string|int $highPriorityLevel The minimum logging level at which this handler will start * @param string|int $highPriorityLevel The minimum logging level at which this handler will start
@@ -94,6 +95,8 @@ class PushoverHandler extends SocketHandler
* to be retried for (every retry seconds). * to be retried for (every retry seconds).
* *
* @phpstan-param string|array<int|string> $users * @phpstan-param string|array<int|string> $users
* @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel
* @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel
*/ */
public function __construct( public function __construct(
string $token, string $token,
@@ -112,7 +115,7 @@ class PushoverHandler extends SocketHandler
$this->token = $token; $this->token = $token;
$this->users = (array) $users; $this->users = (array) $users;
$this->title = $title ?: gethostname(); $this->title = $title ?: (string) gethostname();
$this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel); $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
$this->emergencyLevel = Logger::toMonologLevel($emergencyLevel); $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
$this->retry = $retry; $this->retry = $retry;
@@ -195,6 +198,8 @@ class PushoverHandler extends SocketHandler
/** /**
* @param int|string $value * @param int|string $value
*
* @phpstan-param Level|LevelName|LogLevel::* $value
*/ */
public function setHighPriorityLevel($value): self public function setHighPriorityLevel($value): self
{ {
@@ -205,6 +210,8 @@ class PushoverHandler extends SocketHandler
/** /**
* @param int|string $value * @param int|string $value
*
* @phpstan-param Level|LevelName|LogLevel::* $value
*/ */
public function setEmergencyLevel($value): self public function setEmergencyLevel($value): self
{ {

View File

@@ -97,6 +97,7 @@ class RollbarHandler extends AbstractProcessingHandler
$toLog = $record['message']; $toLog = $record['message'];
} }
// @phpstan-ignore-next-line
$this->rollbarLogger->log($context['level'], $toLog, $context); $this->rollbarLogger->log($context['level'], $toLog, $context);
$this->hasRecords = true; $this->hasRecords = true;

View File

@@ -46,8 +46,6 @@ class RotatingFileHandler extends StreamHandler
/** /**
* @param string $filename * @param string $filename
* @param int $maxFiles The maximal amount of files to keep (0 means unlimited) * @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
* @param bool $useLocking Try to lock log file before doing any writes * @param bool $useLocking Try to lock log file before doing any writes
*/ */
@@ -116,7 +114,7 @@ class RotatingFileHandler extends StreamHandler
{ {
// on the first record written, if the log is new, we should rotate (once per day) // on the first record written, if the log is new, we should rotate (once per day)
if (null === $this->mustRotate) { if (null === $this->mustRotate) {
$this->mustRotate = !file_exists($this->url); $this->mustRotate = null === $this->url || !file_exists($this->url);
} }
if ($this->nextRotation <= $record['datetime']) { if ($this->nextRotation <= $record['datetime']) {
@@ -142,6 +140,11 @@ class RotatingFileHandler extends StreamHandler
} }
$logFiles = glob($this->getGlobPattern()); $logFiles = glob($this->getGlobPattern());
if (false === $logFiles) {
// failed to glob
return;
}
if ($this->maxFiles >= count($logFiles)) { if ($this->maxFiles >= count($logFiles)) {
// no files to remove // no files to remove
return; return;
@@ -176,7 +179,7 @@ class RotatingFileHandler extends StreamHandler
$fileInfo['dirname'] . '/' . $this->filenameFormat $fileInfo['dirname'] . '/' . $this->filenameFormat
); );
if (!empty($fileInfo['extension'])) { if (isset($fileInfo['extension'])) {
$timedFilename .= '.'.$fileInfo['extension']; $timedFilename .= '.'.$fileInfo['extension'];
} }
@@ -191,7 +194,7 @@ class RotatingFileHandler extends StreamHandler
[$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'], [$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'],
$fileInfo['dirname'] . '/' . $this->filenameFormat $fileInfo['dirname'] . '/' . $this->filenameFormat
); );
if (!empty($fileInfo['extension'])) { if (isset($fileInfo['extension'])) {
$glob .= '.'.$fileInfo['extension']; $glob .= '.'.$fileInfo['extension'];
} }

View File

@@ -36,7 +36,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
/** /**
* @var HandlerInterface|callable * @var HandlerInterface|callable
* @phpstan-var HandlerInterface|callable(Record, HandlerInterface): HandlerInterface * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface
*/ */
protected $handler; protected $handler;
@@ -46,7 +46,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
protected $factor; protected $factor;
/** /**
* @psalm-param HandlerInterface|callable(Record, HandlerInterface): HandlerInterface $handler * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler
* *
* @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
* @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled) * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled)
@@ -71,6 +71,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
{ {
if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }

View File

@@ -25,6 +25,7 @@ use Monolog\Formatter\FormatterInterface;
* @see https://api.slack.com/docs/message-attachments * @see https://api.slack.com/docs/message-attachments
* *
* @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler
* @phpstan-import-type Record from \Monolog\Logger
*/ */
class SlackRecord class SlackRecord
{ {
@@ -121,7 +122,7 @@ class SlackRecord
* is expecting. * is expecting.
* *
* @phpstan-param FormattedRecord $record * @phpstan-param FormattedRecord $record
* @phpstan-return string[] * @phpstan-return mixed[]
*/ */
public function getSlackData(array $record): array public function getSlackData(array $record): array
{ {
@@ -137,6 +138,7 @@ class SlackRecord
} }
if ($this->formatter && !$this->useAttachment) { if ($this->formatter && !$this->useAttachment) {
/** @phpstan-ignore-next-line */
$message = $this->formatter->format($record); $message = $this->formatter->format($record);
} else { } else {
$message = $record['message']; $message = $record['message'];
@@ -221,6 +223,7 @@ class SlackRecord
*/ */
public function stringify(array $fields): string public function stringify(array $fields): string
{ {
/** @var Record $fields */
$normalized = $this->normalizerFormatter->format($fields); $normalized = $this->normalizerFormatter->format($fields);
$hasSecondDimension = count(array_filter($normalized, 'is_array')); $hasSecondDimension = count(array_filter($normalized, 'is_array'));
@@ -341,8 +344,11 @@ class SlackRecord
*/ */
private function generateAttachmentFields(array $data): array private function generateAttachmentFields(array $data): array
{ {
/** @var Record $data */
$normalized = $this->normalizerFormatter->format($data);
$fields = array(); $fields = array();
foreach ($this->normalizerFormatter->format($data) as $key => $value) { foreach ($normalized as $key => $value) {
$fields[] = $this->generateAttachmentField((string) $key, $value); $fields[] = $this->generateAttachmentField((string) $key, $value);
} }

View File

@@ -216,7 +216,7 @@ class SocketHandler extends AbstractProcessingHandler
/** /**
* Wrapper to allow mocking * Wrapper to allow mocking
* *
* @return resource|bool * @return resource|false
*/ */
protected function pfsockopen() protected function pfsockopen()
{ {
@@ -226,7 +226,7 @@ class SocketHandler extends AbstractProcessingHandler
/** /**
* Wrapper to allow mocking * Wrapper to allow mocking
* *
* @return resource|bool * @return resource|false
*/ */
protected function fsockopen() protected function fsockopen()
{ {
@@ -245,6 +245,10 @@ class SocketHandler extends AbstractProcessingHandler
$seconds = floor($this->timeout); $seconds = floor($this->timeout);
$microseconds = round(($this->timeout - $seconds) * 1e6); $microseconds = round(($this->timeout - $seconds) * 1e6);
if (!is_resource($this->resource)) {
throw new \LogicException('streamSetTimeout called but $this->resource is not a resource');
}
return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds); return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds);
} }
@@ -257,6 +261,10 @@ class SocketHandler extends AbstractProcessingHandler
*/ */
protected function streamSetChunkSize() protected function streamSetChunkSize()
{ {
if (!is_resource($this->resource)) {
throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource');
}
return stream_set_chunk_size($this->resource, $this->chunkSize); return stream_set_chunk_size($this->resource, $this->chunkSize);
} }
@@ -267,6 +275,10 @@ class SocketHandler extends AbstractProcessingHandler
*/ */
protected function fwrite(string $data) protected function fwrite(string $data)
{ {
if (!is_resource($this->resource)) {
throw new \LogicException('fwrite called but $this->resource is not a resource');
}
return @fwrite($this->resource, $data); return @fwrite($this->resource, $data);
} }
@@ -277,6 +289,10 @@ class SocketHandler extends AbstractProcessingHandler
*/ */
protected function streamGetMetadata() protected function streamGetMetadata()
{ {
if (!is_resource($this->resource)) {
throw new \LogicException('streamGetMetadata called but $this->resource is not a resource');
}
return stream_get_meta_data($this->resource); return stream_get_meta_data($this->resource);
} }
@@ -325,7 +341,7 @@ class SocketHandler extends AbstractProcessingHandler
} else { } else {
$resource = $this->fsockopen(); $resource = $this->fsockopen();
} }
if (!$resource) { if (is_bool($resource)) {
throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
} }
$this->resource = $resource; $this->resource = $resource;
@@ -361,7 +377,7 @@ class SocketHandler extends AbstractProcessingHandler
} }
$sent += $chunk; $sent += $chunk;
$socketInfo = $this->streamGetMetadata(); $socketInfo = $this->streamGetMetadata();
if ($socketInfo['timed_out']) { if (is_array($socketInfo) && $socketInfo['timed_out']) {
throw new \RuntimeException("Write timed-out"); throw new \RuntimeException("Write timed-out");
} }

View File

@@ -101,34 +101,41 @@ class StreamHandler extends AbstractProcessingHandler
protected function write(array $record): void protected function write(array $record): void
{ {
if (!is_resource($this->stream)) { if (!is_resource($this->stream)) {
if (null === $this->url || '' === $this->url) { $url = $this->url;
if (null === $url || '' === $url) {
throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
} }
$this->createDir(); $this->createDir($url);
$this->errorMessage = null; $this->errorMessage = null;
set_error_handler([$this, 'customErrorHandler']); set_error_handler([$this, 'customErrorHandler']);
$this->stream = fopen($this->url, 'a'); $stream = fopen($url, 'a');
if ($this->filePermission !== null) { if ($this->filePermission !== null) {
@chmod($this->url, $this->filePermission); @chmod($url, $this->filePermission);
} }
restore_error_handler(); restore_error_handler();
if (!is_resource($this->stream)) { if (!is_resource($stream)) {
$this->stream = null; $this->stream = null;
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url));
} }
stream_set_chunk_size($this->stream, self::MAX_CHUNK_SIZE); stream_set_chunk_size($stream, self::MAX_CHUNK_SIZE);
$this->stream = $stream;
}
$stream = $this->stream;
if (!is_resource($stream)) {
throw new \LogicException('No stream was opened yet');
} }
if ($this->useLocking) { if ($this->useLocking) {
// ignoring errors here, there's not much we can do about them // ignoring errors here, there's not much we can do about them
flock($this->stream, LOCK_EX); flock($stream, LOCK_EX);
} }
$this->streamWrite($this->stream, $record); $this->streamWrite($stream, $record);
if ($this->useLocking) { if ($this->useLocking) {
flock($this->stream, LOCK_UN); flock($stream, LOCK_UN);
} }
} }
@@ -165,14 +172,14 @@ class StreamHandler extends AbstractProcessingHandler
return null; return null;
} }
private function createDir(): void private function createDir(string $url): void
{ {
// Do not try to create dir if it has already been tried. // Do not try to create dir if it has already been tried.
if ($this->dirCreated) { if ($this->dirCreated) {
return; return;
} }
$dir = $this->getDirFromStream($this->url); $dir = $this->getDirFromStream($url);
if (null !== $dir && !is_dir($dir)) { if (null !== $dir && !is_dir($dir)) {
$this->errorMessage = null; $this->errorMessage = null;
set_error_handler([$this, 'customErrorHandler']); set_error_handler([$this, 'customErrorHandler']);

View File

@@ -36,8 +36,6 @@ class SyslogHandler extends AbstractSyslogHandler
/** /**
* @param string $ident * @param string $ident
* @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int $logopts Option flags for the openlog() call, defaults to LOG_PID * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID
*/ */
public function __construct(string $ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID) public function __construct(string $ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID)

View File

@@ -45,7 +45,6 @@ class SyslogUdpHandler extends AbstractSyslogHandler
* @param string $host Either IP/hostname or a path to a unix socket (port must be 0 then) * @param string $host Either IP/hostname or a path to a unix socket (port must be 0 then)
* @param int $port Port number, or 0 if $host is a unix socket * @param int $port Port number, or 0 if $host is a unix socket
* @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant
* @param string|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param string $ident Program name or tag for each log message. * @param string $ident Program name or tag for each log message.
* @param int $rfc RFC to format the message for. * @param int $rfc RFC to format the message for.
@@ -88,7 +87,12 @@ class SyslogUdpHandler extends AbstractSyslogHandler
$message = implode("\n", $message); $message = implode("\n", $message);
} }
return preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY);
if (false === $lines) {
throw new \RuntimeException('Could not preg_split: '.preg_last_error().' / '.preg_last_error_msg());
}
return $lines;
} }
/** /**

View File

@@ -27,6 +27,8 @@ use Monolog\Logger;
* @link https://core.telegram.org/bots/api * @link https://core.telegram.org/bots/api
* *
* @author Mazur Alexandr <alexandrmazur96@gmail.com> * @author Mazur Alexandr <alexandrmazur96@gmail.com>
*
* @phpstan-import-type Record from \Monolog\Logger
*/ */
class TelegramBotHandler extends AbstractProcessingHandler class TelegramBotHandler extends AbstractProcessingHandler
{ {
@@ -127,6 +129,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
*/ */
public function handleBatch(array $records): void public function handleBatch(array $records): void
{ {
/** @var Record[] $messages */
$messages = []; $messages = [];
foreach ($records as $record) { foreach ($records as $record) {
@@ -135,6 +138,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
} }
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }
@@ -174,6 +178,9 @@ class TelegramBotHandler extends AbstractProcessingHandler
])); ]));
$result = Curl\Util::execute($ch); $result = Curl\Util::execute($ch);
if (!is_string($result)) {
throw new RuntimeException('Telegram API error. Description: No response');
}
$result = json_decode($result, true); $result = json_decode($result, true);
if ($result['ok'] === false) { if ($result['ok'] === false) {

View File

@@ -118,6 +118,8 @@ class TestHandler extends AbstractProcessingHandler
/** /**
* @param string|int $level Logging level value or name * @param string|int $level Logging level value or name
*
* @phpstan-param Level|LevelName|LogLevel::* $level
*/ */
public function hasRecords($level): bool public function hasRecords($level): bool
{ {
@@ -151,6 +153,8 @@ class TestHandler extends AbstractProcessingHandler
/** /**
* @param string|int $level Logging level value or name * @param string|int $level Logging level value or name
*
* @phpstan-param Level|LevelName|LogLevel::* $level
*/ */
public function hasRecordThatContains(string $message, $level): bool public function hasRecordThatContains(string $message, $level): bool
{ {
@@ -214,10 +218,11 @@ class TestHandler extends AbstractProcessingHandler
if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
$genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
$level = constant('Monolog\Logger::' . strtoupper($matches[2])); $level = constant('Monolog\Logger::' . strtoupper($matches[2]));
if (method_exists($this, $genericMethod)) { $callback = [$this, $genericMethod];
if (is_callable($callback)) {
$args[] = $level; $args[] = $level;
return call_user_func_array([$this, $genericMethod], $args); return call_user_func_array($callback, $args);
} }
} }

View File

@@ -16,15 +16,18 @@ namespace Monolog\Handler;
* and continuing through to give every handler a chance to succeed. * and continuing through to give every handler a chance to succeed.
* *
* @author Craig D'Amelio <craig@damelio.ca> * @author Craig D'Amelio <craig@damelio.ca>
*
* @phpstan-import-type Record from \Monolog\Logger
*/ */
class WhatFailureGroupHandler extends GroupHandler class WhatFailureGroupHandler extends GroupHandler
{ {
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function handle(array $record): bool public function handle(array $record): bool
{ {
if ($this->processors) { if ($this->processors) {
/** @var Record $record */
$record = $this->processRecord($record); $record = $this->processRecord($record);
} }
@@ -40,7 +43,7 @@ class WhatFailureGroupHandler extends GroupHandler
} }
/** /**
* {@inheritdoc} * {@inheritDoc}
*/ */
public function handleBatch(array $records): void public function handleBatch(array $records): void
{ {
@@ -49,6 +52,7 @@ class WhatFailureGroupHandler extends GroupHandler
foreach ($records as $record) { foreach ($records as $record) {
$processed[] = $this->processRecord($record); $processed[] = $this->processRecord($record);
} }
/** @var Record[] $records */
$records = $processed; $records = $processed;
} }

View File

@@ -12,12 +12,16 @@
namespace Monolog\Processor; namespace Monolog\Processor;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LogLevel;
/** /**
* Injects Git branch and Git commit SHA in all records * Injects Git branch and Git commit SHA in all records
* *
* @author Nick Otter * @author Nick Otter
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*
* @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
*/ */
class GitProcessor implements ProcessorInterface class GitProcessor implements ProcessorInterface
{ {
@@ -28,6 +32,8 @@ class GitProcessor implements ProcessorInterface
/** /**
* @param string|int $level The minimum logging level at which this Processor will be triggered * @param string|int $level The minimum logging level at which this Processor will be triggered
*
* @phpstan-param Level|LevelName|LogLevel::* $level
*/ */
public function __construct($level = Logger::DEBUG) public function __construct($level = Logger::DEBUG)
{ {

View File

@@ -12,6 +12,7 @@
namespace Monolog\Processor; namespace Monolog\Processor;
use Monolog\Logger; use Monolog\Logger;
use Psr\Log\LogLevel;
/** /**
* Injects line/file:class/function where the log message came from * Injects line/file:class/function where the log message came from
@@ -23,6 +24,9 @@ use Monolog\Logger;
* triggered the FingersCrossedHandler. * triggered the FingersCrossedHandler.
* *
* @author Jordi Boggiano <j.boggiano@seld.be> * @author Jordi Boggiano <j.boggiano@seld.be>
*
* @phpstan-import-type Level from \Monolog\Logger
* @phpstan-import-type LevelName from \Monolog\Logger
*/ */
class IntrospectionProcessor implements ProcessorInterface class IntrospectionProcessor implements ProcessorInterface
{ {
@@ -41,6 +45,8 @@ class IntrospectionProcessor implements ProcessorInterface
/** /**
* @param string|int $level The minimum logging level at which this Processor will be triggered * @param string|int $level The minimum logging level at which this Processor will be triggered
* @param string[] $skipClassesPartials * @param string[] $skipClassesPartials
*
* @phpstan-param Level|LevelName|LogLevel::* $level
*/ */
public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0)
{ {

View File

@@ -138,6 +138,8 @@ final class Utils
* @param int $code return code of json_last_error function * @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded * @param mixed $data data that was meant to be encoded
* @throws \RuntimeException * @throws \RuntimeException
*
* @return never
*/ */
private static function throwEncodeError(int $code, $data): void private static function throwEncodeError(int $code, $data): void
{ {
@@ -186,6 +188,9 @@ final class Utils
}, },
$data $data
); );
if (!is_string($data)) {
throw new \RuntimeException('Failed to preg_replace_callback: '.preg_last_error().' / '.preg_last_error_msg());
}
$data = str_replace( $data = str_replace(
['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'], ['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'],
['€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'], ['€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'],