1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-08-04 12:17:35 +02:00

Merge branches 'mailhandler' and 'master' into mailhandler

This commit is contained in:
Gyula Sallai
2011-05-01 09:10:27 +02:00
6 changed files with 395 additions and 1 deletions

View File

@@ -32,12 +32,12 @@ Notable Features (non-exhaustive and incomplete)
------------------------------------------------
- _FingersCrossedHandler_: A very interesting handler. It takes a logger as parameter and will accumulate log records of all levels until a record exceeds the defined severity level. At which point it delivers all records, including those of lower severity, to the handler it wraps. This means that until an error actually happens you will not see anything in your logs, but when it happens you will have the full information, including debug and info records. This provides you with the info you need, only when you need it.
- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing inline `console` messages within [FireBug](http://getfirebug.com/).
Todo
----
- MailHandler
- FirePHPHandler
Requirements
------------

View File

@@ -0,0 +1,75 @@
<?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;
/**
* Serializes a log message according to Wildfire's header requirements
*
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
*/
class WildfireFormatter extends LineFormatter implements FormatterInterface
{
/**
* Similar to LineFormatter::SIMPLE_FORMAT, except without the "[%datetime%]"
*/
const SIMPLE_FORMAT = "%channel%: %message% %extra%";
/**
* Translates Monolog log levels to Wildfire levels.
*/
private $logLevels = array(
Logger::DEBUG => 'LOG',
Logger::INFO => 'INFO',
Logger::WARNING => 'WARN',
Logger::ERROR => 'ERROR',
);
/**
* {@inheritdoc}
*/
public function __construct($format = null, $dateFormat = null)
{
$this->format = $format ?: self::SIMPLE_FORMAT;
$this->dateFormat = $dateFormat ?: self::SIMPLE_DATE;
}
/**
* {@inheritdoc}
*/
public function format(Array $record)
{
// Format record according with LineFormatter
$formatted = parent::format($record);
// Create JSON object describing the appearance of the message in the console
$json = json_encode(array(
array(
'Type' => $this->logLevels[$record['level']],
'File' => '',
'Line' => '',
),
$formatted['message'],
));
// The message itself is a serialization of the above JSON object + it's length
$formatted['message'] = sprintf(
'%s|%s|',
strlen($json),
$json
);
return $formatted;
}
}

View File

@@ -0,0 +1,151 @@
<?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\Handler;
use Monolog\Logger;
use Monolog\Formatter\WildfireFormatter;
/**
* Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
*
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
*/
class FirePHPHandler extends AbstractHandler
{
/**
* WildFire JSON header message format
*/
const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
/**
* FirePHP structure for parsing messages & their presentation
*/
const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
/**
* Must reference a "known" plugin, otherwise headers won't display in FirePHP
*/
const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/ZendFramework/FirePHP/1.6.2';
/**
* Header prefix for Wildfire to recognize & parse headers
*/
const HEADER_PREFIX = 'X-Wf';
/**
* Whether or not Wildfire vendor-specific headers have been generated & sent yet
*/
protected static $initialized = false;
/**
* Shared static message index between potentially multiple handlers
* @var int
*/
protected static $messageIndex = 1;
/**
* @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
*/
public function __construct($level = Logger::DEBUG, $bubble = false)
{
$this->level = $level;
$this->bubble = $bubble;
}
/**
* Base header creation function used by init headers & record headers
*
* @param array $meta Wildfire Plugin, Protocol & Structure Indexes
* @param string $message Log message
* @return string Complete header string ready for the client
*/
protected function createHeader(array $meta, $message)
{
$header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
return array($header => $message);
}
/**
* Creates message header from record
*
* @see createHeader()
* @param array $record
*/
protected function createRecordHeader(array $record)
{
// Wildfire is extensible to support multiple protocols & plugins in a single request,
// but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
return $this->createHeader(
array(1, 1, 1, self::$messageIndex++),
$record['message']
);
}
protected function getDefaultFormatter()
{
return new WildfireFormatter();
}
/**
* Wildfire initialization headers to enable message parsing
*
* @see createHeader()
* @see sendHeader()
* @return Array
*/
protected function getInitHeaders()
{
// Initial payload consists of required headers for Wildfire
return array_merge(
$this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
$this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
$this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
);
}
/**
* Send header string to the client
*
* @param string $header
* @param string $content
*/
protected function sendHeader($header, $content)
{
if (!headers_sent()) {
header(sprintf('%s: %s', $header, $content));
}
}
/**
* Creates & sends header for a record, ensuring init headers have been sent prior
*
* @see sendHeader()
* @see sendInitHeaders()
* @param array $record
*/
protected function write(array $record)
{
// WildFire-specific headers must be sent prior to any messages
if (!self::$initialized) {
foreach ($this->getInitHeaders() as $header => $content) {
$this->sendHeader($header, $content);
}
self::$initialized = true;
}
$header = $this->createRecordHeader($record);
$this->sendHeader(key($header), current($header));
}
}

View File

@@ -0,0 +1,50 @@
<?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 WildfireFormatterTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider recordProvider
*/
public function testDefaultFormatIsLineFormatterWithoutNewLine($record)
{
$wildfire = new WildfireFormatter();
$record = $wildfire->format($record);
$this->assertEquals(
'70|[{"Type":"ERROR","File":"","Line":""},"meh: log extra(ip: 127.0.0.1)"]|',
$record['message']
);
}
public function recordProvider()
{
$record = array(
'level' => Logger::ERROR,
'level_name' => 'ERROR',
'channel' => 'meh',
'datetime' => new \DateTime,
'extra' => array('ip' => '127.0.0.1'),
'message' => 'log',
);
return array(
array($record),
);
}
}

