Aggiornato Composer
This commit is contained in:
60
vendor/monolog/monolog/CHANGELOG.md
vendored
60
vendor/monolog/monolog/CHANGELOG.md
vendored
@@ -1,7 +1,63 @@
|
||||
### 2.9.3 (2024-04-12)
|
||||
|
||||
* Fixed PHP 8.4 deprecation warnings (#1874)
|
||||
|
||||
### 2.9.2 (2023-10-27)
|
||||
|
||||
* Fixed display_errors parsing in ErrorHandler which did not support string values (#1804)
|
||||
* Fixed bug where the previous error handler would not be restored in some cases where StreamHandler fails (#1815)
|
||||
* Fixed normalization error when normalizing incomplete classes (#1833)
|
||||
|
||||
### 2.9.1 (2023-02-06)
|
||||
|
||||
* Fixed Logger not being serializable anymore (#1792)
|
||||
|
||||
### 2.9.0 (2023-02-05)
|
||||
|
||||
* Deprecated FlowdockHandler & Formatter as the flowdock service was shutdown (#1748)
|
||||
* Added support for enum context values in PsrLogMessageProcessor (#1773)
|
||||
* Added graylog2/gelf-php 2.x support (#1747)
|
||||
* Improved `BrowserConsoleHandler` logging to use more appropriate methods than just console.log in the browser (#1739)
|
||||
* Fixed `WhatFailureGroupHandler` not catching errors happening inside `close()` (#1791)
|
||||
* Fixed datetime field in `GoogleCloudLoggingFormatter` (#1758)
|
||||
* Fixed infinite loop detection within Fibers (#1753)
|
||||
* Fixed `AmqpHandler->setExtraAttributes` not working with buffering handler wrappers (#1781)
|
||||
|
||||
### 2.8.0 (2022-07-24)
|
||||
|
||||
* Deprecated `CubeHandler` and `PHPConsoleHandler` as both projects are abandoned and those should not be used anymore (#1734)
|
||||
* Added RFC 5424 level (`7` to `0`) support to `Logger::log` and `Logger::addRecord` to increase interoperability (#1723)
|
||||
* Added support for `__toString` for objects which are not json serializable in `JsonFormatter` (#1733)
|
||||
* Added `GoogleCloudLoggingFormatter` (#1719)
|
||||
* Added support for Predis 2.x (#1732)
|
||||
* Added `AmqpHandler->setExtraAttributes` to allow configuring attributes when using an AMQPExchange (#1724)
|
||||
* Fixed serialization/unserialization of handlers to make sure private properties are included (#1727)
|
||||
* Fixed allowInlineLineBreaks in LineFormatter causing issues with windows paths containing `\n` or `\r` sequences (#1720)
|
||||
* Fixed max normalization depth not being taken into account when formatting exceptions with a deep chain of previous exceptions (#1726)
|
||||
* Fixed PHP 8.2 deprecation warnings (#1722)
|
||||
* Fixed rare race condition or filesystem issue where StreamHandler is unable to create the directory the log should go into yet it exists already (#1678)
|
||||
|
||||
### 2.7.0 (2022-06-09)
|
||||
|
||||
* Added `$datetime` parameter to `Logger::addRecord` as low level API to allow logging into the past or future (#1682)
|
||||
* Added `Logger::useLoggingLoopDetection` to allow disabling cyclic logging detection in concurrent frameworks (#1681)
|
||||
* Fixed handling of fatal errors if callPrevious is disabled in ErrorHandler (#1670)
|
||||
* Marked the reusable `Monolog\Test\TestCase` class as `@internal` to make sure PHPStorm does not show it above PHPUnit, you may still use it to test your own handlers/etc though (#1677)
|
||||
* Fixed RotatingFileHandler issue when the date format contained slashes (#1671)
|
||||
|
||||
### 2.6.0 (2022-05-10)
|
||||
|
||||
* Deprecated `SwiftMailerHandler`, use `SymfonyMailerHandler` instead
|
||||
* Added `SymfonyMailerHandler` (#1663)
|
||||
* Added ElasticSearch 8.x support to the ElasticsearchHandler (#1662)
|
||||
* Added a way to filter/modify stack traces in LineFormatter (#1665)
|
||||
* Fixed UdpSocket not being able to reopen/reconnect after close()
|
||||
* Fixed infinite loops if a Handler is triggering logging while handling log records
|
||||
|
||||
### 2.5.0 (2022-04-08)
|
||||
|
||||
* Added `callType` to IntrospectionProcessor (#1612)
|
||||
* Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651)
|
||||
* Added `callType` to IntrospectionProcessor (#1612)
|
||||
* Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651)
|
||||
|
||||
### 2.4.0 (2022-03-14)
|
||||
|
||||
|
||||
26
vendor/monolog/monolog/composer.json
vendored
26
vendor/monolog/monolog/composer.json
vendored
@@ -17,20 +17,24 @@
|
||||
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
|
||||
"doctrine/couchdb": "~1.0@dev",
|
||||
"elasticsearch/elasticsearch": "^7",
|
||||
"elasticsearch/elasticsearch": "^7 || ^8",
|
||||
"graylog2/gelf-php": "^1.4.2 || ^2@dev",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"guzzlehttp/psr7": "^2.2",
|
||||
"mongodb/mongodb": "^1.8",
|
||||
"graylog2/gelf-php": "^1.4.2",
|
||||
"php-amqplib/php-amqplib": "~2.4 || ^3",
|
||||
"php-console/php-console": "^3.1.3",
|
||||
"phpspec/prophecy": "^1.6.1",
|
||||
"phpunit/phpunit": "^8.5",
|
||||
"predis/predis": "^1.1",
|
||||
"phpspec/prophecy": "^1.15",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^8.5.38 || ^9.6.19",
|
||||
"predis/predis": "^1.1 || ^2.0",
|
||||
"rollbar/rollbar": "^1.3 || ^2 || ^3",
|
||||
"ruflin/elastica": ">=0.90@dev",
|
||||
"ruflin/elastica": "^7",
|
||||
"swiftmailer/swiftmailer": "^5.3|^6.0",
|
||||
"phpstan/phpstan": "^0.12.91"
|
||||
"symfony/mailer": "^5.4 || ^6",
|
||||
"symfony/mime": "^5.4 || ^6"
|
||||
},
|
||||
"suggest": {
|
||||
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
@@ -43,7 +47,6 @@
|
||||
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"rollbar/rollbar": "Allow sending log messages to Rollbar",
|
||||
"php-console/php-console": "Allow sending log messages to Google Chrome",
|
||||
"ext-mbstring": "Allow to work properly with unicode symbols",
|
||||
"ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
|
||||
"ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
|
||||
@@ -70,6 +73,9 @@
|
||||
"config": {
|
||||
"lock": false,
|
||||
"sort-packages": true,
|
||||
"platform-check": false
|
||||
"platform-check": false,
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable
|
||||
{
|
||||
$this->useMicroseconds = $useMicroseconds;
|
||||
|
||||
// if you like to use a custom time to pass to Logger::addRecord directly,
|
||||
// call modify() or setTimestamp() on this instance to change the date after creating it
|
||||
parent::__construct('now', $timezone);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ class ErrorHandler
|
||||
private $fatalLevel = LogLevel::ALERT;
|
||||
/** @var ?string */
|
||||
private $reservedMemory = null;
|
||||
/** @var ?mixed */
|
||||
private $lastFatalTrace;
|
||||
/** @var ?array{type: int, message: string, file: string, line: int, trace: mixed} */
|
||||
private $lastFatalData = null;
|
||||
/** @var int[] */
|
||||
private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
|
||||
|
||||
@@ -198,7 +198,7 @@ class ErrorHandler
|
||||
($this->previousExceptionHandler)($e);
|
||||
}
|
||||
|
||||
if (!headers_sent() && !ini_get('display_errors')) {
|
||||
if (!headers_sent() && in_array(strtolower((string) ini_get('display_errors')), ['0', '', 'false', 'off', 'none', 'no'], true)) {
|
||||
http_response_code(500);
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ class ErrorHandler
|
||||
} else {
|
||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
array_shift($trace); // Exclude handleError from trace
|
||||
$this->lastFatalTrace = $trace;
|
||||
$this->lastFatalData = ['type' => $code, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace];
|
||||
}
|
||||
|
||||
if ($this->previousErrorHandler === true) {
|
||||
@@ -242,12 +242,18 @@ class ErrorHandler
|
||||
{
|
||||
$this->reservedMemory = '';
|
||||
|
||||
$lastError = error_get_last();
|
||||
if (is_array($this->lastFatalData)) {
|
||||
$lastError = $this->lastFatalData;
|
||||
} else {
|
||||
$lastError = error_get_last();
|
||||
}
|
||||
|
||||
if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
|
||||
$trace = $lastError['trace'] ?? null;
|
||||
$this->logger->log(
|
||||
$this->fatalLevel,
|
||||
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
|
||||
['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace]
|
||||
['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $trace]
|
||||
);
|
||||
|
||||
if ($this->logger instanceof Logger) {
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Monolog\Formatter;
|
||||
* formats the record to be used in the FlowdockHandler
|
||||
*
|
||||
* @author Dominik Liebler <liebler.dominik@gmail.com>
|
||||
* @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4
|
||||
*/
|
||||
class FlowdockFormatter implements FormatterInterface
|
||||
{
|
||||
|
||||
@@ -47,6 +47,11 @@ class GelfMessageFormatter extends NormalizerFormatter
|
||||
*/
|
||||
protected $maxLength;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $gelfVersion = 2;
|
||||
|
||||
/**
|
||||
* Translates Monolog log levels to Graylog2 log priorities.
|
||||
*
|
||||
@@ -78,6 +83,10 @@ class GelfMessageFormatter extends NormalizerFormatter
|
||||
$this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix;
|
||||
$this->contextPrefix = $contextPrefix;
|
||||
$this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength;
|
||||
|
||||
if (method_exists(Message::class, 'setFacility')) {
|
||||
$this->gelfVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,16 +122,20 @@ class GelfMessageFormatter extends NormalizerFormatter
|
||||
$message->setShortMessage(Utils::substr($record['message'], 0, $this->maxLength));
|
||||
}
|
||||
|
||||
if (isset($record['channel'])) {
|
||||
$message->setFacility($record['channel']);
|
||||
}
|
||||
if (isset($extra['line'])) {
|
||||
$message->setLine($extra['line']);
|
||||
unset($extra['line']);
|
||||
}
|
||||
if (isset($extra['file'])) {
|
||||
$message->setFile($extra['file']);
|
||||
unset($extra['file']);
|
||||
if ($this->gelfVersion === 1) {
|
||||
if (isset($record['channel'])) {
|
||||
$message->setFacility($record['channel']);
|
||||
}
|
||||
if (isset($extra['line'])) {
|
||||
$message->setLine($extra['line']);
|
||||
unset($extra['line']);
|
||||
}
|
||||
if (isset($extra['file'])) {
|
||||
$message->setFile($extra['file']);
|
||||
unset($extra['file']);
|
||||
}
|
||||
} else {
|
||||
$message->setAdditional('facility', $record['channel']);
|
||||
}
|
||||
|
||||
foreach ($extra as $key => $val) {
|
||||
@@ -147,11 +160,13 @@ class GelfMessageFormatter extends NormalizerFormatter
|
||||
$message->setAdditional($this->contextPrefix . $key, $val);
|
||||
}
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (null === $message->getFile() && isset($context['exception']['file'])) {
|
||||
if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) {
|
||||
$message->setFile($matches[1]);
|
||||
$message->setLine($matches[2]);
|
||||
if ($this->gelfVersion === 1) {
|
||||
/** @phpstan-ignore-next-line */
|
||||
if (null === $message->getFile() && isset($context['exception']['file'])) {
|
||||
if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) {
|
||||
$message->setFile($matches[1]);
|
||||
$message->setLine($matches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,12 +178,25 @@ class JsonFormatter extends NormalizerFormatter
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
if ($data instanceof \DateTimeInterface) {
|
||||
return $this->formatDate($data);
|
||||
}
|
||||
if (is_object($data)) {
|
||||
if ($data instanceof \DateTimeInterface) {
|
||||
return $this->formatDate($data);
|
||||
}
|
||||
|
||||
if ($data instanceof Throwable) {
|
||||
return $this->normalizeException($data, $depth);
|
||||
if ($data instanceof Throwable) {
|
||||
return $this->normalizeException($data, $depth);
|
||||
}
|
||||
|
||||
// if the object has specific json serializability we want to make sure we skip the __toString treatment below
|
||||
if ($data instanceof \JsonSerializable) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (method_exists($data, '__toString')) {
|
||||
return $data->__toString();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (is_resource($data)) {
|
||||
|
||||
@@ -33,6 +33,8 @@ class LineFormatter extends NormalizerFormatter
|
||||
protected $ignoreEmptyContextAndExtra;
|
||||
/** @var bool */
|
||||
protected $includeStacktraces;
|
||||
/** @var ?callable */
|
||||
protected $stacktracesParser;
|
||||
|
||||
/**
|
||||
* @param string|null $format The format of the message
|
||||
@@ -49,11 +51,12 @@ class LineFormatter extends NormalizerFormatter
|
||||
parent::__construct($dateFormat);
|
||||
}
|
||||
|
||||
public function includeStacktraces(bool $include = true): self
|
||||
public function includeStacktraces(bool $include = true, ?callable $parser = null): self
|
||||
{
|
||||
$this->includeStacktraces = $include;
|
||||
if ($this->includeStacktraces) {
|
||||
$this->allowInlineLineBreaks = true;
|
||||
$this->stacktracesParser = $parser;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -150,6 +153,12 @@ class LineFormatter extends NormalizerFormatter
|
||||
|
||||
if ($previous = $e->getPrevious()) {
|
||||
do {
|
||||
$depth++;
|
||||
if ($depth > $this->maxNormalizeDepth) {
|
||||
$str .= "\n[previous exception] Over " . $this->maxNormalizeDepth . ' levels deep, aborting normalization';
|
||||
break;
|
||||
}
|
||||
|
||||
$str .= "\n[previous exception] " . $this->formatException($previous);
|
||||
} while ($previous = $previous->getPrevious());
|
||||
}
|
||||
@@ -177,7 +186,11 @@ class LineFormatter extends NormalizerFormatter
|
||||
{
|
||||
if ($this->allowInlineLineBreaks) {
|
||||
if (0 === strpos($str, '{')) {
|
||||
return str_replace(array('\r', '\n'), array("\r", "\n"), $str);
|
||||
$str = preg_replace('/(?<!\\\\)\\\\[rn]/', "\n", $str);
|
||||
if (null === $str) {
|
||||
$pcreErrorCode = preg_last_error();
|
||||
throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode));
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
@@ -209,9 +222,25 @@ class LineFormatter extends NormalizerFormatter
|
||||
$str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')';
|
||||
|
||||
if ($this->includeStacktraces) {
|
||||
$str .= "\n[stacktrace]\n" . $e->getTraceAsString() . "\n";
|
||||
$str .= $this->stacktracesParser($e);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
private function stacktracesParser(\Throwable $e): string
|
||||
{
|
||||
$trace = $e->getTraceAsString();
|
||||
|
||||
if ($this->stacktracesParser) {
|
||||
$trace = $this->stacktracesParserCustom($trace);
|
||||
}
|
||||
|
||||
return "\n[stacktrace]\n" . $trace . "\n";
|
||||
}
|
||||
|
||||
private function stacktracesParserCustom(string $trace): string
|
||||
{
|
||||
return implode("\n", array_filter(array_map($this->stacktracesParser, explode("\n", $trace))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ class NormalizerFormatter implements FormatterInterface
|
||||
if ($data instanceof \JsonSerializable) {
|
||||
/** @var null|scalar|array<array|scalar|null> $value */
|
||||
$value = $data->jsonSerialize();
|
||||
} elseif (\get_class($data) === '__PHP_Incomplete_Class') {
|
||||
$accessor = new \ArrayObject($data);
|
||||
$value = (string) $accessor['__PHP_Incomplete_Class_Name'];
|
||||
} elseif (method_exists($data, '__toString')) {
|
||||
/** @var string $value */
|
||||
$value = $data->__toString();
|
||||
@@ -198,6 +201,10 @@ class NormalizerFormatter implements FormatterInterface
|
||||
*/
|
||||
protected function normalizeException(Throwable $e, int $depth = 0)
|
||||
{
|
||||
if ($depth > $this->maxNormalizeDepth) {
|
||||
return ['Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'];
|
||||
}
|
||||
|
||||
if ($e instanceof \JsonSerializable) {
|
||||
return (array) $e->jsonSerialize();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,31 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
* @var AMQPExchange|AMQPChannel $exchange
|
||||
*/
|
||||
protected $exchange;
|
||||
/** @var array<string, mixed> */
|
||||
private $extraAttributes = [];
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getExtraAttributes(): array
|
||||
{
|
||||
return $this->extraAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure extra attributes to pass to the AMQPExchange (if you are using the amqp extension)
|
||||
*
|
||||
* @param array<string, mixed> $extraAttributes One of content_type, content_encoding,
|
||||
* message_id, user_id, app_id, delivery_mode,
|
||||
* priority, timestamp, expiration, type
|
||||
* or reply_to, headers.
|
||||
* @return AmqpHandler
|
||||
*/
|
||||
public function setExtraAttributes(array $extraAttributes): self
|
||||
{
|
||||
$this->extraAttributes = $extraAttributes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@@ -60,14 +85,18 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
$routingKey = $this->getRoutingKey($record);
|
||||
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
$attributes = [
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
];
|
||||
if ($this->extraAttributes) {
|
||||
$attributes = array_merge($attributes, $this->extraAttributes);
|
||||
}
|
||||
$this->exchange->publish(
|
||||
$data,
|
||||
$routingKey,
|
||||
0,
|
||||
[
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
]
|
||||
$attributes
|
||||
);
|
||||
} else {
|
||||
$this->exchange->basic_publish(
|
||||
@@ -122,13 +151,14 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
|
||||
private function createAmqpMessage(string $data): AMQPMessage
|
||||
{
|
||||
return new AMQPMessage(
|
||||
$data,
|
||||
[
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
]
|
||||
);
|
||||
$attributes = [
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
];
|
||||
if ($this->extraAttributes) {
|
||||
$attributes = array_merge($attributes, $this->extraAttributes);
|
||||
}
|
||||
return new AMQPMessage($data, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Monolog\Handler;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Utils;
|
||||
use Monolog\Logger;
|
||||
|
||||
use function count;
|
||||
use function headers_list;
|
||||
@@ -177,7 +178,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
$extra = static::dump('Extra', $record['extra']);
|
||||
|
||||
if (empty($context) && empty($extra)) {
|
||||
$script[] = static::call_array('log', static::handleStyles($record['formatted']));
|
||||
$script[] = static::call_array(static::getConsoleMethodForLevel($record['level']), static::handleStyles($record['formatted']));
|
||||
} else {
|
||||
$script = array_merge(
|
||||
$script,
|
||||
@@ -192,6 +193,20 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
|
||||
}
|
||||
|
||||
private static function getConsoleMethodForLevel(int $level): string
|
||||
{
|
||||
return [
|
||||
Logger::DEBUG => 'debug',
|
||||
Logger::INFO => 'info',
|
||||
Logger::NOTICE => 'info',
|
||||
Logger::WARNING => 'warn',
|
||||
Logger::ERROR => 'error',
|
||||
Logger::CRITICAL => 'error',
|
||||
Logger::ALERT => 'error',
|
||||
Logger::EMERGENCY => 'error',
|
||||
][$level] ?? 'log';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
|
||||
@@ -149,7 +149,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
}
|
||||
|
||||
$json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
$data = base64_encode($json);
|
||||
if (strlen($data) > 3 * 1024) {
|
||||
self::$overflowed = true;
|
||||
|
||||
@@ -163,8 +163,8 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
'extra' => [],
|
||||
];
|
||||
self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
|
||||
$json = Utils::jsonEncode(self::$json, null, true);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
$json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true);
|
||||
$data = base64_encode($json);
|
||||
}
|
||||
|
||||
if (trim($data) !== '') {
|
||||
|
||||
@@ -17,8 +17,9 @@ use Monolog\Utils;
|
||||
/**
|
||||
* Logs to Cube.
|
||||
*
|
||||
* @link http://square.github.com/cube/
|
||||
* @link https://github.com/square/cube/wiki
|
||||
* @author Wan Chen <kami@kamisama.me>
|
||||
* @deprecated Since 2.8.0 and 3.2.0, Cube appears abandoned and thus we will drop this handler in Monolog 4
|
||||
*/
|
||||
class CubeHandler extends AbstractProcessingHandler
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Elastic\Elasticsearch\Response\Elasticsearch;
|
||||
use Throwable;
|
||||
use RuntimeException;
|
||||
use Monolog\Logger;
|
||||
@@ -19,6 +20,8 @@ use Monolog\Formatter\ElasticsearchFormatter;
|
||||
use InvalidArgumentException;
|
||||
use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException;
|
||||
use Elasticsearch\Client;
|
||||
use Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException;
|
||||
use Elastic\Elasticsearch\Client as Client8;
|
||||
|
||||
/**
|
||||
* Elasticsearch handler
|
||||
@@ -44,7 +47,7 @@ use Elasticsearch\Client;
|
||||
class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
* @var Client|Client8
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
@@ -54,11 +57,20 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @param Client $client Elasticsearch Client object
|
||||
* @param mixed[] $options Handler configuration
|
||||
* @var bool
|
||||
*/
|
||||
public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true)
|
||||
private $needsType;
|
||||
|
||||
/**
|
||||
* @param Client|Client8 $client Elasticsearch Client object
|
||||
* @param mixed[] $options Handler configuration
|
||||
*/
|
||||
public function __construct($client, array $options = [], $level = Logger::DEBUG, bool $bubble = true)
|
||||
{
|
||||
if (!$client instanceof Client && !$client instanceof Client8) {
|
||||
throw new \TypeError('Elasticsearch\Client or Elastic\Elasticsearch\Client instance required');
|
||||
}
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
$this->client = $client;
|
||||
$this->options = array_merge(
|
||||
@@ -69,6 +81,14 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
],
|
||||
$options
|
||||
);
|
||||
|
||||
if ($client instanceof Client8 || $client::VERSION[0] === '7') {
|
||||
$this->needsType = false;
|
||||
// force the type to _doc for ES8/ES7
|
||||
$this->options['type'] = '_doc';
|
||||
} else {
|
||||
$this->needsType = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,9 +153,11 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
|
||||
foreach ($records as $record) {
|
||||
$params['body'][] = [
|
||||
'index' => [
|
||||
'index' => $this->needsType ? [
|
||||
'_index' => $record['_index'],
|
||||
'_type' => $record['_type'],
|
||||
] : [
|
||||
'_index' => $record['_index'],
|
||||
],
|
||||
];
|
||||
unset($record['_index'], $record['_type']);
|
||||
@@ -143,6 +165,7 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
$params['body'][] = $record;
|
||||
}
|
||||
|
||||
/** @var Elasticsearch */
|
||||
$responses = $this->client->bulk($params);
|
||||
|
||||
if ($responses['errors'] === true) {
|
||||
@@ -160,9 +183,9 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
*
|
||||
* Only the first error is converted into an exception.
|
||||
*
|
||||
* @param mixed[] $responses returned by $this->client->bulk()
|
||||
* @param mixed[]|Elasticsearch $responses returned by $this->client->bulk()
|
||||
*/
|
||||
protected function createExceptionFromResponses(array $responses): ElasticsearchRuntimeException
|
||||
protected function createExceptionFromResponses($responses): Throwable
|
||||
{
|
||||
foreach ($responses['items'] ?? [] as $item) {
|
||||
if (isset($item['index']['error'])) {
|
||||
@@ -170,6 +193,10 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists(ElasticInvalidArgumentException::class)) {
|
||||
return new ElasticInvalidArgumentException('Elasticsearch failed to index one or more records.');
|
||||
}
|
||||
|
||||
return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.');
|
||||
}
|
||||
|
||||
@@ -178,10 +205,14 @@ class ElasticsearchHandler extends AbstractProcessingHandler
|
||||
*
|
||||
* @param mixed[] $error
|
||||
*/
|
||||
protected function createExceptionFromError(array $error): ElasticsearchRuntimeException
|
||||
protected function createExceptionFromError(array $error): Throwable
|
||||
{
|
||||
$previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null;
|
||||
|
||||
if (class_exists(ElasticInvalidArgumentException::class)) {
|
||||
return new ElasticInvalidArgumentException($error['type'] . ': ' . $error['reason'], 0, $previous);
|
||||
}
|
||||
|
||||
return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface, Rese
|
||||
*
|
||||
* @phpstan-param Record $record
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
public function getHandler(?array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = ($this->handler)($record, $this);
|
||||
|
||||
@@ -210,7 +210,7 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
|
||||
*
|
||||
* @phpstan-param Record $record
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
public function getHandler(?array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = ($this->handler)($record, $this);
|
||||
|
||||
@@ -28,6 +28,7 @@ use Monolog\Formatter\FormatterInterface;
|
||||
* @see https://www.flowdock.com/api/push
|
||||
*
|
||||
* @phpstan-import-type FormattedRecord from AbstractProcessingHandler
|
||||
* @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4
|
||||
*/
|
||||
class FlowdockHandler extends SocketHandler
|
||||
{
|
||||
|
||||
@@ -48,6 +48,15 @@ abstract class Handler implements HandlerInterface
|
||||
{
|
||||
$this->close();
|
||||
|
||||
return array_keys(get_object_vars($this));
|
||||
$reflClass = new \ReflectionClass($this);
|
||||
|
||||
$keys = [];
|
||||
foreach ($reflClass->getProperties() as $reflProp) {
|
||||
if (!$reflProp->isStatic()) {
|
||||
$keys[] = $reflProp->getName();
|
||||
}
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use PhpConsole\Helper;
|
||||
* Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely
|
||||
*
|
||||
* Usage:
|
||||
* 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef
|
||||
* 1. Install Google Chrome extension [now dead and removed from the chrome store]
|
||||
* 2. See overview https://github.com/barbushin/php-console#overview
|
||||
* 3. Install PHP Console library https://github.com/barbushin/php-console#installation
|
||||
* 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png)
|
||||
@@ -39,6 +39,7 @@ use PhpConsole\Helper;
|
||||
* @author Sergey Barbushin https://www.linkedin.com/in/barbushin
|
||||
*
|
||||
* @phpstan-import-type Record from \Monolog\Logger
|
||||
* @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4
|
||||
*/
|
||||
class PHPConsoleHandler extends AbstractProcessingHandler
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ use Monolog\Logger;
|
||||
*/
|
||||
class RedisHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/** @var \Predis\Client|\Redis */
|
||||
/** @var \Predis\Client<\Predis\Client>|\Redis */
|
||||
private $redisClient;
|
||||
/** @var string */
|
||||
private $redisKey;
|
||||
@@ -38,7 +38,7 @@ class RedisHandler extends AbstractProcessingHandler
|
||||
protected $capSize;
|
||||
|
||||
/**
|
||||
* @param \Predis\Client|\Redis $redis The redis instance
|
||||
* @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance
|
||||
* @param string $key The key name to push records to
|
||||
* @param int $capSize Number of entries to limit list size to, 0 = unlimited
|
||||
*/
|
||||
|
||||
@@ -28,13 +28,13 @@ use Monolog\Logger;
|
||||
*/
|
||||
class RedisPubSubHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/** @var \Predis\Client|\Redis */
|
||||
/** @var \Predis\Client<\Predis\Client>|\Redis */
|
||||
private $redisClient;
|
||||
/** @var string */
|
||||
private $channelKey;
|
||||
|
||||
/**
|
||||
* @param \Predis\Client|\Redis $redis The redis instance
|
||||
* @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance
|
||||
* @param string $key The channel key to publish records to
|
||||
*/
|
||||
public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true)
|
||||
|
||||
@@ -191,7 +191,11 @@ class RotatingFileHandler extends StreamHandler
|
||||
$fileInfo = pathinfo($this->filename);
|
||||
$glob = str_replace(
|
||||
['{filename}', '{date}'],
|
||||
[$fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'],
|
||||
[$fileInfo['filename'], str_replace(
|
||||
['Y', 'y', 'm', 'd'],
|
||||
['[0-9][0-9][0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]'],
|
||||
$this->dateFormat)
|
||||
],
|
||||
$fileInfo['dirname'] . '/' . $this->filenameFormat
|
||||
);
|
||||
if (isset($fileInfo['extension'])) {
|
||||
|
||||
@@ -90,7 +90,7 @@ class SamplingHandler extends AbstractHandler implements ProcessableHandlerInter
|
||||
*
|
||||
* @return HandlerInterface
|
||||
*/
|
||||
public function getHandler(array $record = null)
|
||||
public function getHandler(?array $record = null)
|
||||
{
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
$this->handler = ($this->handler)($record, $this);
|
||||
|
||||
@@ -100,7 +100,7 @@ class SlackRecord
|
||||
bool $useShortAttachment = false,
|
||||
bool $includeContextAndExtra = false,
|
||||
array $excludeFields = array(),
|
||||
FormatterInterface $formatter = null
|
||||
?FormatterInterface $formatter = null
|
||||
) {
|
||||
$this
|
||||
->setChannel($channel)
|
||||
|
||||
@@ -135,11 +135,14 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
$this->createDir($url);
|
||||
$this->errorMessage = null;
|
||||
set_error_handler([$this, 'customErrorHandler']);
|
||||
$stream = fopen($url, 'a');
|
||||
if ($this->filePermission !== null) {
|
||||
@chmod($url, $this->filePermission);
|
||||
try {
|
||||
$stream = fopen($url, 'a');
|
||||
if ($this->filePermission !== null) {
|
||||
@chmod($url, $this->filePermission);
|
||||
}
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
}
|
||||
restore_error_handler();
|
||||
if (!is_resource($stream)) {
|
||||
$this->stream = null;
|
||||
|
||||
@@ -212,7 +215,7 @@ class StreamHandler extends AbstractProcessingHandler
|
||||
set_error_handler([$this, 'customErrorHandler']);
|
||||
$status = mkdir($dir, 0777, true);
|
||||
restore_error_handler();
|
||||
if (false === $status && !is_dir($dir)) {
|
||||
if (false === $status && !is_dir($dir) && strpos((string) $this->errorMessage, 'File exists') === false) {
|
||||
throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use Swift;
|
||||
* @author Gyula Sallai
|
||||
*
|
||||
* @phpstan-import-type Record from \Monolog\Logger
|
||||
* @deprecated Since Monolog 2.6. Use SymfonyMailerHandler instead.
|
||||
*/
|
||||
class SwiftMailerHandler extends MailHandler
|
||||
{
|
||||
@@ -42,6 +43,8 @@ class SwiftMailerHandler extends MailHandler
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
@trigger_error('The SwiftMailerHandler is deprecated since Monolog 2.6. Use SymfonyMailerHandler instead.', E_USER_DEPRECATED);
|
||||
|
||||
$this->mailer = $mailer;
|
||||
$this->messageTemplate = $message;
|
||||
}
|
||||
|
||||
@@ -23,20 +23,12 @@ class UdpSocket
|
||||
/** @var int */
|
||||
protected $port;
|
||||
/** @var resource|Socket|null */
|
||||
protected $socket;
|
||||
protected $socket = null;
|
||||
|
||||
public function __construct(string $ip, int $port = 514)
|
||||
{
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$domain = AF_INET;
|
||||
$protocol = SOL_UDP;
|
||||
// Check if we are using unix sockets.
|
||||
if ($port === 0) {
|
||||
$domain = AF_UNIX;
|
||||
$protocol = IPPROTO_IP;
|
||||
}
|
||||
$this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,12 +49,34 @@ class UdpSocket
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource|Socket
|
||||
*/
|
||||
protected function getSocket()
|
||||
{
|
||||
if (null !== $this->socket) {
|
||||
return $this->socket;
|
||||
}
|
||||
|
||||
$domain = AF_INET;
|
||||
$protocol = SOL_UDP;
|
||||
// Check if we are using unix sockets.
|
||||
if ($this->port === 0) {
|
||||
$domain = AF_UNIX;
|
||||
$protocol = IPPROTO_IP;
|
||||
}
|
||||
|
||||
$this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null;
|
||||
if (null === $this->socket) {
|
||||
throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' could not be opened via socket_create');
|
||||
}
|
||||
|
||||
return $this->socket;
|
||||
}
|
||||
|
||||
protected function send(string $chunk): void
|
||||
{
|
||||
if (!is_resource($this->socket) && !$this->socket instanceof Socket) {
|
||||
throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore');
|
||||
}
|
||||
socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
|
||||
socket_sendto($this->getSocket(), $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
|
||||
}
|
||||
|
||||
protected function assembleMessage(string $line, string $header): string
|
||||
|
||||
@@ -108,9 +108,9 @@ class TelegramBotHandler extends AbstractProcessingHandler
|
||||
string $channel,
|
||||
$level = Logger::DEBUG,
|
||||
bool $bubble = true,
|
||||
string $parseMode = null,
|
||||
bool $disableWebPagePreview = null,
|
||||
bool $disableNotification = null,
|
||||
?string $parseMode = null,
|
||||
?bool $disableWebPagePreview = null,
|
||||
?bool $disableNotification = null,
|
||||
bool $splitLongMessages = false,
|
||||
bool $delayBetweenMessages = false
|
||||
)
|
||||
@@ -130,7 +130,7 @@ class TelegramBotHandler extends AbstractProcessingHandler
|
||||
$this->delayBetweenMessages($delayBetweenMessages);
|
||||
}
|
||||
|
||||
public function setParseMode(string $parseMode = null): self
|
||||
public function setParseMode(?string $parseMode = null): self
|
||||
{
|
||||
if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES)) {
|
||||
throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . implode(', ', self::AVAILABLE_PARSE_MODES) . '.');
|
||||
@@ -141,14 +141,14 @@ class TelegramBotHandler extends AbstractProcessingHandler
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disableWebPagePreview(bool $disableWebPagePreview = null): self
|
||||
public function disableWebPagePreview(?bool $disableWebPagePreview = null): self
|
||||
{
|
||||
$this->disableWebPagePreview = $disableWebPagePreview;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function disableNotification(bool $disableNotification = null): self
|
||||
public function disableNotification(?bool $disableNotification = null): self
|
||||
{
|
||||
$this->disableNotification = $disableNotification;
|
||||
|
||||
|
||||
@@ -64,4 +64,18 @@ class WhatFailureGroupHandler extends GroupHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
foreach ($this->handlers as $handler) {
|
||||
try {
|
||||
$handler->close();
|
||||
} catch (\Throwable $e) {
|
||||
// What failure?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
190
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
190
vendor/monolog/monolog/src/Monolog/Logger.php
vendored
@@ -111,6 +111,22 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
self::EMERGENCY => 'EMERGENCY',
|
||||
];
|
||||
|
||||
/**
|
||||
* Mapping between levels numbers defined in RFC 5424 and Monolog ones
|
||||
*
|
||||
* @phpstan-var array<int, Level> $rfc_5424_levels
|
||||
*/
|
||||
private const RFC_5424_LEVELS = [
|
||||
7 => self::DEBUG,
|
||||
6 => self::INFO,
|
||||
5 => self::NOTICE,
|
||||
4 => self::WARNING,
|
||||
3 => self::ERROR,
|
||||
2 => self::CRITICAL,
|
||||
1 => self::ALERT,
|
||||
0 => self::EMERGENCY,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@@ -147,6 +163,23 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
*/
|
||||
protected $exceptionHandler;
|
||||
|
||||
/**
|
||||
* @var int Keeps track of depth to prevent infinite logging loops
|
||||
*/
|
||||
private $logDepth = 0;
|
||||
|
||||
/**
|
||||
* @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops
|
||||
*/
|
||||
private $fiberLogDepth;
|
||||
|
||||
/**
|
||||
* @var bool Whether to detect infinite logging loops
|
||||
*
|
||||
* This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this
|
||||
*/
|
||||
private $detectCycles = true;
|
||||
|
||||
/**
|
||||
* @psalm-param array<callable(array): array> $processors
|
||||
*
|
||||
@@ -161,6 +194,13 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
$this->setHandlers($handlers);
|
||||
$this->processors = $processors;
|
||||
$this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get() ?: 'UTC');
|
||||
|
||||
if (\PHP_VERSION_ID >= 80100) {
|
||||
// Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
|
||||
/** @var \WeakMap<\Fiber, int> $fiberLogDepth */
|
||||
$fiberLogDepth = new \WeakMap();
|
||||
$this->fiberLogDepth = $fiberLogDepth;
|
||||
}
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
@@ -279,42 +319,85 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function useLoggingLoopDetection(bool $detectCycles): self
|
||||
{
|
||||
$this->detectCycles = $detectCycles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a log record.
|
||||
*
|
||||
* @param int $level The logging level
|
||||
* @param string $message The log message
|
||||
* @param mixed[] $context The log context
|
||||
* @return bool Whether the record has been processed
|
||||
* @param int $level The logging level (a Monolog or RFC 5424 level)
|
||||
* @param string $message The log message
|
||||
* @param mixed[] $context The log context
|
||||
* @param DateTimeImmutable $datetime Optional log date to log into the past or future
|
||||
* @return bool Whether the record has been processed
|
||||
*
|
||||
* @phpstan-param Level $level
|
||||
*/
|
||||
public function addRecord(int $level, string $message, array $context = []): bool
|
||||
public function addRecord(int $level, string $message, array $context = [], ?DateTimeImmutable $datetime = null): bool
|
||||
{
|
||||
$record = null;
|
||||
if (isset(self::RFC_5424_LEVELS[$level])) {
|
||||
$level = self::RFC_5424_LEVELS[$level];
|
||||
}
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
if (null === $record) {
|
||||
// skip creating the record as long as no handler is going to handle it
|
||||
if (!$handler->isHandling(['level' => $level])) {
|
||||
continue;
|
||||
if ($this->detectCycles) {
|
||||
if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber::getCurrent()) {
|
||||
$this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0;
|
||||
$logDepth = ++$this->fiberLogDepth[$fiber];
|
||||
} else {
|
||||
$logDepth = ++$this->logDepth;
|
||||
}
|
||||
} else {
|
||||
$logDepth = 0;
|
||||
}
|
||||
|
||||
if ($logDepth === 3) {
|
||||
$this->warning('A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.');
|
||||
return false;
|
||||
} elseif ($logDepth >= 5) { // log depth 4 is let through, so we can log the warning above
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$record = null;
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
if (null === $record) {
|
||||
// skip creating the record as long as no handler is going to handle it
|
||||
if (!$handler->isHandling(['level' => $level])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$levelName = static::getLevelName($level);
|
||||
|
||||
$record = [
|
||||
'message' => $message,
|
||||
'context' => $context,
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'channel' => $this->name,
|
||||
'datetime' => $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||
'extra' => [],
|
||||
];
|
||||
|
||||
try {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = $processor($record);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$levelName = static::getLevelName($level);
|
||||
|
||||
$record = [
|
||||
'message' => $message,
|
||||
'context' => $context,
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'channel' => $this->name,
|
||||
'datetime' => new DateTimeImmutable($this->microsecondTimestamps, $this->timezone),
|
||||
'extra' => [],
|
||||
];
|
||||
|
||||
// once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
|
||||
try {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = $processor($record);
|
||||
if (true === $handler->handle($record)) {
|
||||
break;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
@@ -322,16 +405,13 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// once the record exists, send it to all handlers as long as the bubbling chain is not interrupted
|
||||
try {
|
||||
if (true === $handler->handle($record)) {
|
||||
break;
|
||||
} finally {
|
||||
if ($this->detectCycles) {
|
||||
if (isset($fiber)) {
|
||||
$this->fiberLogDepth[$fiber]--;
|
||||
} else {
|
||||
$this->logDepth--;
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->handleException($e, $record);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +564,7 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
*
|
||||
* This method allows for compatibility with common interfaces.
|
||||
*
|
||||
* @param mixed $level The log level
|
||||
* @param mixed $level The log level (a Monolog, PSR-3 or RFC 5424 level)
|
||||
* @param string|Stringable $message The log message
|
||||
* @param mixed[] $context The log context
|
||||
*
|
||||
@@ -496,6 +576,10 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
throw new \InvalidArgumentException('$level is expected to be a string or int');
|
||||
}
|
||||
|
||||
if (isset(self::RFC_5424_LEVELS[$level])) {
|
||||
$level = self::RFC_5424_LEVELS[$level];
|
||||
}
|
||||
|
||||
$level = static::toMonologLevel($level);
|
||||
|
||||
$this->addRecord($level, (string) $message, $context);
|
||||
@@ -638,4 +722,40 @@ class Logger implements LoggerInterface, ResettableInterface
|
||||
|
||||
($this->exceptionHandler)($e, $record);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'handlers' => $this->handlers,
|
||||
'processors' => $this->processors,
|
||||
'microsecondTimestamps' => $this->microsecondTimestamps,
|
||||
'timezone' => $this->timezone,
|
||||
'exceptionHandler' => $this->exceptionHandler,
|
||||
'logDepth' => $this->logDepth,
|
||||
'detectCycles' => $this->detectCycles,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
foreach (['name', 'handlers', 'processors', 'microsecondTimestamps', 'timezone', 'exceptionHandler', 'logDepth', 'detectCycles'] as $property) {
|
||||
if (isset($data[$property])) {
|
||||
$this->$property = $data[$property];
|
||||
}
|
||||
}
|
||||
|
||||
if (\PHP_VERSION_ID >= 80100) {
|
||||
// Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412
|
||||
/** @var \WeakMap<\Fiber, int> $fiberLogDepth */
|
||||
$fiberLogDepth = new \WeakMap();
|
||||
$this->fiberLogDepth = $fiberLogDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ class PsrLogMessageProcessor implements ProcessorInterface
|
||||
} else {
|
||||
$replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
|
||||
}
|
||||
} elseif ($val instanceof \UnitEnum) {
|
||||
$replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name;
|
||||
} elseif (is_object($val)) {
|
||||
$replacements[$placeholder] = '[object '.Utils::getClass($val).']';
|
||||
} elseif (is_array($val)) {
|
||||
|
||||
@@ -43,7 +43,7 @@ class WebProcessor implements ProcessorInterface
|
||||
* @param array<string, mixed>|\ArrayAccess<string, mixed>|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data
|
||||
* @param array<string, string>|array<string>|null $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data
|
||||
*/
|
||||
public function __construct($serverData = null, array $extraFields = null)
|
||||
public function __construct($serverData = null, ?array $extraFields = null)
|
||||
{
|
||||
if (null === $serverData) {
|
||||
$this->serverData = &$_SERVER;
|
||||
|
||||
@@ -22,9 +22,20 @@ use Monolog\Formatter\FormatterInterface;
|
||||
*
|
||||
* @phpstan-import-type Record from \Monolog\Logger
|
||||
* @phpstan-import-type Level from \Monolog\Logger
|
||||
*
|
||||
* @internal feel free to reuse this to test your own handlers, this is marked internal to avoid issues with PHPStorm https://github.com/Seldaek/monolog/issues/1677
|
||||
*/
|
||||
class TestCase extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
if (isset($this->handler)) {
|
||||
unset($this->handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $context
|
||||
*
|
||||
|
||||
2
vendor/monolog/monolog/src/Monolog/Utils.php
vendored
2
vendor/monolog/monolog/src/Monolog/Utils.php
vendored
@@ -211,7 +211,7 @@ final class Utils
|
||||
$data = preg_replace_callback(
|
||||
'/[\x80-\xFF]+/',
|
||||
function ($m) {
|
||||
return utf8_encode($m[0]);
|
||||
return function_exists('mb_convert_encoding') ? mb_convert_encoding($m[0], 'UTF-8', 'ISO-8859-1') : utf8_encode($m[0]);
|
||||
},
|
||||
$data
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user