From 891acbeeb9a141ae2dd110f137dcbbf01c77c9e2 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Wed, 22 Feb 2012 19:37:33 -0500 Subject: [PATCH 01/14] added GelfHandler for sending log messages to Graylog2 --- src/Monolog/Handler/GelfHandler.php | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/Monolog/Handler/GelfHandler.php diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php new file mode 100644 index 00000000..3fcf9009 --- /dev/null +++ b/src/Monolog/Handler/GelfHandler.php @@ -0,0 +1,110 @@ + + */ +class GelfHandler extends AbstractProcessingHandler +{ + /* + * @var Gelf\MessagePublisher the publisher object that sends the message to the server + */ + protected $publisher; + + /* + * @var string the name of the system for the Gelf log message + */ + protected $system_name; + + /* + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extra_prefix; + + /* + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $context_prefix; + + /** + * Translates Monolog log levels to Graylog2 log priorities. + */ + private $logLevels = array( + Logger::DEBUG => LOG_DEBUG, + Logger::INFO => LOG_INFO, + Logger::WARNING => LOG_WARNING, + Logger::ERROR => LOG_ERR, + Logger::CRITICAL => LOG_CRIT, + Logger::ALERT => LOG_ALERT, + ); + + /** + * @param Gelf\MessagePublisher $publisher a publisher object + * @param string $system_name the name of the system sending messages + * @param integer $level The minimum logging level at which this handler will be triggered + * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $extra_prefix a string to prefix for all the 'extra' fields from Monolog record + * @oaram string $context_prefix a string to prefix for all the 'context' fields from a Monolog record + */ + public function __construct(MessagePublisher $publisher, $system_name = null, $level = Logger::DEBUG, $bubble = true, $extra_prefix = null, $context_prefix = null) + { + parent::__construct($level, $bubble); + + $this->publisher = $publisher; + $this->system_name = $system_name ?: gethostname(); + + $this->extra_prefix = $extra_prefix; + $this->context_prefix = $context_prefix; + } + + /** + * {@inheritdoc} + */ + public function close() + { + $this->publisher = null; + } + + /** + * {@inheritdoc} + */ + public function write(array $record) + { + $message = new Message(); + $message + ->setTimestamp($record['datetime']->format('U.u')) + ->setShortMessage((string) $record['message']) + ->setFullMessage((string) $record['formatted']) + ->setFacility($record['channel']) + ->setHost($this->system_name) + ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) + ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) + ->setLevel($this->logLevels[ $record['level'] ]); + + // Do not duplicate these values in the additional fields + unset($record['extra']['line']); + unset($record['extra']['file']); + + foreach ($record['extra'] as $key => $val) + { + $message->setAdditional($this->extra_prefix . $key, is_scalar($val) ? $val : json_encode($val)); + } + + foreach ($record['context'] as $key => $val) + { + $message->setAdditional($this->context_prefix . $key, is_scalar($val) ? $val : json_encode($val)); + } + + $this->publisher->publish($message); + } +} From c9e61750d096240701129cf0577f75c6b1fb2ef3 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Thu, 5 Apr 2012 22:40:07 -0700 Subject: [PATCH 02/14] Make some changes suggested by @stof in https://github.com/Seldaek/monolog/pull/61 --- composer.json | 9 ++++ src/Monolog/Handler/GelfHandler.php | 54 +++++++++++++---------- tests/Monolog/Handler/GelfHandlerTest.php | 40 +++++++++++++++++ 3 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 tests/Monolog/Handler/GelfHandlerTest.php diff --git a/composer.json b/composer.json index a6e4954c..7585d498 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,15 @@ "require": { "php": ">=5.3.0" }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/mlehner/gelf-php" + } + ], + "suggest": { + "gelf-php": ">=0" + }, "autoload": { "psr-0": {"Monolog": "src/"} } diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 3fcf9009..ad4aaabe 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -1,11 +1,18 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; use Gelf\Message; use Gelf\MessagePublisher; - -use Monolog\Formatter\SimpleFormatter; use Monolog\Logger; use Monolog\Handler\AbstractProcessingHandler; @@ -16,25 +23,25 @@ use Monolog\Handler\AbstractProcessingHandler; */ class GelfHandler extends AbstractProcessingHandler { - /* + /** * @var Gelf\MessagePublisher the publisher object that sends the message to the server */ protected $publisher; - /* + /** * @var string the name of the system for the Gelf log message */ - protected $system_name; + protected $systemName; - /* + /** * @var string a prefix for 'extra' fields from the Monolog record (optional) */ - protected $extra_prefix; + protected $extraPrefix; - /* + /** * @var string a prefix for 'context' fields from the Monolog record (optional) */ - protected $context_prefix; + protected $contentPrefix; /** * Translates Monolog log levels to Graylog2 log priorities. @@ -50,21 +57,22 @@ class GelfHandler extends AbstractProcessingHandler /** * @param Gelf\MessagePublisher $publisher a publisher object - * @param string $system_name the name of the system sending messages + * @param string $systemName the name of the system sending messages * @param integer $level The minimum logging level at which this handler will be triggered * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param string $extra_prefix a string to prefix for all the 'extra' fields from Monolog record - * @oaram string $context_prefix a string to prefix for all the 'context' fields from a Monolog record + * @param string $extraPrefix a string to prefix for all the 'extra' fields from Monolog record + * @oaram string $contentPrefix a string to prefix for all the 'context' fields from a Monolog record */ - public function __construct(MessagePublisher $publisher, $system_name = null, $level = Logger::DEBUG, $bubble = true, $extra_prefix = null, $context_prefix = null) + public function __construct(MessagePublisher $publisher, $systemName = null, $level = Logger::DEBUG, + $bubble = true, $extraPrefix = null, $contentPrefix = 'ctxt_') { parent::__construct($level, $bubble); $this->publisher = $publisher; - $this->system_name = $system_name ?: gethostname(); + $this->systemName = $systemName ?: gethostname(); - $this->extra_prefix = $extra_prefix; - $this->context_prefix = $context_prefix; + $this->extraPrefix = $extraPrefix; + $this->contentPrefix = $contentPrefix; } /** @@ -86,7 +94,7 @@ class GelfHandler extends AbstractProcessingHandler ->setShortMessage((string) $record['message']) ->setFullMessage((string) $record['formatted']) ->setFacility($record['channel']) - ->setHost($this->system_name) + ->setHost($this->systemName) ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) ->setLevel($this->logLevels[ $record['level'] ]); @@ -95,14 +103,12 @@ class GelfHandler extends AbstractProcessingHandler unset($record['extra']['line']); unset($record['extra']['file']); - foreach ($record['extra'] as $key => $val) - { - $message->setAdditional($this->extra_prefix . $key, is_scalar($val) ? $val : json_encode($val)); + foreach ($record['extra'] as $key => $val) { + $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : json_encode($val)); } - foreach ($record['context'] as $key => $val) - { - $message->setAdditional($this->context_prefix . $key, is_scalar($val) ? $val : json_encode($val)); + foreach ($record['context'] as $key => $val) { + $message->setAdditional($this->contentPrefix . $key, is_scalar($val) ? $val : json_encode($val)); } $this->publisher->publish($message); diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php new file mode 100644 index 00000000..1633bd29 --- /dev/null +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Gelf\MessagePublisher; + +class GelfHandlerTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + if (!class_exists("MessagePublisher")) + { + $this->markTestSkipped("https://github.com/mlehner/gelf-php not installed"); + } + } + + /** + * @covers Monolog\Handler\GelfHandler::__construct + */ + public function testConstruct() + { + $handler = new GelfHandler($this->getMessagePublisher()); + $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); + } + + protected function getMessagePublisher() + { + return new MessagePublisher(); + } +} From 14ac76a0aefee79dfd4a9045f594a731a959c8bb Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Apr 2012 07:25:02 -0700 Subject: [PATCH 03/14] Pull in mlehner/gelf-php via Composer --- .gitignore | 2 ++ composer.json | 10 +++++++++- composer.lock | 11 +++++++++++ tests/Monolog/Handler/GelfHandlerTest.php | 15 ++++++++++++--- tests/bootstrap.php | 1 + 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 57be4e31..bebd336c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +vendor +composer.phar phpunit.xml \ No newline at end of file diff --git a/composer.json b/composer.json index 7585d498..c60dc301 100644 --- a/composer.json +++ b/composer.json @@ -19,10 +19,18 @@ { "type": "vcs", "url": "https://github.com/mlehner/gelf-php" + }, + { + "type": "vcs", + "url": "https://github.com/msabramo/gelf-php-1" + }, + { + "type": "vcs", + "url": "https://github.com/msabramo/gelf-php" } ], "suggest": { - "gelf-php": ">=0" + "mlehner/gelf-php": "dev-add-composer-support" }, "autoload": { "psr-0": {"Monolog": "src/"} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..034897c8 --- /dev/null +++ b/composer.lock @@ -0,0 +1,11 @@ +{ + "hash": "5715c4c52bc66b23002954fb3a2f47e4", + "packages": [ + { + "package": "mlehner/gelf-php", + "version": "dev-add-composer-support", + "source-reference": "39419c2b75daf6b9eb9feb6ac0541807ee888cda" + } + ], + "aliases": [] +} diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 1633bd29..cfd2f640 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -11,14 +11,15 @@ namespace Monolog\Handler; +use Monolog\TestCase; use Monolog\Logger; use Gelf\MessagePublisher; -class GelfHandlerTest extends \PHPUnit_Framework_TestCase +class GelfHandlerTest extends TestCase { public function setUp() { - if (!class_exists("MessagePublisher")) + if (!class_exists("Gelf\MessagePublisher")) { $this->markTestSkipped("https://github.com/mlehner/gelf-php not installed"); } @@ -35,6 +36,14 @@ class GelfHandlerTest extends \PHPUnit_Framework_TestCase protected function getMessagePublisher() { - return new MessagePublisher(); + return new MessagePublisher('localhost'); + } + + public function testStuff() + { + $handler = new GelfHandler($this->getMessagePublisher()); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Logger::DEBUG)); + $handler->handle($this->getRecord(Logger::WARNING)); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e3610ebc..dc92e51d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -9,6 +9,7 @@ * file that was distributed with this source code. */ +require_once __DIR__ . "/../vendor/.composer/autoload.php"; require_once __DIR__.'/Monolog/TestCase.php'; spl_autoload_register(function($class) From bd28443b730895a6a3667d07c781e231f44d85d4 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Fri, 6 Apr 2012 08:30:26 -0700 Subject: [PATCH 04/14] Test using a MockMessagePublisher --- tests/Monolog/Handler/GelfHandlerTest.php | 51 +++++++++++++++++++---- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index cfd2f640..81a1ca15 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -14,6 +14,16 @@ namespace Monolog\Handler; use Monolog\TestCase; use Monolog\Logger; use Gelf\MessagePublisher; +use Gelf\Message; + +class MockMessagePublisher extends MessagePublisher +{ + public function publish(Message $message) { + $this->lastMessage = $message; + } + + public $lastMessage = null; +} class GelfHandlerTest extends TestCase { @@ -34,16 +44,43 @@ class GelfHandlerTest extends TestCase $this->assertInstanceOf('Monolog\Handler\GelfHandler', $handler); } - protected function getMessagePublisher() + protected function getHandler($messagePublisher) { - return new MessagePublisher('localhost'); + $handler = new GelfHandler($messagePublisher); + $handler->setFormatter($this->getIdentityFormatter()); + return $handler; } - public function testStuff() + protected function getMessagePublisher() { - $handler = new GelfHandler($this->getMessagePublisher()); - $handler->setFormatter($this->getIdentityFormatter()); - $handler->handle($this->getRecord(Logger::DEBUG)); - $handler->handle($this->getRecord(Logger::WARNING)); + return new MockMessagePublisher('localhost'); + } + + public function testDebug() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $record = $this->getRecord(Logger::DEBUG, "A test debug message"); + $handler->handle($record); + + $this->assertEquals(7, $messagePublisher->lastMessage->getLevel()); + $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getFullMessage()); + } + + public function testWarning() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $handler->handle($record); + + $this->assertEquals(4, $messagePublisher->lastMessage->getLevel()); + $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); + $this->assertEquals($record['message'], $messagePublisher->lastMessage->getFullMessage()); } } From 2a4fd11998af97ddee680a200d7b44258795e43a Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Mon, 16 Apr 2012 20:32:10 -0400 Subject: [PATCH 05/14] added composer.lock to ignore, mlehner/gelf-php is now registered on packagist --- .gitignore | 3 ++- composer.json | 16 +--------------- composer.lock | 11 ----------- 3 files changed, 3 insertions(+), 27 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index bebd336c..aba4f4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor composer.phar -phpunit.xml \ No newline at end of file +phpunit.xml +composer.lock diff --git a/composer.json b/composer.json index c60dc301..acaf5616 100644 --- a/composer.json +++ b/composer.json @@ -15,22 +15,8 @@ "require": { "php": ">=5.3.0" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/mlehner/gelf-php" - }, - { - "type": "vcs", - "url": "https://github.com/msabramo/gelf-php-1" - }, - { - "type": "vcs", - "url": "https://github.com/msabramo/gelf-php" - } - ], "suggest": { - "mlehner/gelf-php": "dev-add-composer-support" + "mlehner/gelf-php": "dev-master" }, "autoload": { "psr-0": {"Monolog": "src/"} diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 034897c8..00000000 --- a/composer.lock +++ /dev/null @@ -1,11 +0,0 @@ -{ - "hash": "5715c4c52bc66b23002954fb3a2f47e4", - "packages": [ - { - "package": "mlehner/gelf-php", - "version": "dev-add-composer-support", - "source-reference": "39419c2b75daf6b9eb9feb6ac0541807ee888cda" - } - ], - "aliases": [] -} From b8e409d307aea19927e4ec6b2cdd1fc9fbaaf6ee Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Tue, 17 Apr 2012 14:46:07 -0400 Subject: [PATCH 06/14] added require-dev block for tests, added proper description for suggested package --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index acaf5616..43c82816 100644 --- a/composer.json +++ b/composer.json @@ -15,9 +15,12 @@ "require": { "php": ">=5.3.0" }, - "suggest": { + "require-dev": { "mlehner/gelf-php": "dev-master" }, + "suggest": { + "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server" + }, "autoload": { "psr-0": {"Monolog": "src/"} } From d551f340b8bb08ec2351aa040f94950e421a3c37 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Tue, 17 Apr 2012 14:46:28 -0400 Subject: [PATCH 07/14] removed un-needed autoload function --- tests/bootstrap.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index dc92e51d..ea4bb20d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -11,12 +11,3 @@ require_once __DIR__ . "/../vendor/.composer/autoload.php"; require_once __DIR__.'/Monolog/TestCase.php'; - -spl_autoload_register(function($class) -{ - $file = __DIR__.'/../src/'.strtr($class, '\\', '/').'.php'; - if (file_exists($file)) { - require $file; - return true; - } -}); From 979c4655f96cec438264961ce6708f5a0f9a03b2 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Tue, 17 Apr 2012 16:17:43 -0400 Subject: [PATCH 08/14] created GelfMessageFormatter and related tests --- .../Formatter/GelfMessageFormatter.php | 102 ++++++++++++ src/Monolog/Handler/GelfHandler.php | 76 ++------- .../Formatter/GelfMessageFormatterTest.php | 150 ++++++++++++++++++ tests/Monolog/Handler/GelfHandlerTest.php | 5 +- 4 files changed, 267 insertions(+), 66 deletions(-) create mode 100644 src/Monolog/Formatter/GelfMessageFormatter.php create mode 100644 tests/Monolog/Formatter/GelfMessageFormatterTest.php diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php new file mode 100644 index 00000000..9ad65319 --- /dev/null +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -0,0 +1,102 @@ + + * + * 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; +use Gelf\Message; + +/** + * Serializes a log message according to Wildfire's header requirements + * + * @author Matt Lehner + */ +class GelfMessageFormatter implements FormatterInterface +{ + /** + * @var string the name of the system for the Gelf log message + */ + protected $systemName; + + /** + * @var string a prefix for 'extra' fields from the Monolog record (optional) + */ + protected $extraPrefix; + + /** + * @var string a prefix for 'context' fields from the Monolog record (optional) + */ + protected $contentPrefix; + + /** + * Translates Monolog log levels to Graylog2 log priorities. + */ + private $logLevels = array( + Logger::DEBUG => LOG_DEBUG, + Logger::INFO => LOG_INFO, + Logger::WARNING => LOG_WARNING, + Logger::ERROR => LOG_ERR, + Logger::CRITICAL => LOG_CRIT, + Logger::ALERT => LOG_ALERT, + ); + + public function __construct($systemName = null, $extraPrefix = null, $contentPrefix = 'ctxt_') + { + $this->systemName = $systemName ?: gethostname(); + + $this->extraPrefix = $extraPrefix; + $this->contentPrefix = $contentPrefix; + } + + /** + * {@inheritdoc} + */ + public function format(array $record) + { + $message = new Message(); + $message + ->setTimestamp($record['datetime']->format('U.u')) + ->setShortMessage((string) $record['message']) + ->setFacility($record['channel']) + ->setHost($this->systemName) + ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) + ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) + ->setLevel($this->logLevels[ $record['level'] ]); + + // Do not duplicate these values in the additional fields + unset($record['extra']['line']); + unset($record['extra']['file']); + + foreach ($record['extra'] as $key => $val) { + $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : json_encode($val)); + } + + foreach ($record['context'] as $key => $val) { + $message->setAdditional($this->contentPrefix . $key, is_scalar($val) ? $val : json_encode($val)); + } + + return $message; + } + + /** + * {@inheritdoc} + */ + public function formatBatch(array $records) + { + $messages = array(); + + foreach ($records as $record) { + $messages[] = $this->format($record); + } + + return $messages; + } +} diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index ad4aaabe..2eec8fc1 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -11,10 +11,10 @@ namespace Monolog\Handler; -use Gelf\Message; -use Gelf\MessagePublisher; +use Gelf\IMessagePublisher; use Monolog\Logger; use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Formatter\GelfMessageFormatter; /** * Handler to send messages to a Graylog2 (http://www.graylog2.org) server @@ -24,55 +24,28 @@ use Monolog\Handler\AbstractProcessingHandler; class GelfHandler extends AbstractProcessingHandler { /** - * @var Gelf\MessagePublisher the publisher object that sends the message to the server + * @var Gelf\IMessagePublisher the publisher object that sends the message to the server */ protected $publisher; /** - * @var string the name of the system for the Gelf log message - */ - protected $systemName; - - /** - * @var string a prefix for 'extra' fields from the Monolog record (optional) - */ - protected $extraPrefix; - - /** - * @var string a prefix for 'context' fields from the Monolog record (optional) - */ - protected $contentPrefix; - - /** - * Translates Monolog log levels to Graylog2 log priorities. - */ - private $logLevels = array( - Logger::DEBUG => LOG_DEBUG, - Logger::INFO => LOG_INFO, - Logger::WARNING => LOG_WARNING, - Logger::ERROR => LOG_ERR, - Logger::CRITICAL => LOG_CRIT, - Logger::ALERT => LOG_ALERT, - ); - - /** - * @param Gelf\MessagePublisher $publisher a publisher object - * @param string $systemName the name of the system sending messages + * @param Gelf\IMessagePublisher $publisher a publisher object * @param integer $level The minimum logging level at which this handler will be triggered * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not - * @param string $extraPrefix a string to prefix for all the 'extra' fields from Monolog record - * @oaram string $contentPrefix a string to prefix for all the 'context' fields from a Monolog record */ - public function __construct(MessagePublisher $publisher, $systemName = null, $level = Logger::DEBUG, - $bubble = true, $extraPrefix = null, $contentPrefix = 'ctxt_') + public function __construct(IMessagePublisher $publisher, $level = Logger::DEBUG, $bubble = true) { parent::__construct($level, $bubble); $this->publisher = $publisher; - $this->systemName = $systemName ?: gethostname(); + } - $this->extraPrefix = $extraPrefix; - $this->contentPrefix = $contentPrefix; + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new GelfMessageFormatter(); } /** @@ -88,29 +61,6 @@ class GelfHandler extends AbstractProcessingHandler */ public function write(array $record) { - $message = new Message(); - $message - ->setTimestamp($record['datetime']->format('U.u')) - ->setShortMessage((string) $record['message']) - ->setFullMessage((string) $record['formatted']) - ->setFacility($record['channel']) - ->setHost($this->systemName) - ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) - ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) - ->setLevel($this->logLevels[ $record['level'] ]); - - // Do not duplicate these values in the additional fields - unset($record['extra']['line']); - unset($record['extra']['file']); - - foreach ($record['extra'] as $key => $val) { - $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : json_encode($val)); - } - - foreach ($record['context'] as $key => $val) { - $message->setAdditional($this->contentPrefix . $key, is_scalar($val) ? $val : json_encode($val)); - } - - $this->publisher->publish($message); + $this->publisher->publish($record['formatted']); } } diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php new file mode 100644 index 00000000..d03fc5c1 --- /dev/null +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -0,0 +1,150 @@ + + * + * 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 +{ + /** + * @covers Monolog\Formatter\GelfMessageFormatter::format + */ + 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(LOG_ERR, $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 + */ + 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 + */ + 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 + */ + 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']); + } +} diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 81a1ca15..3e9420a3 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -47,7 +47,6 @@ class GelfHandlerTest extends TestCase protected function getHandler($messagePublisher) { $handler = new GelfHandler($messagePublisher); - $handler->setFormatter($this->getIdentityFormatter()); return $handler; } @@ -67,7 +66,7 @@ class GelfHandlerTest extends TestCase $this->assertEquals(7, $messagePublisher->lastMessage->getLevel()); $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); - $this->assertEquals($record['message'], $messagePublisher->lastMessage->getFullMessage()); + $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); } public function testWarning() @@ -81,6 +80,6 @@ class GelfHandlerTest extends TestCase $this->assertEquals(4, $messagePublisher->lastMessage->getLevel()); $this->assertEquals('test', $messagePublisher->lastMessage->getFacility()); $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); - $this->assertEquals($record['message'], $messagePublisher->lastMessage->getFullMessage()); + $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); } } From 97b65bc3e491b8c0841d3f4daaecfa9434e9607b Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Tue, 17 Apr 2012 16:24:50 -0400 Subject: [PATCH 09/14] contentPrefix should be contextPrefix --- src/Monolog/Formatter/GelfMessageFormatter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Formatter/GelfMessageFormatter.php b/src/Monolog/Formatter/GelfMessageFormatter.php index 9ad65319..e3ecb2ec 100644 --- a/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/src/Monolog/Formatter/GelfMessageFormatter.php @@ -34,7 +34,7 @@ class GelfMessageFormatter implements FormatterInterface /** * @var string a prefix for 'context' fields from the Monolog record (optional) */ - protected $contentPrefix; + protected $contextPrefix; /** * Translates Monolog log levels to Graylog2 log priorities. @@ -48,12 +48,12 @@ class GelfMessageFormatter implements FormatterInterface Logger::ALERT => LOG_ALERT, ); - public function __construct($systemName = null, $extraPrefix = null, $contentPrefix = 'ctxt_') + public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') { $this->systemName = $systemName ?: gethostname(); $this->extraPrefix = $extraPrefix; - $this->contentPrefix = $contentPrefix; + $this->contextPrefix = $contextPrefix; } /** @@ -80,7 +80,7 @@ class GelfMessageFormatter implements FormatterInterface } foreach ($record['context'] as $key => $val) { - $message->setAdditional($this->contentPrefix . $key, is_scalar($val) ? $val : json_encode($val)); + $message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : json_encode($val)); } return $message; From 07338af3236b59524ac2f73bc420085678e865c1 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Tue, 17 Apr 2012 16:25:53 -0400 Subject: [PATCH 10/14] test injecting a GelfMessageFormatter with constructor arguments --- tests/Monolog/Handler/GelfHandlerTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 3e9420a3..5e438d46 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -13,6 +13,7 @@ namespace Monolog\Handler; use Monolog\TestCase; use Monolog\Logger; +use Monolog\Formatter\GelfMessageFormatter; use Gelf\MessagePublisher; use Gelf\Message; @@ -82,4 +83,21 @@ class GelfHandlerTest extends TestCase $this->assertEquals($record['message'], $messagePublisher->lastMessage->getShortMessage()); $this->assertEquals(null, $messagePublisher->lastMessage->getFullMessage()); } + + public function testInjectedGelfMessageFormatter() + { + $messagePublisher = $this->getMessagePublisher(); + $handler = $this->getHandler($messagePublisher); + + $handler->setFormatter(new GelfMessageFormatter('mysystem', 'EXT', 'CTX')); + + $record = $this->getRecord(Logger::WARNING, "A test warning message"); + $record['extra']['blarg'] = 'yep'; + $record['context']['from'] = 'logger'; + $handler->handle($record); + + $this->assertEquals('mysystem', $messagePublisher->lastMessage->getHost()); + $this->assertArrayHasKey('_EXTblarg', $messagePublisher->lastMessage->toArray()); + $this->assertArrayHasKey('_CTXfrom', $messagePublisher->lastMessage->toArray()); + } } From a497704d949ed19cea7b9a0be5b45597d0c2288d Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Fri, 20 Apr 2012 13:24:28 -0400 Subject: [PATCH 11/14] write method should be protected, and protected methods after public methods --- src/Monolog/Handler/GelfHandler.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Monolog/Handler/GelfHandler.php b/src/Monolog/Handler/GelfHandler.php index 2eec8fc1..7346029a 100644 --- a/src/Monolog/Handler/GelfHandler.php +++ b/src/Monolog/Handler/GelfHandler.php @@ -40,14 +40,6 @@ class GelfHandler extends AbstractProcessingHandler $this->publisher = $publisher; } - /** - * {@inheritDoc} - */ - protected function getDefaultFormatter() - { - return new GelfMessageFormatter(); - } - /** * {@inheritdoc} */ @@ -59,8 +51,16 @@ class GelfHandler extends AbstractProcessingHandler /** * {@inheritdoc} */ - public function write(array $record) + protected function write(array $record) { $this->publisher->publish($record['formatted']); } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new GelfMessageFormatter(); + } } From d95889a98d32a7f7cbfbb21ea5cadbe4aaf01eef Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Fri, 20 Apr 2012 13:25:38 -0400 Subject: [PATCH 12/14] code cleanups as suggested by @stof --- tests/Monolog/Formatter/GelfMessageFormatterTest.php | 8 ++++---- tests/Monolog/Handler/GelfHandlerTest.php | 5 ++--- tests/bootstrap.php | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/Monolog/Formatter/GelfMessageFormatterTest.php b/tests/Monolog/Formatter/GelfMessageFormatterTest.php index d03fc5c1..94092689 100644 --- a/tests/Monolog/Formatter/GelfMessageFormatterTest.php +++ b/tests/Monolog/Formatter/GelfMessageFormatterTest.php @@ -18,7 +18,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase /** * @covers Monolog\Formatter\GelfMessageFormatter::format */ - function testDefaultFormatter() + public function testDefaultFormatter() { $formatter = new GelfMessageFormatter(); $record = array( @@ -53,7 +53,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase /** * @covers Monolog\Formatter\GelfMessageFormatter::format */ - function testFormatWithFileAndLine() + public function testFormatWithFileAndLine() { $formatter = new GelfMessageFormatter(); $record = array( @@ -76,7 +76,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase /** * @covers Monolog\Formatter\GelfMessageFormatter::format */ - function testFormatWithContext() + public function testFormatWithContext() { $formatter = new GelfMessageFormatter(); $record = array( @@ -114,7 +114,7 @@ class GelfMessageFormatterTest extends \PHPUnit_Framework_TestCase /** * @covers Monolog\Formatter\GelfMessageFormatter::format */ - function testFormatWithExtra() + public function testFormatWithExtra() { $formatter = new GelfMessageFormatter(); $record = array( diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 5e438d46..a0af4830 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -30,9 +30,8 @@ class GelfHandlerTest extends TestCase { public function setUp() { - if (!class_exists("Gelf\MessagePublisher")) - { - $this->markTestSkipped("https://github.com/mlehner/gelf-php not installed"); + if (!class_exists("Gelf\MessagePublisher")) { + $this->markTestSkipped("mlehner/gelf-php not installed"); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index ea4bb20d..b5a19634 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -9,5 +9,5 @@ * file that was distributed with this source code. */ -require_once __DIR__ . "/../vendor/.composer/autoload.php"; +require_once __DIR__ . "/../vendor/autoload.php"; require_once __DIR__.'/Monolog/TestCase.php'; From 7ffd390c47528fbaabe9069fd3f89c2853c2cf57 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Fri, 20 Apr 2012 14:02:40 -0400 Subject: [PATCH 13/14] add composer commands to travis config --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index a8c90f29..735c285c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,8 @@ php: - 5.3 - 5.4 +before_script: + - wget -nc http://getcomposer.org/composer.phar + - php composer.phar install --dev + script: phpunit From 6507d1a61586b474eaa92aa6ca8c3e8d71c54f93 Mon Sep 17 00:00:00 2001 From: Matt Lehner Date: Fri, 20 Apr 2012 14:34:38 -0400 Subject: [PATCH 14/14] use installer script to install Composer --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 735c285c..eb350496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ php: - 5.4 before_script: - - wget -nc http://getcomposer.org/composer.phar + - curl -s http://getcomposer.org/installer | php - php composer.phar install --dev script: phpunit