diff --git a/composer.json b/composer.json index 85637ddd..21d80648 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,8 @@ "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" + "php-console/php-console": "Allow sending log messages to Google Chrome", + "ext-mbstring": "Allow to work properly with unicode symbols" }, "autoload": { "psr-4": {"Monolog\\": "src/Monolog"} diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index e5626794..271628a3 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -13,6 +13,7 @@ namespace Monolog\Formatter; use Monolog\Logger; use Gelf\Message; +use Monolog\Utils; /** * Serializes a log message to GELF @@ -96,7 +97,7 @@ class GelfMessageFormatter extends NormalizerFormatter $len = 200 + strlen((string) $record['message']) + strlen($this->systemName); if ($len > $this->maxLength) { - $message->setShortMessage(substr($record['message'], 0, $this->maxLength)); + $message->setShortMessage(Utils::substr($record['message'], 0, $this->maxLength)); } if (isset($record['channel'])) { @@ -115,7 +116,8 @@ class GelfMessageFormatter extends NormalizerFormatter $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); + $message->setAdditional($this->extraPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + continue; } $message->setAdditional($this->extraPrefix . $key, $val); @@ -125,7 +127,8 @@ class GelfMessageFormatter extends NormalizerFormatter $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); + $message->setAdditional($this->contextPrefix . $key, Utils::substr($val, 0, $this->maxLength)); + continue; } $message->setAdditional($this->contextPrefix . $key, $val); diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index 5e46b13b..4dff9f24 100644 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; +use Monolog\Utils; /** * Handler sending logs to browser's javascript console with no browser extension required @@ -175,7 +176,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler $args[] = '"font-weight: normal"'; $pos = $match[0][1]; - $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); + $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + strlen($match[0][0])); } array_unshift($args, static::quote($format)); diff --git a/src/Monolog/Handler/Curl/Util.php b/src/Monolog/Handler/Curl/Util.php index 91e81bb6..b0aeac9c 100644 --- a/src/Monolog/Handler/Curl/Util.php +++ b/src/Monolog/Handler/Curl/Util.php @@ -31,9 +31,9 @@ final class Util /** * Executes a CURL request with optional retries and exception on failure * - * @param resource $ch curl handler - * @param int $retries - * @param bool $closeAfterDone + * @param resource $ch curl handler + * @param int $retries + * @param bool $closeAfterDone * @return bool|string @see curl_exec */ public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) @@ -65,4 +65,4 @@ final class Util return false; } -} \ No newline at end of file +} diff --git a/src/Monolog/Handler/OverflowHandler.php b/src/Monolog/Handler/OverflowHandler.php index 30e81c43..3d034b97 100644 --- a/src/Monolog/Handler/OverflowHandler.php +++ b/src/Monolog/Handler/OverflowHandler.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Logger; - /** * Handler to only pass log messages when a certain threshold of number of messages is reached. * @@ -60,9 +59,9 @@ class OverflowHandler extends AbstractHandler /** * @param HandlerInterface $handler - * @param int[] $thresholdMap Dictionary of logger level => threshold - * @param int $level - * @param bool $bubble + * @param int[] $thresholdMap Dictionary of logger level => threshold + * @param int $level + * @param bool $bubble */ public function __construct( HandlerInterface $handler, @@ -87,7 +86,7 @@ class OverflowHandler extends AbstractHandler * 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 + * @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. @@ -108,6 +107,7 @@ class OverflowHandler extends AbstractHandler // The overflow threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 $this->thresholdMap[$level]--; $this->buffer[$level][] = $record; + return false === $this->bubble; } diff --git a/src/Monolog/Handler/PushoverHandler.php b/src/Monolog/Handler/PushoverHandler.php index 2689de1c..3bb99c75 100644 --- a/src/Monolog/Handler/PushoverHandler.php +++ b/src/Monolog/Handler/PushoverHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\Utils; /** * Sends notifications through the pushover api to mobile phones @@ -118,7 +119,7 @@ class PushoverHandler extends SocketHandler $maxMessageLength = 512 - strlen($this->title); $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message']; - $message = substr($message, 0, $maxMessageLength); + $message = Utils::substr($message, 0, $maxMessageLength); $timestamp = $record['datetime']->getTimestamp(); diff --git a/src/Monolog/Handler/SqsHandler.php b/src/Monolog/Handler/SqsHandler.php index 2c89a33d..a98c87bf 100644 --- a/src/Monolog/Handler/SqsHandler.php +++ b/src/Monolog/Handler/SqsHandler.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Aws\Sqs\SqsClient; use Monolog\Logger; +use Monolog\Utils; /** * Writes to any sqs queue. @@ -52,7 +53,7 @@ class SqsHandler extends AbstractProcessingHandler $messageBody = $record['formatted']; if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { - $messageBody = substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); + $messageBody = Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); } $this->client->sendMessage([ diff --git a/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/src/Monolog/Handler/SyslogUdp/UdpSocket.php index ad7bb2d9..c43bc156 100644 --- a/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -11,6 +11,8 @@ namespace Monolog\Handler\SyslogUdp; +use Monolog\Utils; + class UdpSocket { protected const DATAGRAM_MAX_LENGTH = 65023; @@ -54,6 +56,6 @@ class UdpSocket { $chunkSize = static::DATAGRAM_MAX_LENGTH - strlen($header); - return $header . substr($line, 0, $chunkSize); + return $header . Utils::substr($line, 0, $chunkSize); } } diff --git a/src/Monolog/Handler/TelegramBotHandler.php b/src/Monolog/Handler/TelegramBotHandler.php index 34a87da5..5dae9f54 100644 --- a/src/Monolog/Handler/TelegramBotHandler.php +++ b/src/Monolog/Handler/TelegramBotHandler.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog\Handler; @@ -38,7 +47,7 @@ class TelegramBotHandler extends AbstractProcessingHandler private $channel; /** - * @param string $apiKey Telegram bot access token provided by BotFather + * @param string $apiKey Telegram bot access token provided by BotFather * @param string $channel Telegram channel name * @inheritDoc */ @@ -87,4 +96,4 @@ class TelegramBotHandler extends AbstractProcessingHandler throw new RuntimeException('Telegram API error. Description: ' . $result['description']); } } -} \ No newline at end of file +} diff --git a/src/Monolog/Utils.php b/src/Monolog/Utils.php index 14b76661..c3890422 100644 --- a/src/Monolog/Utils.php +++ b/src/Monolog/Utils.php @@ -22,4 +22,13 @@ final class Utils return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; } + + public static function substr(string $string, int $start, ?int $length = null) + { + if (extension_loaded('mbstring')) { + return mb_strcut($string, $start, $length); + } + + return substr($string, $start, $length); + } } diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index 3d58f58b..88eb9a4a 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -253,6 +253,26 @@ class GelfMessageFormatterTest extends TestCase $this->assertGreaterThanOrEqual(131289, $length, 'The message should not be truncated'); } + public function testFormatWithLargeCyrillicData() + { + $formatter = new GelfMessageFormatter(); + $record = [ + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => ['exception' => str_repeat('а', 32767)], + 'datetime' => new \DateTimeImmutable("@0"), + 'extra' => ['key' => str_repeat('б', 32767)], + 'message' => str_repeat('в', 32767), + ]; + $message = $formatter->format($record); + $messageArray = $message->toArray(); + + $messageString = json_encode($messageArray); + + $this->assertIsString($messageString); + } + private function isLegacy() { return interface_exists('\Gelf\IMessagePublisher'); diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index 680de290..a3b6bff9 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -14,7 +14,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; use PhpAmqpLib\Message\AMQPMessage; -use PhpAmqpLib\Connection\AMQPConnection; /** * @covers Monolog\Handler\RotatingFileHandler diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 6c346e48..87be8172 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -67,7 +67,6 @@ class SyslogUdpHandlerTest extends TestCase $handler->handle($this->getRecordWithMessage(null)); } - public function testRfc() { $time = 'Jan 07 12:34:56'; diff --git a/tests/Monolog/Handler/TelegramBotHandlerTest.php b/tests/Monolog/Handler/TelegramBotHandlerTest.php index 6e09aadd..1d36406b 100644 --- a/tests/Monolog/Handler/TelegramBotHandlerTest.php +++ b/tests/Monolog/Handler/TelegramBotHandlerTest.php @@ -1,4 +1,13 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Monolog\Handler;