diff --git a/phpstan.neon.dist b/phpstan.neon.dist index a56c5030..04ba0f33 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,5 @@ parameters: - level: 5 + level: 6 treatPhpDocTypesAsCertain: false reportUnmatchedIgnoredErrors: false @@ -18,3 +18,8 @@ parameters: - message: '#Method Monolog\\Handler\\LogglyHandler::loadCurlHandle\(\) never returns resource so it can be removed from the return typehint.#' paths: - src/Monolog/Handler/LogglyHandler.php + + # blocked by https://github.com/phpstan/phpstan/issues/5091 + - '#has unknown class Monolog\\Handler\\Record#' + - '#::processRecord#' + - '#is incompatible with native type array.#' diff --git a/src/Monolog/ErrorHandler.php b/src/Monolog/ErrorHandler.php index 3cf351a7..e7d244bb 100644 --- a/src/Monolog/ErrorHandler.php +++ b/src/Monolog/ErrorHandler.php @@ -25,19 +25,30 @@ use Psr\Log\LogLevel; */ class ErrorHandler { + /** @var LoggerInterface */ private $logger; - private $previousExceptionHandler; - private $uncaughtExceptionLevelMap; + /** @var ?callable */ + private $previousExceptionHandler = null; + /** @var array an array of class name to LogLevel::* constant mapping */ + private $uncaughtExceptionLevelMap = []; - private $previousErrorHandler; - private $errorLevelMap; - private $handleOnlyReportedErrors; + /** @var callable|true|null */ + private $previousErrorHandler = null; + /** @var array an array of E_* constant to LogLevel::* constant mapping */ + private $errorLevelMap = []; + /** @var bool */ + private $handleOnlyReportedErrors = true; - private $hasFatalErrorHandler; - private $fatalLevel; - private $reservedMemory; + /** @var bool */ + private $hasFatalErrorHandler = false; + /** @var LogLevel::* */ + private $fatalLevel = LogLevel::ALERT; + /** @var ?string */ + private $reservedMemory = null; + /** @var ?mixed */ private $lastFatalTrace; + /** @var int[] */ private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; public function __construct(LoggerInterface $logger) @@ -50,10 +61,10 @@ class ErrorHandler * * By default it will handle errors, exceptions and fatal errors * - * @param LoggerInterface $logger - * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling - * @param array|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling - * @param string|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling + * @param LoggerInterface $logger + * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling + * @param array|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling + * @param LogLevel::*|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling * @return ErrorHandler */ public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self @@ -73,7 +84,11 @@ class ErrorHandler return $handler; } - public function registerExceptionHandler($levelMap = [], $callPrevious = true): self + /** + * @param array $levelMap an array of class name to LogLevel::* constant mapping + * @return $this + */ + public function registerExceptionHandler(array $levelMap = [], bool $callPrevious = true): self { $prev = set_exception_handler(function (\Throwable $e): void { $this->handleException($e); @@ -91,12 +106,18 @@ class ErrorHandler return $this; } - public function registerErrorHandler(array $levelMap = [], $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true): self + /** + * @param array $levelMap an array of E_* constant to LogLevel::* constant mapping + * @return $this + */ + public function registerErrorHandler(array $levelMap = [], bool $callPrevious = true, int $errorTypes = -1, bool $handleOnlyReportedErrors = true): self { $prev = set_error_handler([$this, 'handleError'], $errorTypes); $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); if ($callPrevious) { $this->previousErrorHandler = $prev ?: true; + } else { + $this->previousErrorHandler = null; } $this->handleOnlyReportedErrors = $handleOnlyReportedErrors; @@ -105,20 +126,23 @@ class ErrorHandler } /** - * @param string|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling - * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done + * @param LogLevel::*|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT + * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done */ public function registerFatalHandler($level = null, int $reservedMemorySize = 20): self { register_shutdown_function([$this, 'handleFatalError']); $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); - $this->fatalLevel = $level; + $this->fatalLevel = null === $level ? LogLevel::ALERT : $level; $this->hasFatalErrorHandler = true; return $this; } + /** + * @return array + */ protected function defaultExceptionLevelMap(): array { return [ @@ -127,6 +151,9 @@ class ErrorHandler ]; } + /** + * @return array + */ protected function defaultErrorLevelMap(): array { return [ @@ -148,7 +175,10 @@ class ErrorHandler ]; } - private function handleException(\Throwable $e) + /** + * @phpstan-return never + */ + private function handleException(\Throwable $e): void { $level = LogLevel::ERROR; foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { @@ -177,11 +207,13 @@ class ErrorHandler /** * @private + * + * @param mixed[] $context */ - public function handleError($code, $message, $file = '', $line = 0, $context = []) + public function handleError(int $code, string $message, string $file = '', int $line = 0, array $context = []): bool { if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { - return; + return false; } // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries @@ -197,7 +229,7 @@ class ErrorHandler if ($this->previousErrorHandler === true) { return false; } elseif ($this->previousErrorHandler) { - return ($this->previousErrorHandler)($code, $message, $file, $line, $context); + return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context); } return true; @@ -206,14 +238,14 @@ class ErrorHandler /** * @private */ - public function handleFatalError() + public function handleFatalError(): void { $this->reservedMemory = ''; $lastError = error_get_last(); if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) { $this->logger->log( - $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, + $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace] ); @@ -226,6 +258,9 @@ class ErrorHandler } } + /** + * @param int $code + */ private static function codeToString($code): string { switch ($code) { diff --git a/src/Monolog/Formatter/ChromePHPFormatter.php b/src/Monolog/Formatter/ChromePHPFormatter.php index 2b4d649c..424282ab 100644 --- a/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/src/Monolog/Formatter/ChromePHPFormatter.php @@ -22,6 +22,8 @@ class ChromePHPFormatter implements FormatterInterface { /** * Translates Monolog log levels to Wildfire levels. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 'log', diff --git a/src/Monolog/Formatter/ElasticaFormatter.php b/src/Monolog/Formatter/ElasticaFormatter.php index 21787bc4..4dcebda7 100644 --- a/src/Monolog/Formatter/ElasticaFormatter.php +++ b/src/Monolog/Formatter/ElasticaFormatter.php @@ -17,6 +17,8 @@ use Elastica\Document; * Format a log message into an Elastica Document * * @author Jelle Vink + * + * @phpstan-import-type Record from \Monolog\Logger */ class ElasticaFormatter extends NormalizerFormatter { @@ -68,8 +70,8 @@ class ElasticaFormatter extends NormalizerFormatter /** * Convert a log message into an Elastica Document - * @param array $record - * @return Document + * + * @phpstan-param Record $record */ protected function getDocument(array $record): Document { diff --git a/src/Monolog/Formatter/ElasticsearchFormatter.php b/src/Monolog/Formatter/ElasticsearchFormatter.php index 84affef3..5442cb79 100644 --- a/src/Monolog/Formatter/ElasticsearchFormatter.php +++ b/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -11,7 +11,7 @@ namespace Monolog\Formatter; -use DateTime; +use DateTimeInterface; /** * Format a log message into an Elasticsearch record @@ -37,7 +37,7 @@ class ElasticsearchFormatter extends NormalizerFormatter public function __construct(string $index, string $type) { // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. - parent::__construct(DateTime::ISO8601); + parent::__construct(DateTimeInterface::ISO8601); $this->index = $index; $this->type = $type; @@ -76,8 +76,8 @@ class ElasticsearchFormatter extends NormalizerFormatter /** * Convert a log message into an Elasticsearch record * - * @param array $record Log message - * @return array + * @param mixed[] $record Log message + * @return mixed[] */ protected function getDocument(array $record): array { diff --git a/src/Monolog/Formatter/FlowdockFormatter.php b/src/Monolog/Formatter/FlowdockFormatter.php index 301b74b2..f7f2e81a 100644 --- a/src/Monolog/Formatter/FlowdockFormatter.php +++ b/src/Monolog/Formatter/FlowdockFormatter.php @@ -36,6 +36,8 @@ class FlowdockFormatter implements FormatterInterface /** * {@inheritdoc} + * + * @return mixed[] */ public function format(array $record): array { @@ -70,6 +72,8 @@ class FlowdockFormatter implements FormatterInterface /** * {@inheritdoc} + * + * @return mixed[][] */ public function formatBatch(array $records): array { diff --git a/src/Monolog/Formatter/FormatterInterface.php b/src/Monolog/Formatter/FormatterInterface.php index 7442134e..19617ec5 100644 --- a/src/Monolog/Formatter/FormatterInterface.php +++ b/src/Monolog/Formatter/FormatterInterface.php @@ -15,6 +15,8 @@ namespace Monolog\Formatter; * Interface for formatters * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ interface FormatterInterface { @@ -23,6 +25,8 @@ interface FormatterInterface * * @param array $record A record to format * @return mixed The formatted record + * + * @phpstan-param Record $record */ public function format(array $record); @@ -31,6 +35,8 @@ interface FormatterInterface * * @param array $records A set of records to format * @return mixed The formatted set of records + * + * @phpstan-param Record[] $records */ public function formatBatch(array $records); } diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 95d7c1d8..3ca84c33 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -47,6 +47,8 @@ class GelfMessageFormatter extends NormalizerFormatter /** * Translates Monolog log levels to Graylog2 log priorities. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 7, diff --git a/src/Monolog/Formatter/HtmlFormatter.php b/src/Monolog/Formatter/HtmlFormatter.php index 90db3f2a..10a4311c 100644 --- a/src/Monolog/Formatter/HtmlFormatter.php +++ b/src/Monolog/Formatter/HtmlFormatter.php @@ -25,6 +25,8 @@ class HtmlFormatter extends NormalizerFormatter { /** * Translates Monolog log levels to html color priorities. + * + * @var array */ protected $logLevels = [ Logger::DEBUG => '#CCCCCC', @@ -79,7 +81,6 @@ class HtmlFormatter extends NormalizerFormatter /** * Formats a log record. * - * @param array $record A record to format * @return string The formatted record */ public function format(array $record): string @@ -113,7 +114,6 @@ class HtmlFormatter extends NormalizerFormatter /** * Formats a set of log records. * - * @param array $records A set of records to format * @return string The formatted set of records */ public function formatBatch(array $records): string @@ -126,6 +126,9 @@ class HtmlFormatter extends NormalizerFormatter return $message; } + /** + * @param mixed $data + */ protected function convertToString($data): string { if (null === $data || is_scalar($data)) { diff --git a/src/Monolog/Formatter/JsonFormatter.php b/src/Monolog/Formatter/JsonFormatter.php index 59d9f0a0..16421e22 100644 --- a/src/Monolog/Formatter/JsonFormatter.php +++ b/src/Monolog/Formatter/JsonFormatter.php @@ -19,21 +19,26 @@ use Throwable; * This can be useful to log to databases or remote APIs * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ class JsonFormatter extends NormalizerFormatter { public const BATCH_MODE_JSON = 1; public const BATCH_MODE_NEWLINES = 2; + /** @var self::BATCH_MODE_* */ protected $batchMode; + /** @var bool */ protected $appendNewline; + /** @var bool */ protected $ignoreEmptyContextAndExtra; - - /** - * @var bool - */ + /** @var bool */ protected $includeStacktraces = false; + /** + * @param self::BATCH_MODE_* $batchMode + */ public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false) { $this->batchMode = $batchMode; @@ -101,6 +106,9 @@ class JsonFormatter extends NormalizerFormatter } } + /** + * @return void + */ public function includeStacktraces(bool $include = true) { $this->includeStacktraces = $include; @@ -108,6 +116,8 @@ class JsonFormatter extends NormalizerFormatter /** * Return a JSON-encoded array of records. + * + * @phpstan-param Record[] $records */ protected function formatBatchJson(array $records): string { @@ -117,6 +127,8 @@ class JsonFormatter extends NormalizerFormatter /** * Use new lines to separate records instead of a * JSON-encoded array. + * + * @phpstan-param Record[] $records */ protected function formatBatchNewlines(array $records): string { @@ -175,6 +187,8 @@ class JsonFormatter extends NormalizerFormatter /** * Normalizes given exception with or without its own stack trace based on * `includeStacktraces` property. + * + * {@inheritDoc} */ protected function normalizeException(Throwable $e, int $depth = 0): array { diff --git a/src/Monolog/Formatter/LineFormatter.php b/src/Monolog/Formatter/LineFormatter.php index de27f2f7..fa87cf35 100644 --- a/src/Monolog/Formatter/LineFormatter.php +++ b/src/Monolog/Formatter/LineFormatter.php @@ -25,9 +25,13 @@ class LineFormatter extends NormalizerFormatter { public const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; + /** @var string */ protected $format; + /** @var bool */ protected $allowInlineLineBreaks; + /** @var bool */ protected $ignoreEmptyContextAndExtra; + /** @var bool */ protected $includeStacktraces; /** @@ -44,7 +48,7 @@ class LineFormatter extends NormalizerFormatter parent::__construct($dateFormat); } - public function includeStacktraces(bool $include = true) + public function includeStacktraces(bool $include = true): void { $this->includeStacktraces = $include; if ($this->includeStacktraces) { @@ -52,12 +56,12 @@ class LineFormatter extends NormalizerFormatter } } - public function allowInlineLineBreaks(bool $allow = true) + public function allowInlineLineBreaks(bool $allow = true): void { $this->allowInlineLineBreaks = $allow; } - public function ignoreEmptyContextAndExtra(bool $ignore = true) + public function ignoreEmptyContextAndExtra(bool $ignore = true): void { $this->ignoreEmptyContextAndExtra = $ignore; } @@ -121,6 +125,9 @@ class LineFormatter extends NormalizerFormatter return $message; } + /** + * @param mixed $value + */ public function stringify($value): string { return $this->replaceNewlines($this->convertToString($value)); @@ -139,6 +146,9 @@ class LineFormatter extends NormalizerFormatter return $str; } + /** + * @param mixed $data + */ protected function convertToString($data): string { if (null === $data || is_bool($data)) { diff --git a/src/Monolog/Formatter/MongoDBFormatter.php b/src/Monolog/Formatter/MongoDBFormatter.php index 9241b1b7..0c1197ed 100644 --- a/src/Monolog/Formatter/MongoDBFormatter.php +++ b/src/Monolog/Formatter/MongoDBFormatter.php @@ -21,8 +21,11 @@ use Monolog\Utils; */ class MongoDBFormatter implements FormatterInterface { + /** @var bool */ private $exceptionTraceAsString; + /** @var int */ private $maxNestingLevel; + /** @var bool */ private $isLegacyMongoExt; /** @@ -39,6 +42,8 @@ class MongoDBFormatter implements FormatterInterface /** * {@inheritDoc} + * + * @return scalar[] */ public function format(array $record): array { @@ -47,40 +52,48 @@ class MongoDBFormatter implements FormatterInterface /** * {@inheritDoc} + * + * @return array */ public function formatBatch(array $records): array { + $formatted = []; foreach ($records as $key => $record) { - $records[$key] = $this->format($record); + $formatted[$key] = $this->format($record); } - return $records; + return $formatted; } /** - * @return array|string Array except when max nesting level is reached then a string "[...]" + * @param mixed[] $array + * @return mixed[]|string Array except when max nesting level is reached then a string "[...]" */ - protected function formatArray(array $record, int $nestingLevel = 0) + protected function formatArray(array $array, int $nestingLevel = 0) { - if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) { - foreach ($record as $name => $value) { - if ($value instanceof \DateTimeInterface) { - $record[$name] = $this->formatDate($value, $nestingLevel + 1); - } elseif ($value instanceof \Throwable) { - $record[$name] = $this->formatException($value, $nestingLevel + 1); - } elseif (is_array($value)) { - $record[$name] = $this->formatArray($value, $nestingLevel + 1); - } elseif (is_object($value)) { - $record[$name] = $this->formatObject($value, $nestingLevel + 1); - } - } - } else { - $record = '[...]'; + if ($this->maxNestingLevel > 0 && $nestingLevel > $this->maxNestingLevel) { + return '[...]'; } - return $record; + foreach ($array as $name => $value) { + if ($value instanceof \DateTimeInterface) { + $array[$name] = $this->formatDate($value, $nestingLevel + 1); + } elseif ($value instanceof \Throwable) { + $array[$name] = $this->formatException($value, $nestingLevel + 1); + } elseif (is_array($value)) { + $array[$name] = $this->formatArray($value, $nestingLevel + 1); + } elseif (is_object($value)) { + $array[$name] = $this->formatObject($value, $nestingLevel + 1); + } + } + + return $array; } + /** + * @param mixed $value + * @return mixed[]|string + */ protected function formatObject($value, int $nestingLevel) { $objectVars = get_object_vars($value); @@ -89,6 +102,9 @@ class MongoDBFormatter implements FormatterInterface return $this->formatArray($objectVars, $nestingLevel); } + /** + * @return mixed[]|string + */ protected function formatException(\Throwable $exception, int $nestingLevel) { $formattedException = [ diff --git a/src/Monolog/Formatter/NormalizerFormatter.php b/src/Monolog/Formatter/NormalizerFormatter.php index 4daef814..29288543 100644 --- a/src/Monolog/Formatter/NormalizerFormatter.php +++ b/src/Monolog/Formatter/NormalizerFormatter.php @@ -123,7 +123,7 @@ class NormalizerFormatter implements FormatterInterface /** * @param mixed $data - * @return int|bool|string|null|array + * @return scalar|array */ protected function normalize($data, int $depth = 0) { @@ -189,7 +189,7 @@ class NormalizerFormatter implements FormatterInterface } /** - * @return array + * @return mixed[] */ protected function normalizeException(Throwable $e, int $depth = 0) { @@ -248,6 +248,9 @@ class NormalizerFormatter implements FormatterInterface return Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors); } + /** + * @return string + */ protected function formatDate(\DateTimeInterface $date) { // in case the date format isn't custom then we defer to the custom DateTimeImmutable @@ -259,12 +262,12 @@ class NormalizerFormatter implements FormatterInterface return $date->format($this->dateFormat); } - public function addJsonEncodeOption(int $option) + public function addJsonEncodeOption(int $option): void { $this->jsonEncodeOptions |= $option; } - public function removeJsonEncodeOption(int $option) + public function removeJsonEncodeOption(int $option): void { $this->jsonEncodeOptions &= ~$option; } diff --git a/src/Monolog/Formatter/ScalarFormatter.php b/src/Monolog/Formatter/ScalarFormatter.php index 17402041..c8889b5b 100644 --- a/src/Monolog/Formatter/ScalarFormatter.php +++ b/src/Monolog/Formatter/ScalarFormatter.php @@ -21,6 +21,8 @@ class ScalarFormatter extends NormalizerFormatter { /** * {@inheritdoc} + * + * @phpstan-return scalar[] $record */ public function format(array $record): array { diff --git a/src/Monolog/Formatter/WildfireFormatter.php b/src/Monolog/Formatter/WildfireFormatter.php index 20288ab5..5ee94d71 100644 --- a/src/Monolog/Formatter/WildfireFormatter.php +++ b/src/Monolog/Formatter/WildfireFormatter.php @@ -19,11 +19,15 @@ use Monolog\Logger; * @author Eric Clemmons (@ericclemmons) * @author Christophe Coevoet * @author Kirill chEbba Chebunin + * + * @phpstan-import-type Level from \Monolog\Logger */ class WildfireFormatter extends NormalizerFormatter { /** * Translates Monolog log levels to Wildfire levels. + * + * @var array */ private $logLevels = [ Logger::DEBUG => 'LOG', @@ -49,6 +53,8 @@ class WildfireFormatter extends NormalizerFormatter /** * {@inheritdoc} + * + * @return string */ public function format(array $record): string { @@ -108,6 +114,8 @@ class WildfireFormatter extends NormalizerFormatter /** * {@inheritdoc} + * + * @phpstan-return never */ public function formatBatch(array $records) { @@ -116,7 +124,8 @@ class WildfireFormatter extends NormalizerFormatter /** * {@inheritdoc} - * @return int|bool|string|null|array|object + * + * @return scalar|array|object */ protected function normalize($data, int $depth = 0) { diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index c9405bfb..6d0fdae2 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -18,10 +18,17 @@ use Monolog\ResettableInterface; * Base Handler class providing basic level/bubble support * * @author Jordi Boggiano + * + * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractHandler extends Handler implements ResettableInterface { + /** + * @var int + * @phpstan-var Level + */ protected $level = Logger::DEBUG; + /** @var bool */ protected $bubble = true; /** @@ -59,6 +66,8 @@ abstract class AbstractHandler extends Handler implements ResettableInterface * Gets minimum logging level at which this handler will be triggered. * * @return int + * + * @phpstan-return Level */ public function getLevel(): int { @@ -90,6 +99,9 @@ abstract class AbstractHandler extends Handler implements ResettableInterface return $this->bubble; } + /** + * {@inheritDoc} + */ public function reset() { } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index 1100260c..eaff86ac 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -18,6 +18,10 @@ namespace Monolog\Handler; * * @author Jordi Boggiano * @author Christophe Coevoet + * + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed} */ abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { @@ -46,9 +50,14 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc /** * Writes the record down to the log of the implementing handler + * + * @phpstan-param FormattedRecord $record */ abstract protected function write(array $record): void; + /** + * @return void + */ public function reset() { parent::reset(); diff --git a/src/Monolog/Handler/AbstractSyslogHandler.php b/src/Monolog/Handler/AbstractSyslogHandler.php index b7f249d7..55a3384d 100644 --- a/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/src/Monolog/Handler/AbstractSyslogHandler.php @@ -17,13 +17,18 @@ use Monolog\Formatter\LineFormatter; /** * Common syslog functionality + * + * @phpstan-import-type Level from \Monolog\Logger */ abstract class AbstractSyslogHandler extends AbstractProcessingHandler { + /** @var int */ protected $facility; /** * Translates Monolog log levels to syslog log priorities. + * @var array + * @phpstan-var array */ protected $logLevels = [ Logger::DEBUG => LOG_DEBUG, @@ -38,6 +43,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler /** * List of valid log facility names. + * @var array */ protected $facilities = [ 'auth' => LOG_AUTH, diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php index 33fffccd..d91f1b68 100644 --- a/src/Monolog/Handler/AmqpHandler.php +++ b/src/Monolog/Handler/AmqpHandler.php @@ -18,6 +18,9 @@ use PhpAmqpLib\Message\AMQPMessage; use PhpAmqpLib\Channel\AMQPChannel; use AMQPExchange; +/** + * @phpstan-import-type Record from \Monolog\Logger + */ class AmqpHandler extends AbstractProcessingHandler { /** @@ -108,6 +111,8 @@ class AmqpHandler extends AbstractProcessingHandler /** * Gets the routing key for the AMQP exchange + * + * @phpstan-param Record $record */ protected function getRoutingKey(array $record): string { diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 310591c7..6245def4 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -19,10 +19,14 @@ use Monolog\Utils; * Handler sending logs to browser's javascript console with no browser extension required * * @author Olivier Poitrey + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class BrowserConsoleHandler extends AbstractProcessingHandler { + /** @var bool */ protected static $initialized = false; + /** @var FormattedRecord[] */ protected static $records = []; /** @@ -165,6 +169,9 @@ class BrowserConsoleHandler extends AbstractProcessingHandler return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } + /** + * @return string[] + */ private static function handleStyles(string $formatted): array { $args = []; @@ -205,6 +212,10 @@ class BrowserConsoleHandler extends AbstractProcessingHandler }, $style); } + /** + * @param mixed[] $dict + * @return mixed[] + */ private static function dump(string $title, array $dict): array { $script = []; @@ -229,13 +240,22 @@ class BrowserConsoleHandler extends AbstractProcessingHandler return '"' . addcslashes($arg, "\"\n\\") . '"'; } + /** + * @param mixed $args + */ private static function call(...$args): string { $method = array_shift($args); + if (!is_string($method)) { + throw new \UnexpectedValueException('Expected the first arg to be a string, got: '.var_export($method, true)); + } return static::call_array($method, $args); } + /** + * @param mixed[] $args + */ private static function call_array(string $method, array $args): string { return 'c.' . $method . '(' . implode(', ', $args) . ');'; diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index fbf5effa..874fd0d9 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -22,6 +22,8 @@ use Monolog\Formatter\FormatterInterface; * sending one per log message. * * @author Christophe Coevoet + * + * @phpstan-import-type Record from \Monolog\Logger */ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { @@ -29,10 +31,15 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa /** @var HandlerInterface */ protected $handler; + /** @var int */ protected $bufferSize = 0; + /** @var int */ protected $bufferLimit; + /** @var bool */ protected $flushOnOverflow; + /** @var Record[] */ protected $buffer = []; + /** @var bool */ protected $initialized = false; /** diff --git a/src/Monolog/Handler/ChromePHPHandler.php b/src/Monolog/Handler/ChromePHPHandler.php index 44dbf0d4..d9b58767 100644 --- a/src/Monolog/Handler/ChromePHPHandler.php +++ b/src/Monolog/Handler/ChromePHPHandler.php @@ -42,6 +42,7 @@ class ChromePHPHandler extends AbstractProcessingHandler */ protected const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; + /** @var bool */ protected static $initialized = false; /** @@ -53,12 +54,14 @@ class ChromePHPHandler extends AbstractProcessingHandler */ protected static $overflowed = false; + /** @var mixed[] */ protected static $json = [ 'version' => self::VERSION, 'columns' => ['label', 'log', 'backtrace', 'type'], 'rows' => [], ]; + /** @var bool */ protected static $sendHeaders = true; /** diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php index b2d1e189..52657613 100644 --- a/src/Monolog/Handler/CouchDBHandler.php +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -22,8 +22,12 @@ use Monolog\Logger; */ class CouchDBHandler extends AbstractProcessingHandler { + /** @var mixed[] */ private $options; + /** + * @param mixed[] $options + */ public function __construct(array $options = [], $level = Logger::DEBUG, bool $bubble = true) { $this->options = array_merge([ diff --git a/src/Monolog/Handler/CubeHandler.php b/src/Monolog/Handler/CubeHandler.php index 00d38e99..d40ac435 100644 --- a/src/Monolog/Handler/CubeHandler.php +++ b/src/Monolog/Handler/CubeHandler.php @@ -22,11 +22,17 @@ use Monolog\Utils; */ class CubeHandler extends AbstractProcessingHandler { - private $udpConnection; - private $httpConnection; + /** @var resource|\Socket|null */ + private $udpConnection = null; + /** @var resource|\CurlHandle|null */ + private $httpConnection = null; + /** @var string */ private $scheme; + /** @var string */ private $host; + /** @var int */ private $port; + /** @var string[] */ private $acceptedSchemes = ['http', 'udp']; /** @@ -53,7 +59,7 @@ class CubeHandler extends AbstractProcessingHandler $this->scheme = $urlInfo['scheme']; $this->host = $urlInfo['host']; - $this->port = $urlInfo['port']; + $this->port = (int) $urlInfo['port']; parent::__construct($level, $bubble); } diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index cc0b6c39..7213e8ee 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -20,6 +20,7 @@ use CurlHandle; */ final class Util { + /** @var array */ private static $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index 864c29ae..be27c03a 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -32,6 +32,8 @@ use Monolog\Logger; * same way. * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ class DeduplicationHandler extends BufferHandler { @@ -100,6 +102,9 @@ class DeduplicationHandler extends BufferHandler } } + /** + * @phpstan-param Record $record + */ private function isDuplicate(array $record): bool { if (!file_exists($this->deduplicationStore)) { @@ -166,6 +171,9 @@ class DeduplicationHandler extends BufferHandler $this->gc = false; } + /** + * @phpstan-param Record $record + */ private function appendRecord(array $record): void { file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php index b80490d1..ebd52c3a 100644 --- a/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -23,6 +23,7 @@ use Doctrine\CouchDB\CouchDBClient; */ class DoctrineCouchDBHandler extends AbstractProcessingHandler { + /** @var CouchDBClient */ private $client; public function __construct(CouchDBClient $client, $level = Logger::DEBUG, bool $bubble = true) diff --git a/src/Monolog/Handler/DynamoDbHandler.php b/src/Monolog/Handler/DynamoDbHandler.php index 29f340a0..9948ef19 100644 --- a/src/Monolog/Handler/DynamoDbHandler.php +++ b/src/Monolog/Handler/DynamoDbHandler.php @@ -86,6 +86,10 @@ class DynamoDbHandler extends AbstractProcessingHandler ]); } + /** + * @param mixed[] $record + * @return mixed[] + */ protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { diff --git a/src/Monolog/Handler/ElasticaHandler.php b/src/Monolog/Handler/ElasticaHandler.php index 7af68fef..3c6f8795 100644 --- a/src/Monolog/Handler/ElasticaHandler.php +++ b/src/Monolog/Handler/ElasticaHandler.php @@ -11,6 +11,7 @@ namespace Monolog\Handler; +use Elastica\Document; use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\ElasticaFormatter; use Monolog\Logger; @@ -41,13 +42,13 @@ class ElasticaHandler extends AbstractProcessingHandler protected $client; /** - * @var array Handler config options + * @var mixed[] Handler config options */ protected $options = []; /** * @param Client $client Elastica Client object - * @param array $options Handler configuration + * @param mixed[] $options Handler configuration * @param int|string $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ @@ -85,6 +86,9 @@ class ElasticaHandler extends AbstractProcessingHandler throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); } + /** + * @return mixed[] + */ public function getOptions(): array { return $this->options; @@ -109,6 +113,9 @@ class ElasticaHandler extends AbstractProcessingHandler /** * Use Elasticsearch bulk API to send list of documents + * + * @param Document[] $documents + * * @throws \RuntimeException */ protected function bulkSend(array $documents): void diff --git a/src/Monolog/Handler/ElasticsearchHandler.php b/src/Monolog/Handler/ElasticsearchHandler.php index 7a7ef059..fddcc5be 100644 --- a/src/Monolog/Handler/ElasticsearchHandler.php +++ b/src/Monolog/Handler/ElasticsearchHandler.php @@ -49,13 +49,13 @@ class ElasticsearchHandler extends AbstractProcessingHandler protected $client; /** - * @var array Handler config options + * @var mixed[] Handler config options */ protected $options = []; /** * @param Client $client Elasticsearch Client object - * @param array $options Handler configuration + * @param mixed[] $options Handler configuration * @param string|int $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ @@ -96,7 +96,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler /** * Getter options * - * @return array + * @return mixed[] */ public function getOptions(): array { @@ -123,7 +123,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler /** * Use Elasticsearch bulk API to send list of documents * - * @param array $records + * @param array[] $records Records + _index/_type keys * @throws \RuntimeException */ protected function bulkSend(array $records): void @@ -162,7 +162,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler * * Only the first error is converted into an exception. * - * @param array $responses returned by $this->client->bulk() + * @param mixed[] $responses returned by $this->client->bulk() */ protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException { @@ -178,7 +178,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler /** * Creates elasticsearch exception from error array * - * @param array $error + * @param mixed[] $error */ protected function createExceptionFromError(array $error): ElasticsearchRuntimeException { diff --git a/src/Monolog/Handler/ErrorLogHandler.php b/src/Monolog/Handler/ErrorLogHandler.php index 737c0705..fb0ebf2f 100644 --- a/src/Monolog/Handler/ErrorLogHandler.php +++ b/src/Monolog/Handler/ErrorLogHandler.php @@ -25,7 +25,9 @@ class ErrorLogHandler extends AbstractProcessingHandler public const OPERATING_SYSTEM = 0; public const SAPI = 4; + /** @var int */ protected $messageType; + /** @var bool */ protected $expandNewlines; /** @@ -49,7 +51,7 @@ class ErrorLogHandler extends AbstractProcessingHandler } /** - * @return array With all available types + * @return int[] With all available types */ public static function getAvailableTypes(): array { diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 36e2cd0f..cad7637d 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -14,6 +14,7 @@ namespace Monolog\Handler; use Monolog\Logger; use Monolog\ResettableInterface; use Monolog\Formatter\FormatterInterface; +use Psr\Log\LogLevel; /** * Simple handler wrapper that filters records based on a list of levels @@ -22,6 +23,10 @@ use Monolog\Formatter\FormatterInterface; * * @author Hennadiy Verkh * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class FilterHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { @@ -30,7 +35,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * Handler or factory callable($record, $this) * - * @var callable|\Monolog\Handler\HandlerInterface + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface */ protected $handler; @@ -38,6 +44,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * Minimum level for logs that are passed to handler * * @var int[] + * @phpstan-var Level[] */ protected $acceptedLevels; @@ -49,12 +56,14 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese protected $bubble; /** - * @psalm-param HandlerInterface|callable(?array, HandlerInterface): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int|string $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * + * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList */ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) { @@ -67,6 +76,9 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese } } + /** + * @phpstan-return Level[] + */ public function getAcceptedLevels(): array { return array_flip($this->acceptedLevels); @@ -75,6 +87,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese /** * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array + * + * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList */ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self { @@ -141,6 +155,8 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface + * + * @phpstan-param Record $record */ public function getHandler(array $record = null) { diff --git a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index 1ba99c73..0aa5607b 100644 --- a/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -15,11 +15,15 @@ namespace Monolog\Handler\FingersCrossed; * Interface for activation strategies for the FingersCrossedHandler. * * @author Johannes M. Schmitt + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ActivationStrategyInterface { /** * Returns whether the given record activates the handler. + * + * @phpstan-param Record $record */ public function isHandlerActivated(array $record): bool; } diff --git a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index f98ecfac..599d76c6 100644 --- a/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -32,6 +32,9 @@ use Monolog\Logger; * * * @author Mike Meessen + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { @@ -41,13 +44,15 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface private $defaultActionLevel; /** - * @var array + * @var array */ private $channelToActionLevel; /** - * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $channelToActionLevel An array that maps channel names to action levels. + * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $channelToActionLevel An array that maps channel names to action levels. + * + * @phpstan-param array $channelToActionLevel */ public function __construct($defaultActionLevel, array $channelToActionLevel = []) { @@ -55,6 +60,9 @@ class ChannelLevelActivationStrategy implements ActivationStrategyInterface $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } + /** + * @phpstan-param Record $record + */ public function isHandlerActivated(array $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 2253e71f..45801ec7 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -32,23 +32,40 @@ use Monolog\Formatter\FormatterInterface; * Monolog\Handler\FingersCrossed\ namespace. * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; - /** @var HandlerInterface */ + /** + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface + */ protected $handler; + /** @var ActivationStrategyInterface */ protected $activationStrategy; + /** @var bool */ protected $buffering = true; + /** @var int */ protected $bufferSize; + /** @var Record[] */ protected $buffer = []; + /** @var bool */ protected $stopBuffering; + /** + * @var ?int + * @phpstan-var ?Level + */ protected $passthruLevel; + /** @var bool */ protected $bubble; /** - * @psalm-param HandlerInterface|callable(?array, FingersCrossedHandler): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). * @param int|string|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated @@ -171,7 +188,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa return $record['level'] >= $level; }); if (count($this->buffer) > 0) { - $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); + $this->getHandler(end($this->buffer))->handleBatch($this->buffer); } } @@ -185,6 +202,8 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface + * + * @phpstan-param Record $record */ public function getHandler(array $record = null) { diff --git a/src/Monolog/Handler/FirePHPHandler.php b/src/Monolog/Handler/FirePHPHandler.php index c9638630..f57677c8 100644 --- a/src/Monolog/Handler/FirePHPHandler.php +++ b/src/Monolog/Handler/FirePHPHandler.php @@ -18,6 +18,8 @@ use Monolog\Formatter\FormatterInterface; * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. * * @author Eric Clemmons (@ericclemmons) + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FirePHPHandler extends AbstractProcessingHandler { @@ -45,6 +47,7 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet + * @var bool */ protected static $initialized = false; @@ -54,14 +57,15 @@ class FirePHPHandler extends AbstractProcessingHandler */ protected static $messageIndex = 1; + /** @var bool */ protected static $sendHeaders = true; /** * Base header creation function used by init headers & record headers * - * @param array $meta Wildfire Plugin, Protocol & Structure Indexes - * @param string $message Log message - * @return array Complete header string ready for the client as key and message as value + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * @return array Complete header string ready for the client as key and message as value */ protected function createHeader(array $meta, string $message): array { @@ -73,7 +77,11 @@ class FirePHPHandler extends AbstractProcessingHandler /** * Creates message header from record * + * @return array + * * @see createHeader() + * + * @phpstan-param FormattedRecord $record */ protected function createRecordHeader(array $record): array { @@ -98,6 +106,8 @@ class FirePHPHandler extends AbstractProcessingHandler * * @see createHeader() * @see sendHeader() + * + * @return array */ protected function getInitHeaders(): array { @@ -124,7 +134,6 @@ class FirePHPHandler extends AbstractProcessingHandler * * @see sendHeader() * @see sendInitHeaders() - * @param array $record */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/FleepHookHandler.php b/src/Monolog/Handler/FleepHookHandler.php index 5087009f..81584407 100644 --- a/src/Monolog/Handler/FleepHookHandler.php +++ b/src/Monolog/Handler/FleepHookHandler.php @@ -22,6 +22,8 @@ use Monolog\Logger; * * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation * @author Ando Roots + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FleepHookHandler extends SocketHandler { @@ -104,6 +106,8 @@ class FleepHookHandler extends SocketHandler /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { diff --git a/src/Monolog/Handler/FlowdockHandler.php b/src/Monolog/Handler/FlowdockHandler.php index 062af418..c12fe334 100644 --- a/src/Monolog/Handler/FlowdockHandler.php +++ b/src/Monolog/Handler/FlowdockHandler.php @@ -26,6 +26,8 @@ use Monolog\Formatter\FormatterInterface; * * @author Dominik Liebler * @see https://www.flowdock.com/api/push + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FlowdockHandler extends SocketHandler { @@ -72,8 +74,6 @@ class FlowdockHandler extends SocketHandler /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { @@ -94,6 +94,8 @@ class FlowdockHandler extends SocketHandler /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index a7d8a317..7265d87a 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -25,6 +25,7 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset /** @var HandlerInterface[] */ protected $handlers; + /** @var bool */ protected $bubble; /** diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index 68aed186..affcc51f 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -15,6 +15,9 @@ namespace Monolog\Handler; * Interface that all Monolog Handlers must implement * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface { @@ -30,6 +33,8 @@ interface HandlerInterface * @param array $record Partial log record containing only a level key * * @return bool + * + * @phpstan-param array{level: Level} $record */ public function isHandling(array $record): bool; @@ -46,6 +51,8 @@ interface HandlerInterface * @param array $record The record to handle * @return bool true means that this handler handled the record, and that bubbling is not permitted. * false means the record was either not processed or that this handler allows bubbling. + * + * @phpstan-param Record $record */ public function handle(array $record): bool; @@ -53,6 +60,8 @@ interface HandlerInterface * Handles a set of records at once. * * @param array $records The records to handle (an array of record arrays) + * + * @phpstan-param Record[] $records */ public function handleBatch(array $records): void; diff --git a/src/Monolog/Handler/IFTTTHandler.php b/src/Monolog/Handler/IFTTTHandler.php index 921c9f24..c8ed6ff7 100644 --- a/src/Monolog/Handler/IFTTTHandler.php +++ b/src/Monolog/Handler/IFTTTHandler.php @@ -27,7 +27,9 @@ use Monolog\Utils; */ class IFTTTHandler extends AbstractProcessingHandler { + /** @var string */ private $eventName; + /** @var string */ private $secretKey; /** diff --git a/src/Monolog/Handler/LogglyHandler.php b/src/Monolog/Handler/LogglyHandler.php index 6fc7066c..cd110bf7 100644 --- a/src/Monolog/Handler/LogglyHandler.php +++ b/src/Monolog/Handler/LogglyHandler.php @@ -37,8 +37,10 @@ class LogglyHandler extends AbstractProcessingHandler */ protected $curlHandlers = []; + /** @var string */ protected $token; + /** @var string[] */ protected $tag = []; /** diff --git a/src/Monolog/Handler/MailHandler.php b/src/Monolog/Handler/MailHandler.php index 7a7b787d..a0148a58 100644 --- a/src/Monolog/Handler/MailHandler.php +++ b/src/Monolog/Handler/MailHandler.php @@ -18,6 +18,8 @@ use Monolog\Formatter\HtmlFormatter; * Base class for all mail handlers * * @author Gyula Sallai + * + * @phpstan-import-type Record from \Monolog\Logger */ abstract class MailHandler extends AbstractProcessingHandler { @@ -45,6 +47,8 @@ abstract class MailHandler extends AbstractProcessingHandler * * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content + * + * @phpstan-param Record[] $records */ abstract protected function send(string $content, array $records): void; @@ -56,6 +60,10 @@ abstract class MailHandler extends AbstractProcessingHandler $this->send((string) $record['formatted'], [$record]); } + /** + * @phpstan-param Record[] $records + * @phpstan-return Record + */ protected function getHighestRecord(array $records): array { $highestRecord = null; diff --git a/src/Monolog/Handler/MongoDBHandler.php b/src/Monolog/Handler/MongoDBHandler.php index e7539174..477bcd64 100644 --- a/src/Monolog/Handler/MongoDBHandler.php +++ b/src/Monolog/Handler/MongoDBHandler.php @@ -33,8 +33,11 @@ use Monolog\Formatter\MongoDBFormatter; */ class MongoDBHandler extends AbstractProcessingHandler { + /** @var \MongoDB\Collection */ private $collection; + /** @var Client|Manager */ private $manager; + /** @var string */ private $namespace; /** diff --git a/src/Monolog/Handler/NativeMailerHandler.php b/src/Monolog/Handler/NativeMailerHandler.php index cd205611..c2ef64e6 100644 --- a/src/Monolog/Handler/NativeMailerHandler.php +++ b/src/Monolog/Handler/NativeMailerHandler.php @@ -24,7 +24,7 @@ class NativeMailerHandler extends MailHandler { /** * The email addresses to which the message will be sent - * @var array + * @var string[] */ protected $to; @@ -36,13 +36,13 @@ class NativeMailerHandler extends MailHandler /** * Optional headers for the message - * @var array + * @var string[] */ protected $headers = []; /** * Optional parameters for the message - * @var array + * @var string[] */ protected $parameters = []; @@ -65,7 +65,7 @@ class NativeMailerHandler extends MailHandler protected $encoding = 'utf-8'; /** - * @param string|array $to The receiver of the mail + * @param string|string[] $to The receiver of the mail * @param string $subject The subject of the mail * @param string $from The sender of the mail * @param string|int $level The minimum logging level at which this handler will be triggered @@ -84,7 +84,7 @@ class NativeMailerHandler extends MailHandler /** * Add headers to the message * - * @param string|array $headers Custom added headers + * @param string|string[] $headers Custom added headers */ public function addHeader($headers): self { @@ -101,7 +101,7 @@ class NativeMailerHandler extends MailHandler /** * Add parameters to the message * - * @param string|array $parameters Custom added parameters + * @param string|string[] $parameters Custom added parameters */ public function addParameter($parameters): self { diff --git a/src/Monolog/Handler/NewRelicHandler.php b/src/Monolog/Handler/NewRelicHandler.php index 177ad21a..25df5427 100644 --- a/src/Monolog/Handler/NewRelicHandler.php +++ b/src/Monolog/Handler/NewRelicHandler.php @@ -30,14 +30,14 @@ class NewRelicHandler extends AbstractProcessingHandler /** * Name of the New Relic application that will receive logs from this handler. * - * @var string|null + * @var ?string */ protected $appName; /** * Name of the current transaction * - * @var string|null + * @var ?string */ protected $transactionName; @@ -135,6 +135,8 @@ class NewRelicHandler extends AbstractProcessingHandler /** * Returns the appname where this log should be sent. Each log can override the default appname, set in this * handler's constructor, by providing the appname in it's context. + * + * @param mixed[] $context */ protected function getAppName(array $context): ?string { @@ -148,6 +150,8 @@ class NewRelicHandler extends AbstractProcessingHandler /** * Returns the name of the current transaction. Each log can override the default transaction name, set in this * handler's constructor, by providing the transaction_name in it's context + * + * @param mixed[] $context */ protected function getTransactionName(array $context): ?string { diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 4c309865..04760749 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -87,10 +87,7 @@ class OverflowHandler extends AbstractHandler implements FormattableHandlerInter * Unless the bubbling is interrupted (by returning true), the Logger class will keep on * calling further handlers in the stack with a given log record. * - * @param array $record The record to handle - * - * @return Boolean true means that this handler handled the record, and that bubbling is not permitted. - * false means the record was either not processed or that this handler allows bubbling. + * {@inheritdoc} */ public function handle(array $record): bool { diff --git a/src/Monolog/Handler/PHPConsoleHandler.php b/src/Monolog/Handler/PHPConsoleHandler.php index 94802d0b..d596c046 100644 --- a/src/Monolog/Handler/PHPConsoleHandler.php +++ b/src/Monolog/Handler/PHPConsoleHandler.php @@ -37,9 +37,12 @@ use PhpConsole\Helper; * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin + * + * @phpstan-import-type Record from \Monolog\Logger */ class PHPConsoleHandler extends AbstractProcessingHandler { + /** @var array */ private $options = [ 'enabled' => true, // bool Is PHP Console server enabled 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... @@ -67,10 +70,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler private $connector; /** - * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details - * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param string|int $level The minimum logging level at which this handler will be triggered. - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not. + * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details + * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) + * @param string|int $level The minimum logging level at which this handler will be triggered. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not. * @throws \RuntimeException */ public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) @@ -83,6 +86,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler $this->connector = $this->initConnector($connector); } + /** + * @param array $options + * @return array + */ private function initOptions(array $options): array { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); @@ -153,6 +160,9 @@ class PHPConsoleHandler extends AbstractProcessingHandler return $this->connector; } + /** + * @return array + */ public function getOptions(): array { return $this->options; @@ -181,6 +191,9 @@ class PHPConsoleHandler extends AbstractProcessingHandler } } + /** + * @phpstan-param Record $record + */ private function handleDebugRecord(array $record): void { $tags = $this->getRecordTags($record); @@ -191,11 +204,17 @@ class PHPConsoleHandler extends AbstractProcessingHandler $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } + /** + * @phpstan-param Record $record + */ private function handleExceptionRecord(array $record): void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } + /** + * @phpstan-param Record $record + */ private function handleErrorRecord(array $record): void { $context = $record['context']; @@ -209,6 +228,10 @@ class PHPConsoleHandler extends AbstractProcessingHandler ); } + /** + * @phpstan-param Record $record + * @return string + */ private function getRecordTags(array &$record) { $tags = null; diff --git a/src/Monolog/Handler/ProcessHandler.php b/src/Monolog/Handler/ProcessHandler.php index 36e30b87..97549949 100644 --- a/src/Monolog/Handler/ProcessHandler.php +++ b/src/Monolog/Handler/ProcessHandler.php @@ -44,12 +44,12 @@ class ProcessHandler extends AbstractProcessingHandler private $cwd; /** - * @var array + * @var resource[] */ private $pipes = []; /** - * @var array + * @var array */ protected const DESCRIPTOR_SPEC = [ 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from diff --git a/src/Monolog/Handler/ProcessableHandlerInterface.php b/src/Monolog/Handler/ProcessableHandlerInterface.php index 41b52ce5..a7487617 100644 --- a/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -17,13 +17,15 @@ use Monolog\Processor\ProcessorInterface; * Interface to describe loggers that have processors * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessableHandlerInterface { /** * Adds a processor in the stack. * - * @psalm-param ProcessorInterface|callable(array): array $callback + * @psalm-param ProcessorInterface|callable(Record): Record $callback * * @param ProcessorInterface|callable $callback * @return HandlerInterface self @@ -33,10 +35,10 @@ interface ProcessableHandlerInterface /** * Removes the processor on top of the stack and returns it. * - * @psalm-return callable(array): array + * @psalm-return ProcessorInterface|callable(Record): Record $callback * * @throws \LogicException In case the processor stack is empty - * @return callable + * @return callable|ProcessorInterface */ public function popProcessor(): callable; } diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 71d767be..f3cdd2a3 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -12,16 +12,20 @@ namespace Monolog\Handler; use Monolog\ResettableInterface; +use Monolog\Processor\ProcessorInterface; /** * Helper trait for implementing ProcessableInterface * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ trait ProcessableHandlerTrait { /** * @var callable[] + * @phpstan-var array */ protected $processors = []; @@ -49,6 +53,9 @@ trait ProcessableHandlerTrait /** * Processes a record. + * + * @phpstan-param Record $record + * @phpstan-return Record */ protected function processRecord(array $record): array { diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 3bb99c75..12cc101c 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -19,24 +19,35 @@ use Monolog\Utils; * * @author Sebastian Göttschkes * @see https://www.pushover.net/api + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class PushoverHandler extends SocketHandler { + /** @var string */ private $token; + /** @var array */ private $users; + /** @var ?string */ private $title; - private $user; + /** @var string|int|null */ + private $user = null; + /** @var int */ private $retry; + /** @var int */ private $expire; + /** @var int */ private $highPriorityLevel; + /** @var int */ private $emergencyLevel; + /** @var bool */ private $useFormattedMessage = false; /** * All parameters that can be sent to Pushover * @see https://pushover.net/api - * @var array + * @var array */ private $parameterNames = [ 'token' => true, @@ -57,7 +68,7 @@ class PushoverHandler extends SocketHandler /** * Sounds the api supports by default * @see https://pushover.net/api#sounds - * @var array + * @var string[] */ private $sounds = [ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', @@ -81,6 +92,8 @@ class PushoverHandler extends SocketHandler * send the same notification to the user. * @param int $expire The expire parameter specifies how many seconds your notification will continue * to be retried for (every retry seconds). + * + * @phpstan-param string|array $users */ public function __construct( string $token, @@ -113,6 +126,9 @@ class PushoverHandler extends SocketHandler return $this->buildHeader($content) . $content; } + /** + * @phpstan-param FormattedRecord $record + */ private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. @@ -177,6 +193,9 @@ class PushoverHandler extends SocketHandler $this->user = null; } + /** + * @param int|string $value + */ public function setHighPriorityLevel($value): self { $this->highPriorityLevel = Logger::toMonologLevel($value); @@ -184,6 +203,9 @@ class PushoverHandler extends SocketHandler return $this; } + /** + * @param int|string $value + */ public function setEmergencyLevel($value): self { $this->emergencyLevel = Logger::toMonologLevel($value); diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index 46482b61..02ee1c14 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -25,11 +25,16 @@ use Monolog\Logger; * $log->pushHandler($redis); * * @author Thomas Tourlourat + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class RedisHandler extends AbstractProcessingHandler { + /** @var \Predis\Client|\Redis */ private $redisClient; + /** @var string */ private $redisKey; + /** @var int */ protected $capSize; /** @@ -67,6 +72,8 @@ class RedisHandler extends AbstractProcessingHandler /** * Write and cap the collection * Writes the record to the redis list and caps its + * + * @phpstan-param FormattedRecord $record */ protected function writeCapped(array $record): void { diff --git a/src/Monolog/Handler/RedisPubSubHandler.php b/src/Monolog/Handler/RedisPubSubHandler.php index c9b13198..f6db4803 100644 --- a/src/Monolog/Handler/RedisPubSubHandler.php +++ b/src/Monolog/Handler/RedisPubSubHandler.php @@ -28,7 +28,9 @@ use Monolog\Logger; */ class RedisPubSubHandler extends AbstractProcessingHandler { + /** @var \Predis\Client|\Redis */ private $redisClient; + /** @var string */ private $channelKey; /** diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 979d651e..fdc4abb9 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -38,6 +38,7 @@ class RollbarHandler extends AbstractProcessingHandler */ protected $rollbarLogger; + /** @var string[] */ protected $levelMap = [ Logger::DEBUG => 'debug', Logger::INFO => 'info', @@ -56,6 +57,7 @@ class RollbarHandler extends AbstractProcessingHandler */ private $hasRecords = false; + /** @var bool */ protected $initialized = false; /** diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index f61e5eb6..949fd1b8 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -30,11 +30,17 @@ class RotatingFileHandler extends StreamHandler public const FILE_PER_MONTH = 'Y-m'; public const FILE_PER_YEAR = 'Y'; + /** @var string */ protected $filename; + /** @var int */ protected $maxFiles; + /** @var bool */ protected $mustRotate; + /** @var \DateTimeImmutable */ protected $nextRotation; + /** @var string */ protected $filenameFormat; + /** @var string */ protected $dateFormat; /** diff --git a/src/Monolog/Handler/SamplingHandler.php b/src/Monolog/Handler/SamplingHandler.php index 4c33d4a3..d76f1d35 100644 --- a/src/Monolog/Handler/SamplingHandler.php +++ b/src/Monolog/Handler/SamplingHandler.php @@ -26,13 +26,17 @@ use Monolog\Formatter\FormatterInterface; * * @author Bryan Davis * @author Kunal Mehta + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { use ProcessableHandlerTrait; /** - * @var callable|HandlerInterface $handler + * @var HandlerInterface|callable + * @phpstan-var HandlerInterface|callable(Record, HandlerInterface): HandlerInterface */ protected $handler; @@ -42,7 +46,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter protected $factor; /** - * @psalm-param HandlerInterface|callable(array, HandlerInterface): HandlerInterface $handler + * @psalm-param HandlerInterface|callable(Record, HandlerInterface): HandlerInterface $handler * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled) @@ -81,6 +85,8 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * + * @phpstan-param Record|array{level: Level}|null $record + * * @return HandlerInterface */ public function getHandler(array $record = null) diff --git a/src/Monolog/Handler/SendGridHandler.php b/src/Monolog/Handler/SendGridHandler.php index e774d309..3dcf9155 100644 --- a/src/Monolog/Handler/SendGridHandler.php +++ b/src/Monolog/Handler/SendGridHandler.php @@ -40,7 +40,7 @@ class SendGridHandler extends MailHandler /** * The email addresses to which the message will be sent - * @var array + * @var string[] */ protected $to; @@ -51,13 +51,13 @@ class SendGridHandler extends MailHandler protected $subject; /** - * @param string $apiUser The SendGrid API User - * @param string $apiKey The SendGrid API Key - * @param string $from The sender of the email - * @param string|array $to The recipients of the email - * @param string $subject The subject of the mail - * @param int|string $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $apiUser The SendGrid API User + * @param string $apiKey The SendGrid API Key + * @param string $from The sender of the email + * @param string|string[] $to The recipients of the email + * @param string $subject The subject of the mail + * @param int|string $level The minimum logging level at which this handler will be triggered + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) { diff --git a/src/Monolog/Handler/Slack/SlackRecord.php b/src/Monolog/Handler/Slack/SlackRecord.php index 6658d0d4..53f2e760 100644 --- a/src/Monolog/Handler/Slack/SlackRecord.php +++ b/src/Monolog/Handler/Slack/SlackRecord.php @@ -23,6 +23,8 @@ use Monolog\Formatter\FormatterInterface; * @author Haralan Dobrev * @see https://api.slack.com/incoming-webhooks * @see https://api.slack.com/docs/message-attachments + * + * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler */ class SlackRecord { @@ -72,7 +74,7 @@ class SlackRecord /** * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] - * @var array + * @var string[] */ private $excludeFields; @@ -86,6 +88,9 @@ class SlackRecord */ private $normalizerFormatter; + /** + * @param string[] $excludeFields + */ public function __construct( ?string $channel = null, ?string $username = null, @@ -114,6 +119,9 @@ class SlackRecord /** * Returns required data in format that Slack * is expecting. + * + * @phpstan-param FormattedRecord $record + * @phpstan-return string[] */ public function getSlackData(array $record): array { @@ -208,6 +216,8 @@ class SlackRecord /** * Stringifies an array of key/value pairs to be used in attachment fields + * + * @param mixed[] $fields */ public function stringify(array $fields): string { @@ -285,6 +295,9 @@ class SlackRecord return $this; } + /** + * @param string[] $excludeFields + */ public function excludeFields(array $excludeFields = []): self { $this->excludeFields = $excludeFields; @@ -302,7 +315,8 @@ class SlackRecord /** * Generates attachment field * - * @param string|array $value + * @param string|mixed[] $value + * @return array{title: string, value: string, short: false} */ private function generateAttachmentField(string $title, $value): array { @@ -319,6 +333,9 @@ class SlackRecord /** * Generates a collection of attachment fields from array + * + * @param mixed[] $data + * @return array */ private function generateAttachmentFields(array $data): array { @@ -332,6 +349,9 @@ class SlackRecord /** * Get a copy of record with fields excluded according to $this->excludeFields + * + * @phpstan-param FormattedRecord $record + * @return mixed[] */ private function removeExcludedFields(array $record): array { diff --git a/src/Monolog/Handler/SlackHandler.php b/src/Monolog/Handler/SlackHandler.php index 1535a180..67e97474 100644 --- a/src/Monolog/Handler/SlackHandler.php +++ b/src/Monolog/Handler/SlackHandler.php @@ -21,6 +21,8 @@ use Monolog\Handler\Slack\SlackRecord; * * @author Greg Kedzierski * @see https://api.slack.com/ + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SlackHandler extends SocketHandler { @@ -46,7 +48,7 @@ class SlackHandler extends SocketHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ public function __construct( @@ -102,6 +104,8 @@ class SlackHandler extends SocketHandler /** * Builds the body of API call + * + * @phpstan-param FormattedRecord $record */ private function buildContent(array $record): string { @@ -110,6 +114,10 @@ class SlackHandler extends SocketHandler return http_build_query($dataArray); } + /** + * @phpstan-param FormattedRecord $record + * @return string[] + */ protected function prepareContentData(array $record): array { $dataArray = $this->slackRecord->getSlackData($record); @@ -224,6 +232,9 @@ class SlackHandler extends SocketHandler return $this; } + /** + * @param string[] $excludeFields + */ public function excludeFields(array $excludeFields): self { $this->slackRecord->excludeFields($excludeFields); diff --git a/src/Monolog/Handler/SlackWebhookHandler.php b/src/Monolog/Handler/SlackWebhookHandler.php index 17d12b06..33ac1387 100644 --- a/src/Monolog/Handler/SlackWebhookHandler.php +++ b/src/Monolog/Handler/SlackWebhookHandler.php @@ -46,7 +46,7 @@ class SlackWebhookHandler extends AbstractProcessingHandler * @param bool $includeContextAndExtra Whether the attachment should include context and extra data * @param string|int $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] */ public function __construct( string $webhookUrl, @@ -87,8 +87,6 @@ class SlackWebhookHandler extends AbstractProcessingHandler /** * {@inheritdoc} - * - * @param array $record */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/SocketHandler.php b/src/Monolog/Handler/SocketHandler.php index 7e8e0187..4a1d7bf1 100644 --- a/src/Monolog/Handler/SocketHandler.php +++ b/src/Monolog/Handler/SocketHandler.php @@ -18,10 +18,15 @@ use Monolog\Logger; * * @author Pablo de Leon Belloc * @see http://php.net/manual/en/function.fsockopen.php + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SocketHandler extends AbstractProcessingHandler { + /** @var string */ private $connectionString; + /** @var float */ private $connectionTimeout; /** @var resource|null */ private $resource; @@ -29,14 +34,18 @@ class SocketHandler extends AbstractProcessingHandler private $timeout = 0.0; /** @var float */ private $writingTimeout = 10.0; + /** @var ?int */ private $lastSentBytes = null; /** @var int */ private $chunkSize = null; + /** @var bool */ private $persistent = false; - private $errno; - private $errstr; + /** @var ?int */ + private $errno = null; + /** @var ?string */ + private $errstr = null; /** @var ?float */ - private $lastWritingAt; + private $lastWritingAt = null; /** * @param string $connectionString Socket connection string @@ -53,7 +62,7 @@ class SocketHandler extends AbstractProcessingHandler /** * Connect (if necessary) and write to the socket * - * @param array $record + * {@inheritDoc} * * @throws \UnexpectedValueException * @throws \RuntimeException @@ -208,6 +217,8 @@ class SocketHandler extends AbstractProcessingHandler /** * Wrapper to allow mocking + * + * @return resource|bool */ protected function pfsockopen() { @@ -216,6 +227,8 @@ class SocketHandler extends AbstractProcessingHandler /** * Wrapper to allow mocking + * + * @return resource|bool */ protected function fsockopen() { @@ -226,6 +239,8 @@ class SocketHandler extends AbstractProcessingHandler * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-timeout.php + * + * @return bool */ protected function streamSetTimeout() { @@ -239,6 +254,8 @@ class SocketHandler extends AbstractProcessingHandler * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-chunk-size.php + * + * @return int|bool */ protected function streamSetChunkSize() { @@ -247,29 +264,32 @@ class SocketHandler extends AbstractProcessingHandler /** * Wrapper to allow mocking + * + * @return int|bool */ - protected function fwrite($data) + protected function fwrite(string $data) { return @fwrite($this->resource, $data); } /** * Wrapper to allow mocking + * + * @return mixed[]|bool */ protected function streamGetMetadata() { return stream_get_meta_data($this->resource); } - private function validateTimeout($value) + private function validateTimeout(float $value): void { - $ok = filter_var($value, FILTER_VALIDATE_FLOAT); - if ($ok === false || $value < 0) { + if ($value < 0) { throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); } } - private function connectIfNotConnected() + private function connectIfNotConnected(): void { if ($this->isConnected()) { return; @@ -277,6 +297,9 @@ class SocketHandler extends AbstractProcessingHandler $this->connect(); } + /** + * @phpstan-param FormattedRecord $record + */ protected function generateDataStream(array $record): string { return (string) $record['formatted']; diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index a98c87bf..2d531458 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -41,9 +41,7 @@ class SqsHandler extends AbstractProcessingHandler } /** - * Writes the record down to the log of the implementing handler. - * - * @param array $record + * {@inheritdoc} */ protected function write(array $record): void { diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 5a126665..4ef049f3 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -20,6 +20,8 @@ use Monolog\Utils; * Can be used to store into php://stderr, remote and local files, etc. * * @author Jordi Boggiano + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class StreamHandler extends AbstractProcessingHandler { @@ -27,12 +29,16 @@ class StreamHandler extends AbstractProcessingHandler /** @var resource|null */ protected $stream; - protected $url; - /** @var string|null */ - private $errorMessage; + /** @var ?string */ + protected $url = null; + /** @var ?string */ + private $errorMessage = null; + /** @var ?int */ protected $filePermission; + /** @var bool */ protected $useLocking; - private $dirCreated; + /** @var true|null */ + private $dirCreated = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write @@ -132,13 +138,15 @@ class StreamHandler extends AbstractProcessingHandler * Write to stream * @param resource $stream * @param array $record + * + * @phpstan-param FormattedRecord $record */ protected function streamWrite($stream, array $record): void { fwrite($stream, (string) $record['formatted']); } - private function customErrorHandler($code, $msg): bool + private function customErrorHandler(int $code, string $msg): bool { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); diff --git a/src/Monolog/Handler/SwiftMailerHandler.php b/src/Monolog/Handler/SwiftMailerHandler.php index 2c5c5dac..aa2181b2 100644 --- a/src/Monolog/Handler/SwiftMailerHandler.php +++ b/src/Monolog/Handler/SwiftMailerHandler.php @@ -21,14 +21,18 @@ use Swift; * SwiftMailerHandler uses Swift_Mailer to send the emails * * @author Gyula Sallai + * + * @phpstan-import-type Record from \Monolog\Logger */ class SwiftMailerHandler extends MailHandler { + /** @var \Swift_Mailer */ protected $mailer; + /** @var Swift_Message|callable(string, Record[]): Swift_Message */ private $messageTemplate; /** - * @psalm-param Swift_Message|callable(string, array): Swift_Message $message + * @psalm-param Swift_Message|callable(string, Record[]): Swift_Message $message * * @param \Swift_Mailer $mailer The mailer to use * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced @@ -67,6 +71,8 @@ class SwiftMailerHandler extends MailHandler * @param string $content formatted email body to be sent * @param array $records Log records that formed the content * @return Swift_Message + * + * @phpstan-param Record[] $records */ protected function buildMessage(string $content, array $records): Swift_Message { diff --git a/src/Monolog/Handler/SyslogHandler.php b/src/Monolog/Handler/SyslogHandler.php index 20594ced..12636e53 100644 --- a/src/Monolog/Handler/SyslogHandler.php +++ b/src/Monolog/Handler/SyslogHandler.php @@ -28,7 +28,9 @@ use Monolog\Logger; */ class SyslogHandler extends AbstractSyslogHandler { + /** @var string */ protected $ident; + /** @var int */ protected $logopts; /** diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 228a705a..30b5186b 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -39,6 +39,11 @@ class UdpSocket $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; } + /** + * @param string $line + * @param string $header + * @return void + */ public function write($line, $header = "") { $this->send($this->assembleMessage($line, $header)); diff --git a/src/Monolog/Handler/SyslogUdpHandler.php b/src/Monolog/Handler/SyslogUdpHandler.php index 2bf3da69..d1821ca7 100644 --- a/src/Monolog/Handler/SyslogUdpHandler.php +++ b/src/Monolog/Handler/SyslogUdpHandler.php @@ -27,14 +27,18 @@ class SyslogUdpHandler extends AbstractSyslogHandler const RFC5424 = 1; const RFC5424e = 2; + /** @var array */ private $dateFormats = array( self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, self::RFC5424e => \DateTime::RFC3339_EXTENDED, ); + /** @var UdpSocket */ protected $socket; + /** @var string */ protected $ident; + /** @var self::RFC* */ protected $rfc; /** @@ -45,6 +49,8 @@ class SyslogUdpHandler extends AbstractSyslogHandler * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param string $ident Program name or tag for each log message. * @param int $rfc RFC to format the message for. + * + * @phpstan-param self::RFC* $rfc */ public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) { @@ -72,6 +78,10 @@ class SyslogUdpHandler extends AbstractSyslogHandler $this->socket->close(); } + /** + * @param string|string[] $message + * @return string[] + */ private function splitMessageIntoLines($message): array { if (is_array($message)) { diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 025c89e3..9ea79a97 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -33,7 +33,7 @@ class TelegramBotHandler extends AbstractProcessingHandler private const BOT_API = 'https://api.telegram.org/bot'; /** - * @var array AVAILABLE_PARSE_MODES The available values of parseMode according to the Telegram api documentation + * The available values of parseMode according to the Telegram api documentation */ private const AVAILABLE_PARSE_MODES = [ 'HTML', @@ -59,19 +59,19 @@ class TelegramBotHandler extends AbstractProcessingHandler * The kind of formatting that is used for the message. * See available options at https://core.telegram.org/bots/api#formatting-options * or in AVAILABLE_PARSE_MODES - * @var string|null + * @var ?string */ private $parseMode; /** * Disables link previews for links in the message. - * @var bool|null + * @var ?bool */ private $disableWebPagePreview; /** * Sends the message silently. Users will receive a notification with no sound. - * @var bool|null + * @var ?bool */ private $disableNotification; diff --git a/src/Monolog/Handler/TestHandler.php b/src/Monolog/Handler/TestHandler.php index 9fa77b9f..03b51cd6 100644 --- a/src/Monolog/Handler/TestHandler.php +++ b/src/Monolog/Handler/TestHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Used for testing purposes. @@ -64,24 +65,42 @@ use Monolog\Logger; * @method bool hasNoticeThatPasses($message) * @method bool hasInfoThatPasses($message) * @method bool hasDebugThatPasses($message) + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class TestHandler extends AbstractProcessingHandler { + /** @var Record[] */ protected $records = []; + /** @var array */ protected $recordsByLevel = []; + /** @var bool */ private $skipReset = false; + /** + * @return array + * + * @phpstan-return Record[] + */ public function getRecords() { return $this->records; } + /** + * @return void + */ public function clear() { $this->records = []; $this->recordsByLevel = []; } + /** + * @return void + */ public function reset() { if (!$this->skipReset) { @@ -89,6 +108,9 @@ class TestHandler extends AbstractProcessingHandler } } + /** + * @return void + */ public function setSkipReset(bool $skipReset) { $this->skipReset = $skipReset; @@ -105,6 +127,9 @@ class TestHandler extends AbstractProcessingHandler /** * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records * @param string|int $level Logging level value or name + * + * @phpstan-param array{message: string, context?: mixed[]}|string $record + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecord($record, $level): bool { @@ -136,6 +161,8 @@ class TestHandler extends AbstractProcessingHandler /** * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatMatches(string $regex, $level): bool { @@ -145,10 +172,11 @@ class TestHandler extends AbstractProcessingHandler } /** - * @psalm-param callable(array, int): mixed $predicate - * * @param string|int $level Logging level value or name * @return bool + * + * @psalm-param callable(Record, int): mixed $predicate + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function hasRecordThatPasses(callable $predicate, $level) { @@ -176,6 +204,11 @@ class TestHandler extends AbstractProcessingHandler $this->records[] = $record; } + /** + * @param string $method + * @param mixed[] $args + * @return bool + */ public function __call($method, $args) { if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { diff --git a/src/Monolog/Handler/ZendMonitorHandler.php b/src/Monolog/Handler/ZendMonitorHandler.php index 34fe80fa..dc99f8f0 100644 --- a/src/Monolog/Handler/ZendMonitorHandler.php +++ b/src/Monolog/Handler/ZendMonitorHandler.php @@ -20,13 +20,15 @@ use Monolog\Logger; * * @author Christian Bergau * @author Jason Davis + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class ZendMonitorHandler extends AbstractProcessingHandler { /** * Monolog level / ZendMonitor Custom Event priority map * - * @var array + * @var array */ protected $levelMap = []; @@ -75,6 +77,8 @@ class ZendMonitorHandler extends AbstractProcessingHandler * @param string $message Text displayed in "Error String" * @param array $formatted Displayed in Custom Variables tab * @param int $severity Set the event severity level (-1,0,1) + * + * @phpstan-param FormattedRecord $formatted */ protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void { @@ -89,6 +93,9 @@ class ZendMonitorHandler extends AbstractProcessingHandler return new NormalizerFormatter(); } + /** + * @return array + */ public function getLevelMap(): array { return $this->levelMap; diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index 927c3127..0b7cb448 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -15,6 +15,7 @@ use DateTimeZone; use Monolog\Handler\HandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\InvalidArgumentException; +use Psr\Log\LogLevel; use Throwable; /** @@ -24,6 +25,10 @@ use Throwable; * and uses them to store records that are added to it. * * @author Jordi Boggiano + * + * @phpstan-type Level Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY + * @phpstan-type LevelName 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY' + * @phpstan-type Record array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ class Logger implements LoggerInterface, ResettableInterface { @@ -91,6 +96,8 @@ class Logger implements LoggerInterface, ResettableInterface * This is a static variable and not a constant to serve as an extension point for custom levels * * @var array $levels Logging levels with the levels as key + * + * @phpstan-var array $levels Logging levels with the levels as key */ protected static $levels = [ self::DEBUG => 'DEBUG', @@ -276,6 +283,8 @@ class Logger implements LoggerInterface, ResettableInterface * @param string $message The log message * @param mixed[] $context The log context * @return bool Whether the record has been processed + * + * @phpstan-param Level $level */ public function addRecord(int $level, string $message, array $context = []): bool { @@ -383,6 +392,9 @@ class Logger implements LoggerInterface, ResettableInterface * Gets the name of the logging level. * * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level $level + * @phpstan-return LevelName */ public static function getLevelName(int $level): string { @@ -398,11 +410,15 @@ class Logger implements LoggerInterface, ResettableInterface * * @param string|int $level Level number (monolog) or name (PSR-3) * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-return Level */ public static function toMonologLevel($level): int { if (is_string($level)) { if (is_numeric($level)) { + /** @phpstan-ignore-next-line */ return intval($level); } @@ -413,18 +429,21 @@ class Logger implements LoggerInterface, ResettableInterface return constant(__CLASS__ . '::' . $upper); } - throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } if (!is_int($level)) { - throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } + /** @phpstan-ignore-next-line */ return $level; } /** * Checks whether the Logger has a handler that listens on the given level + * + * @phpstan-param Level $level */ public function isHandling(int $level): bool { @@ -463,9 +482,11 @@ class Logger implements LoggerInterface, ResettableInterface * * This method allows for compatibility with common interfaces. * - * @param mixed $level The log level - * @param string $message The log message - * @param mixed[] $context The log context + * @param int|string $level The log level + * @param string $message The log message + * @param mixed[] $context The log context + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function log($level, $message, array $context = []): void { @@ -599,6 +620,9 @@ class Logger implements LoggerInterface, ResettableInterface /** * Delegates exception management to the custom exception handler, * or throws the exception if no custom handler is set. + * + * @param array $record + * @phpstan-param Record $record */ protected function handleException(Throwable $e, array $record): void { diff --git a/src/Monolog/Processor/GitProcessor.php b/src/Monolog/Processor/GitProcessor.php index 6abd3d8c..337ef226 100644 --- a/src/Monolog/Processor/GitProcessor.php +++ b/src/Monolog/Processor/GitProcessor.php @@ -21,8 +21,10 @@ use Monolog\Logger; */ class GitProcessor implements ProcessorInterface { + /** @var int */ private $level; - private static $cache; + /** @var array{branch: string, commit: string}|array|null */ + private static $cache = null; /** * @param string|int $level The minimum logging level at which this Processor will be triggered @@ -32,6 +34,9 @@ class GitProcessor implements ProcessorInterface $this->level = Logger::toMonologLevel($level); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -44,6 +49,9 @@ class GitProcessor implements ProcessorInterface return $record; } + /** + * @return array{branch: string, commit: string}|array + */ private static function getGitInfo(): array { if (self::$cache) { diff --git a/src/Monolog/Processor/HostnameProcessor.php b/src/Monolog/Processor/HostnameProcessor.php index 7c23db8b..91fda7d6 100644 --- a/src/Monolog/Processor/HostnameProcessor.php +++ b/src/Monolog/Processor/HostnameProcessor.php @@ -16,6 +16,7 @@ namespace Monolog\Processor; */ class HostnameProcessor implements ProcessorInterface { + /** @var string */ private static $host; public function __construct() @@ -23,6 +24,9 @@ class HostnameProcessor implements ProcessorInterface self::$host = (string) gethostname(); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['hostname'] = self::$host; diff --git a/src/Monolog/Processor/IntrospectionProcessor.php b/src/Monolog/Processor/IntrospectionProcessor.php index c0cc014e..5a3e93c9 100644 --- a/src/Monolog/Processor/IntrospectionProcessor.php +++ b/src/Monolog/Processor/IntrospectionProcessor.php @@ -26,19 +26,21 @@ use Monolog\Logger; */ class IntrospectionProcessor implements ProcessorInterface { + /** @var int */ private $level; - + /** @var string[] */ private $skipClassesPartials; - + /** @var int */ private $skipStackFramesCount; - + /** @var string[] */ private $skipFunctions = [ 'call_user_func', 'call_user_func_array', ]; /** - * @param string|int $level The minimum logging level at which this Processor will be triggered + * @param string|int $level The minimum logging level at which this Processor will be triggered + * @param string[] $skipClassesPartials */ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { @@ -47,6 +49,9 @@ class IntrospectionProcessor implements ProcessorInterface $this->skipStackFramesCount = $skipStackFramesCount; } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -97,7 +102,10 @@ class IntrospectionProcessor implements ProcessorInterface return $record; } - private function isTraceClassOrSkippedFunction(array $trace, int $index) + /** + * @param array[] $trace + */ + private function isTraceClassOrSkippedFunction(array $trace, int $index): bool { if (!isset($trace[$index])) { return false; diff --git a/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/src/Monolog/Processor/MemoryPeakUsageProcessor.php index a1eef61a..37c756fc 100644 --- a/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -19,6 +19,9 @@ namespace Monolog\Processor; */ class MemoryPeakUsageProcessor extends MemoryProcessor { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $usage = memory_get_peak_usage($this->realUsage); diff --git a/src/Monolog/Processor/MemoryUsageProcessor.php b/src/Monolog/Processor/MemoryUsageProcessor.php index 653c76d1..e141921e 100644 --- a/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/src/Monolog/Processor/MemoryUsageProcessor.php @@ -19,6 +19,9 @@ namespace Monolog\Processor; */ class MemoryUsageProcessor extends MemoryProcessor { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $usage = memory_get_usage($this->realUsage); diff --git a/src/Monolog/Processor/MercurialProcessor.php b/src/Monolog/Processor/MercurialProcessor.php index d50f7138..9aeb3e3a 100644 --- a/src/Monolog/Processor/MercurialProcessor.php +++ b/src/Monolog/Processor/MercurialProcessor.php @@ -20,8 +20,10 @@ use Monolog\Logger; */ class MercurialProcessor implements ProcessorInterface { + /** @var int */ private $level; - private static $cache; + /** @var array{branch: string, revision: string}|array|null */ + private static $cache = null; /** * @param string|int $level The minimum logging level at which this Processor will be triggered @@ -31,6 +33,9 @@ class MercurialProcessor implements ProcessorInterface $this->level = Logger::toMonologLevel($level); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // return if the level is not high enough @@ -43,6 +48,9 @@ class MercurialProcessor implements ProcessorInterface return $record; } + /** + * @return array{branch: string, revision: string}|array + */ private static function getMercurialInfo(): array { if (self::$cache) { diff --git a/src/Monolog/Processor/ProcessIdProcessor.php b/src/Monolog/Processor/ProcessIdProcessor.php index 7851fff6..3b939a95 100644 --- a/src/Monolog/Processor/ProcessIdProcessor.php +++ b/src/Monolog/Processor/ProcessIdProcessor.php @@ -18,6 +18,9 @@ namespace Monolog\Processor; */ class ProcessIdProcessor implements ProcessorInterface { + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['process_id'] = getmypid(); diff --git a/src/Monolog/Processor/ProcessorInterface.php b/src/Monolog/Processor/ProcessorInterface.php index 9e2ded19..5defb7eb 100644 --- a/src/Monolog/Processor/ProcessorInterface.php +++ b/src/Monolog/Processor/ProcessorInterface.php @@ -15,11 +15,16 @@ namespace Monolog\Processor; * An optional interface to allow labelling Monolog processors. * * @author Nicolas Grekas + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessorInterface { /** * @return array The processed record + * + * @phpstan-param Record $record + * @phpstan-return Record */ public function __invoke(array $record); } diff --git a/src/Monolog/Processor/PsrLogMessageProcessor.php b/src/Monolog/Processor/PsrLogMessageProcessor.php index 7b80e57d..2c2a00e7 100644 --- a/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -41,8 +41,7 @@ class PsrLogMessageProcessor implements ProcessorInterface } /** - * @param array $record - * @return array + * {@inheritDoc} */ public function __invoke(array $record): array { diff --git a/src/Monolog/Processor/TagProcessor.php b/src/Monolog/Processor/TagProcessor.php index 199760ad..80f18747 100644 --- a/src/Monolog/Processor/TagProcessor.php +++ b/src/Monolog/Processor/TagProcessor.php @@ -18,13 +18,20 @@ namespace Monolog\Processor; */ class TagProcessor implements ProcessorInterface { + /** @var string[] */ private $tags; + /** + * @param string[] $tags + */ public function __construct(array $tags = []) { $this->setTags($tags); } + /** + * @param string[] $tags + */ public function addTags(array $tags = []): self { $this->tags = array_merge($this->tags, $tags); @@ -32,6 +39,9 @@ class TagProcessor implements ProcessorInterface return $this; } + /** + * @param string[] $tags + */ public function setTags(array $tags = []): self { $this->tags = $tags; @@ -39,6 +49,9 @@ class TagProcessor implements ProcessorInterface return $this; } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['tags'] = $this->tags; diff --git a/src/Monolog/Processor/UidProcessor.php b/src/Monolog/Processor/UidProcessor.php index 0c97ab6c..a27b74db 100644 --- a/src/Monolog/Processor/UidProcessor.php +++ b/src/Monolog/Processor/UidProcessor.php @@ -20,6 +20,7 @@ use Monolog\ResettableInterface; */ class UidProcessor implements ProcessorInterface, ResettableInterface { + /** @var string */ private $uid; public function __construct(int $length = 7) @@ -31,6 +32,9 @@ class UidProcessor implements ProcessorInterface, ResettableInterface $this->uid = $this->generateUid($length); } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { $record['extra']['uid'] = $this->uid; diff --git a/src/Monolog/Processor/WebProcessor.php b/src/Monolog/Processor/WebProcessor.php index 6c32b2d1..155e8157 100644 --- a/src/Monolog/Processor/WebProcessor.php +++ b/src/Monolog/Processor/WebProcessor.php @@ -19,7 +19,7 @@ namespace Monolog\Processor; class WebProcessor implements ProcessorInterface { /** - * @var array|\ArrayAccess + * @var array|\ArrayAccess */ protected $serverData; @@ -28,7 +28,7 @@ class WebProcessor implements ProcessorInterface * * Array is structured as [key in record.extra => key in $serverData] * - * @var array + * @var array */ protected $extraFields = [ 'url' => 'REQUEST_URI', @@ -39,8 +39,8 @@ class WebProcessor implements ProcessorInterface ]; /** - * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer + * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data + * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer */ public function __construct($serverData = null, array $extraFields = null) { @@ -69,6 +69,9 @@ class WebProcessor implements ProcessorInterface } } + /** + * {@inheritDoc} + */ public function __invoke(array $record): array { // skip processing if for some reason request data @@ -89,6 +92,10 @@ class WebProcessor implements ProcessorInterface return $this; } + /** + * @param mixed[] $extra + * @return mixed[] + */ private function appendExtraFields(array $extra): array { foreach ($this->extraFields as $extraName => $serverName) { diff --git a/src/Monolog/Registry.php b/src/Monolog/Registry.php index 78fb97e5..ae94ae6c 100644 --- a/src/Monolog/Registry.php +++ b/src/Monolog/Registry.php @@ -51,6 +51,7 @@ class Registry * @param string|null $name Name of the logging channel ($logger->getName() by default) * @param bool $overwrite Overwrite instance in the registry if the given name already exists? * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists + * @return void */ public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false) { @@ -122,7 +123,7 @@ class Registry * Gets Logger instance from the registry via static method call * * @param string $name Name of the requested Logger instance - * @param array $arguments Arguments passed to static method call + * @param mixed[] $arguments Arguments passed to static method call * @throws \InvalidArgumentException If named Logger instance is not in the registry * @return Logger Requested instance of Logger */ diff --git a/src/Monolog/SignalHandler.php b/src/Monolog/SignalHandler.php index 517ab549..62f45e39 100644 --- a/src/Monolog/SignalHandler.php +++ b/src/Monolog/SignalHandler.php @@ -22,10 +22,14 @@ use ReflectionExtension; */ class SignalHandler { + /** @var LoggerInterface */ private $logger; + /** @var array SIG_DFL, SIG_IGN or previous callable */ private $previousSignalHandler = []; + /** @var array */ private $signalLevelMap = []; + /** @var array */ private $signalRestartSyscalls = []; public function __construct(LoggerInterface $logger) @@ -33,12 +37,21 @@ class SignalHandler $this->logger = $logger; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self + /** + * @param int|string $level Level or level name + * @param bool $callPrevious + * @param bool $restartSyscalls + * @param bool|null $async + * @return $this + */ + public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self { if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { return $this; } + $level = Logger::toMonologLevel($level); + if ($callPrevious) { $handler = pcntl_signal_get_handler($signo); $this->previousSignalHandler[$signo] = $handler; @@ -57,7 +70,10 @@ class SignalHandler return $this; } - public function handleSignal($signo, array $siginfo = null): void + /** + * @param mixed $siginfo + */ + public function handleSignal(int $signo, $siginfo = null): void { static $signals = []; @@ -80,7 +96,7 @@ class SignalHandler return; } - if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if ($this->previousSignalHandler[$signo] === SIG_DFL) { if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill') ) { diff --git a/src/Monolog/Test/TestCase.php b/src/Monolog/Test/TestCase.php index b996bbc9..1824fde4 100644 --- a/src/Monolog/Test/TestCase.php +++ b/src/Monolog/Test/TestCase.php @@ -17,15 +17,23 @@ use Monolog\Formatter\FormatterInterface; /** * Lets you easily generate log records and a dummy formatter for testing purposes - * * + * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class TestCase extends \PHPUnit\Framework\TestCase { /** + * @param mixed[] $context + * * @return array Record + * + * @phpstan-param Level $level + * @phpstan-return Record */ - protected function getRecord($level = Logger::WARNING, $message = 'test', array $context = []): array + protected function getRecord(int $level = Logger::WARNING, string $message = 'test', array $context = []): array { return [ 'message' => (string) $message, @@ -38,6 +46,9 @@ class TestCase extends \PHPUnit\Framework\TestCase ]; } + /** + * @phpstan-return Record[] + */ protected function getMultipleRecords(): array { return [ diff --git a/tests/Monolog/ErrorHandlerTest.php b/tests/Monolog/ErrorHandlerTest.php index 69cb3e50..05123f2a 100644 --- a/tests/Monolog/ErrorHandlerTest.php +++ b/tests/Monolog/ErrorHandlerTest.php @@ -54,8 +54,8 @@ class ErrorHandlerTest extends \PHPUnit\Framework\TestCase public function fatalHandlerProvider() { return [ - [null, 10, str_repeat(' ', 1024 * 10), null], - [E_ALL, 15, str_repeat(' ', 1024 * 15), E_ALL], + [null, 10, str_repeat(' ', 1024 * 10), LogLevel::ALERT], + [LogLevel::DEBUG, 15, str_repeat(' ', 1024 * 15), LogLevel::DEBUG], ]; }