View File

@@ -0,0 +1,30 @@
<?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.
*/
spl_autoload_register(function($class)
{
$file = __DIR__.'/../../../../src/'.strtr($class, '\\', '/').'.php';
if (file_exists($file)) {
require $file;
return true;
}
});
use Monolog\Logger;
use Monolog\Handler\FirePHPHandler;
$logger = new Logger('firephp');
$logger->pushHandler(new FirePHPHandler);
$logger->addDebug('Debug');
$logger->addInfo('Info');
$logger->addWarning('Warning');
$logger->addError('Error');

View File

@@ -0,0 +1,88 @@
<?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\Handler;
use Monolog\TestCase;
use Monolog\Logger;
class FirePHPHandlerTest extends TestCase
{
public function setUp()
{
TestFirePHPHandler::reset();
}
public function testHeaders()
{
$handler = new TestFirePHPHandler;
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/ZendFramework/FirePHP/1.6.2',
'X-Wf-1-1-1-1' => '50|[{"Type":"LOG","File":"","Line":""},"test: test "]|',
'X-Wf-1-1-1-2' => '51|[{"Type":"WARN","File":"","Line":""},"test: test "]|',
);
$this->assertEquals($expected, $handler->getHeaders());
}
public function testConcurrentHandlers()
{
$handler = new TestFirePHPHandler;
$handler->handle($this->getRecord(Logger::DEBUG));
$handler->handle($this->getRecord(Logger::WARNING));
$handler2 = new TestFirePHPHandler;
$handler2->handle($this->getRecord(Logger::DEBUG));
$handler2->handle($this->getRecord(Logger::WARNING));
$expected = array(
'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
'X-Wf-1-Structure-1' => 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1',
'X-Wf-1-Plugin-1' => 'http://meta.firephp.org/Wildfire/Plugin/ZendFramework/FirePHP/1.6.2',
'X-Wf-1-1-1-1' => '50|[{"Type":"LOG","File":"","Line":""},"test: test "]|',
'X-Wf-1-1-1-2' => '51|[{"Type":"WARN","File":"","Line":""},"test: test "]|',
);
$expected2 = array(
'X-Wf-1-1-1-3' => '50|[{"Type":"LOG","File":"","Line":""},"test: test "]|',
'X-Wf-1-1-1-4' => '51|[{"Type":"WARN","File":"","Line":""},"test: test "]|',
);
$this->assertEquals($expected, $handler->getHeaders());
$this->assertEquals($expected2, $handler2->getHeaders());
}
}
class TestFirePHPHandler extends FirePHPHandler
{
protected $headers = array();
public static function reset()
{
self::$initialized = false;
self::$messageIndex = 1;
}
protected function sendHeader($header, $content)
{
$this->headers[$header] = $content;
}
public function getHeaders()
{
return $this->headers;
}
}