Skip to content

Commit

Permalink
Use GELF max length per field and make max length configurable in con…
Browse files Browse the repository at this point in the history
…structor
  • Loading branch information
enleur committed Apr 7, 2017
1 parent 3266b6e commit faed450
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 20 deletions.
33 changes: 17 additions & 16 deletions src/Monolog/Formatter/GelfMessageFormatter.php
Expand Up @@ -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
Expand All @@ -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.
*/
Expand All @@ -53,14 +58,15 @@ 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');

$this->systemName = $systemName ?: gethostname();

$this->extraPrefix = $extraPrefix;
$this->contextPrefix = $contextPrefix;
$this->maxLength = $maxLength;
}

/**
Expand All @@ -81,45 +87,40 @@ 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);
}

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);
Expand Down
32 changes: 28 additions & 4 deletions tests/Monolog/Formatter/GelfMessageFormatterTest.php
Expand Up @@ -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()
Expand Down

0 comments on commit faed450

Please sign in to comment.