From faed450d52d7e64ca26ce9023694e6c5e0f87bf4 Mon Sep 17 00:00:00 2001 From: Enleur Date: Fri, 7 Apr 2017 13:22:14 +0300 Subject: [PATCH] Use GELF max length per field and make max length configurable in constructor --- .../Formatter/GelfMessageFormatter.php | 33 ++++++++++--------- .../Formatter/GelfMessageFormatterTest.php | 32 +++++++++++++++--- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 64e766520..bfdfcc08b 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -22,7 +22,7 @@ */ class GelfMessageFormatter extends NormalizerFormatter { - const MAX_LENGTH = 32766; + const DEFAULT_MAX_LENGTH = 32766; /** * @var string the name of the system for the Gelf log message @@ -39,6 +39,11 @@ class GelfMessageFormatter extends NormalizerFormatter */ protected $contextPrefix; + /** + * @var int max length per field + */ + protected $maxLength; + /** * Translates Monolog log levels to Graylog2 log priorities. */ @@ -53,7 +58,7 @@ class GelfMessageFormatter extends NormalizerFormatter Logger::EMERGENCY => 0, ); - public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') + public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $maxLength = self::DEFAULT_MAX_LENGTH) { parent::__construct('U.u'); @@ -61,6 +66,7 @@ public function __construct($systemName = null, $extraPrefix = null, $contextPre $this->extraPrefix = $extraPrefix; $this->contextPrefix = $contextPrefix; + $this->maxLength = $maxLength; } /** @@ -81,35 +87,30 @@ public function format(array $record) ->setHost($this->systemName) ->setLevel($this->logLevels[$record['level']]); - // start count with message length + system name length + 200 for padding / metadata + // message length + system name length + 200 for padding / metadata $len = 200 + strlen((string) $record['message']) + strlen($this->systemName); - if ($len > self::MAX_LENGTH) { - $message->setShortMessage(substr($record['message'], 0, self::MAX_LENGTH - 200)); - - return $message; + if ($len > $this->maxLength) { + $message->setShortMessage(substr($record['message'], 0, $this->maxLength)); } if (isset($record['channel'])) { $message->setFacility($record['channel']); - $len += strlen($record['channel']); } if (isset($record['extra']['line'])) { $message->setLine($record['extra']['line']); - $len += 10; unset($record['extra']['line']); } if (isset($record['extra']['file'])) { $message->setFile($record['extra']['file']); - $len += strlen($record['extra']['file']); unset($record['extra']['file']); } foreach ($record['extra'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len += strlen($this->extraPrefix . $key . $val); - if ($len > self::MAX_LENGTH) { - $message->setAdditional($this->extraPrefix . $key, substr($val, 0, self::MAX_LENGTH - $len)); + $len = strlen($this->extraPrefix . $key . $val); + if ($len > $this->maxLength) { + $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); break; } $message->setAdditional($this->extraPrefix . $key, $val); @@ -117,9 +118,9 @@ public function format(array $record) foreach ($record['context'] as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); - $len += strlen($this->contextPrefix . $key . $val); - if ($len > self::MAX_LENGTH) { - $message->setAdditional($this->contextPrefix . $key, substr($val, 0, self::MAX_LENGTH - $len)); + $len = strlen($this->contextPrefix . $key . $val); + if ($len > $this->maxLength) { + $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); break; } $message->setAdditional($this->contextPrefix . $key, $val); diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index e6bd3098a..889dc5422 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -221,10 +221,34 @@ public function testFormatWithLargeData() } } - // in graylog2/gelf-php before 1.4.1 empty strings are filtered and won't be included in the message - // though it should be sufficient to ensure that the entire message length does not exceed the maximum - // length being allowed - $this->assertLessThanOrEqual(32766, $length, 'The message length is no longer than the maximum allowed length'); + $this->assertLessThanOrEqual(65792, $length, 'The message length is no longer than the maximum allowed length'); + } + + public function testFormatWithUnlimitedLength() + { + $formatter = new GelfMessageFormatter(null, null, 'ctxt_', PHP_INT_MAX); + $record = array( + 'level' => Logger::ERROR, + 'level_name' => 'ERROR', + 'channel' => 'meh', + 'context' => array('exception' => str_repeat(' ', 32767 * 2)), + 'datetime' => new \DateTime("@0"), + 'extra' => array('key' => str_repeat(' ', 32767 * 2)), + 'message' => 'log' + ); + $message = $formatter->format($record); + $messageArray = $message->toArray(); + + // 200 for padding + metadata + $length = 200; + + foreach ($messageArray as $key => $value) { + if (!in_array($key, array('level', 'timestamp'))) { + $length += strlen($value); + } + } + + $this->assertGreaterThanOrEqual(131289, $length, 'The message should not be truncated'); } private function isLegacy()