mirror of
https://github.com/Seldaek/monolog.git
synced 2025-07-30 09:50:26 +02:00
With `React` or `Guzzle`, that register stream wrappers with PHP, the traces are treated as coming from internal functions with no line and file inside the frame. But they almost always contain resources as arguments, on which the `json_encode()` call will choke (probably this should be addressed in json_encode internally, since it is very easy to cast a resource to a string). I added a test case proving the situation and a pretty basic recursive checker for resources which just casts them as a string into the frame again.
230 lines
7.1 KiB
PHP
230 lines
7.1 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Monolog package.
|
|
*
|
|
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Monolog\Formatter;
|
|
|
|
use Monolog\Logger;
|
|
|
|
class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase
|
|
{
|
|
public function setUp()
|
|
{
|
|
if (!class_exists('\Gelf\Message')) {
|
|
$this->markTestSkipped("graylog2/gelf-php or mlehner/gelf-php is not installed");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testDefaultFormatter()
|
|
{
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array(),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array(),
|
|
'message' => 'log',
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
$this->assertEquals(0, $message->getTimestamp());
|
|
$this->assertEquals('log', $message->getShortMessage());
|
|
$this->assertEquals('meh', $message->getFacility());
|
|
$this->assertEquals(null, $message->getLine());
|
|
$this->assertEquals(null, $message->getFile());
|
|
$this->assertEquals($this->isLegacy() ? 3 : 'error', $message->getLevel());
|
|
$this->assertNotEmpty($message->getHost());
|
|
|
|
$formatter = new GelfMessageFormatter('mysystem');
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
$this->assertEquals('mysystem', $message->getHost());
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testFormatWithFileAndLine()
|
|
{
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array('from' => 'logger'),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array('file' => 'test', 'line' => 14),
|
|
'message' => 'log',
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
$this->assertEquals('test', $message->getFile());
|
|
$this->assertEquals(14, $message->getLine());
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testFormatWithContext()
|
|
{
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array('from' => 'logger'),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array('key' => 'pair'),
|
|
'message' => 'log'
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
|
|
$message_array = $message->toArray();
|
|
|
|
$this->assertArrayHasKey('_ctxt_from', $message_array);
|
|
$this->assertEquals('logger', $message_array['_ctxt_from']);
|
|
|
|
// Test with extraPrefix
|
|
$formatter = new GelfMessageFormatter(null, null, 'CTX');
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
|
|
$message_array = $message->toArray();
|
|
|
|
$this->assertArrayHasKey('_CTXfrom', $message_array);
|
|
$this->assertEquals('logger', $message_array['_CTXfrom']);
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testFormatWithContextContainingException()
|
|
{
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array('from' => 'logger', 'exception' => array(
|
|
'class' => '\Exception',
|
|
'file' => '/some/file/in/dir.php:56',
|
|
'trace' => array('/some/file/1.php:23', '/some/file/2.php:3')
|
|
)),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array(),
|
|
'message' => 'log'
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
|
|
$this->assertEquals("/some/file/in/dir.php", $message->getFile());
|
|
$this->assertEquals("56", $message->getLine());
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testFormatWithExtra()
|
|
{
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array('from' => 'logger'),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array('key' => 'pair'),
|
|
'message' => 'log'
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
|
|
$message_array = $message->toArray();
|
|
|
|
$this->assertArrayHasKey('_key', $message_array);
|
|
$this->assertEquals('pair', $message_array['_key']);
|
|
|
|
// Test with extraPrefix
|
|
$formatter = new GelfMessageFormatter(null, 'EXT');
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertInstanceOf('Gelf\Message', $message);
|
|
|
|
$message_array = $message->toArray();
|
|
|
|
$this->assertArrayHasKey('_EXTkey', $message_array);
|
|
$this->assertEquals('pair', $message_array['_EXTkey']);
|
|
}
|
|
|
|
/**
|
|
* @covers Monolog\Formatter\GelfMessageFormatter::format
|
|
*/
|
|
public function testExceptionObjectWithResourceTrace()
|
|
{
|
|
// This happens i.e. in React promises or Guzzle streams where stream wrappers are registered
|
|
// and no file or line are included in the trace because it's treated as internal function
|
|
set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
|
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
|
});
|
|
|
|
try {
|
|
$resource = fopen('php://memory', '+w');
|
|
// Just do something stupid with a resource as argument
|
|
strpos($resource);
|
|
} catch (\Exception $e) {
|
|
}
|
|
|
|
// restore the error handler
|
|
restore_error_handler();
|
|
|
|
$formatter = new GelfMessageFormatter();
|
|
$record = array(
|
|
'level' => Logger::ERROR,
|
|
'level_name' => 'ERROR',
|
|
'channel' => 'meh',
|
|
'context' => array('from' => 'logger', 'exception' => $e),
|
|
'datetime' => new \DateTime("@0"),
|
|
'extra' => array(),
|
|
'message' => 'log'
|
|
);
|
|
|
|
$message = $formatter->format($record);
|
|
|
|
$this->assertRegExp(
|
|
'%\\\\"resource\\\\":\\\\"Resource id #\d+\\\\"%',
|
|
$message->getAdditional('ctxt_exception')
|
|
);
|
|
}
|
|
|
|
private function isLegacy()
|
|
{
|
|
return interface_exists('\Gelf\IMessagePublisher');
|
|
}
|
|
}
|