mirror of
https://github.com/Seldaek/monolog.git
synced 2025-08-05 04:37:38 +02:00
Refactored FirePHPHandler a bit to support Closures & Methods to override how headers are sent.
(Defaults to PHP's `header` function)
This commit is contained in:
@@ -22,16 +22,60 @@ use Monolog\Formatter\WildfireFormatter;
|
||||
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';
|
||||
|
||||
/**
|
||||
* Whether or not Wildfire vendor-specific headers have been generated & sent yet
|
||||
*/
|
||||
private $initialized = false;
|
||||
|
||||
/**
|
||||
* Header prefix for Wildfire to recognize & parse headers
|
||||
*/
|
||||
private $prefix = 'X-Wf';
|
||||
|
||||
private $records = array();
|
||||
/**
|
||||
* Shared static message index between potentially multiple handlers
|
||||
*/
|
||||
private static $messageIndex = 1;
|
||||
|
||||
/**
|
||||
* Function, Method or Closure for sending the header
|
||||
*/
|
||||
private $writer = 'header';
|
||||
|
||||
/**
|
||||
* @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 mixed $writer Function, Method or Closure to use for sending headers
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG, $bubble = false, $writer = 'header')
|
||||
{
|
||||
$this->level = $level;
|
||||
$this->bubble = $bubble;
|
||||
$this->writer = $writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base header creation function used by init headers & record headers
|
||||
*
|
||||
* @var Array $meta Wildfire Plugin, Protocol & Structure Indexes
|
||||
* @var String $message Log message
|
||||
* @return String Complete header string ready for the client
|
||||
*/
|
||||
protected function createHeader(Array $meta, $message)
|
||||
{
|
||||
return sprintf(
|
||||
@@ -42,49 +86,20 @@ class FirePHPHandler extends AbstractHandler
|
||||
);
|
||||
}
|
||||
|
||||
protected function write(Array $record)
|
||||
{
|
||||
$this->records[] = $record;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
if (headers_sent()) {
|
||||
return false;
|
||||
} else {
|
||||
foreach ($this->getHeaders() as $header) {
|
||||
header($header);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
/**
|
||||
* Creates message header from record
|
||||
*
|
||||
* @see createHeader()
|
||||
* @var 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) for simplicity's sake.
|
||||
// (It does help understanding header formatting, though!)
|
||||
$protocolIndex = 1;
|
||||
$structureIndex = 1;
|
||||
$pluginIndex = 1;
|
||||
$messageIndex = 1;
|
||||
|
||||
// Initial payload consists of required headers for Wildfire
|
||||
$headers = array(
|
||||
$this->createHeader(array('Protocol', $protocolIndex), self::PROTOCOL_URI),
|
||||
$this->createHeader(array($protocolIndex, 'Structure', $structureIndex), self::STRUCTURE_URI),
|
||||
$this->createHeader(array($protocolIndex, 'Plugin', $pluginIndex), self::PLUGIN_URI),
|
||||
// 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']
|
||||
);
|
||||
|
||||
foreach ($this->records as $record) {
|
||||
$headers[] = $this->createHeader(
|
||||
array($protocolIndex, $structureIndex, $pluginIndex, $messageIndex++),
|
||||
$record['message']
|
||||
);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function getDefaultFormatter()
|
||||
@@ -92,4 +107,82 @@ class FirePHPHandler extends AbstractHandler
|
||||
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(
|
||||
$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
|
||||
*
|
||||
* @var String $header
|
||||
* @return Boolean False if headers are already sent, true if header are sent successfully
|
||||
*/
|
||||
protected function sendHeader($header)
|
||||
{
|
||||
if (headers_sent()) {
|
||||
return false;
|
||||
} else {
|
||||
$writer = $this->getWriter();
|
||||
|
||||
if ($writer instanceof \Closure) {
|
||||
$writer($header);
|
||||
} else {
|
||||
call_user_func($writer, $header);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates & sends header for a record, ensuring init headers have been sent prior
|
||||
*
|
||||
* @see sendHeader()
|
||||
* @see sendInitHeaders()
|
||||
* @var Array $record
|
||||
*/
|
||||
protected function write(Array $record)
|
||||
{
|
||||
// WildFire-specific headers must be sent prior to any messages
|
||||
if (! $this->initialized) {
|
||||
foreach ($this->getInitHeaders() as $header) {
|
||||
$this->sendHeader($header);
|
||||
}
|
||||
|
||||
$this->initialized = true;
|
||||
}
|
||||
|
||||
$header = $this->createRecordHeader($record);
|
||||
$this->sendHeader($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed Writer used for sending headers
|
||||
*/
|
||||
public function getWriter()
|
||||
{
|
||||
return $this->writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var mixed Function, Method or Closure to use for sending headers
|
||||
*/
|
||||
public function setWriter($writer)
|
||||
{
|
||||
$this->writer = $writer;
|
||||
}
|
||||
|
||||
}
|
@@ -20,24 +20,77 @@ class FirePHPHandlerTest extends TestCase
|
||||
/**
|
||||
* @dataProvider handlerProvider
|
||||
*/
|
||||
public function testCloseReturnsFalseWhenHeadersAlreadySent($handler)
|
||||
public function testCloseReturnsHeadersSent($handler)
|
||||
{
|
||||
$this->assertFalse($handler->close());
|
||||
}
|
||||
|
||||
public function testEmptyHandlerHasProtocolStructureAndPluginHeaders()
|
||||
{
|
||||
$handler = new FirePHPHandler();
|
||||
|
||||
$this->assertEquals(3, count($handler->getHeaders()));
|
||||
$this->assertEquals(headers_sent(), $handler->close());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider handlerProvider
|
||||
*/
|
||||
public function testHandlerHasWildFireAndRecordHeaders($handler)
|
||||
public function testDefaultWriterIsClosure($handler)
|
||||
{
|
||||
$this->assertEquals(7, count($handler->getHeaders()));
|
||||
$this->assertEquals('header', $handler->getWriter());
|
||||
}
|
||||
|
||||
public function testConstructWithWriter()
|
||||
{
|
||||
$writer = array($this, 'testWriter');
|
||||
|
||||
$handler = new FirePHPHandler(Logger::DEBUG, false, $writer);
|
||||
|
||||
$this->assertEquals($writer, $handler->getWriter());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider handlerProvider
|
||||
*/
|
||||
public function testWriterIsSettable($handler)
|
||||
{
|
||||
$writer = array($this, 'testWriter');
|
||||
$handler->setWriter($writer);
|
||||
|
||||
$this->assertNotEquals('header', $handler->getWriter());
|
||||
$this->assertEquals($writer, $handler->getWriter());
|
||||
}
|
||||
|
||||
public function testMethodWriter()
|
||||
{
|
||||
$handler = new FirePHPHandler;
|
||||
$handler->setWriter(array($this, 'writerForTestMethodWriter'));
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
}
|
||||
|
||||
public function writerForTestMethodWriter($header)
|
||||
{
|
||||
$valid = 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-5: 50|[{"Type":"LOG","File":"","Line":""},"test: test "]|',
|
||||
);
|
||||
|
||||
$this->assertTrue(in_array($header, $valid));
|
||||
}
|
||||
|
||||
public function testClosureWriter()
|
||||
{
|
||||
$headers = array();
|
||||
|
||||
$handler = new FirePHPHandler;
|
||||
$handler->setWriter(function($header) use (&$headers) {
|
||||
$headers[] = $header;
|
||||
});
|
||||
|
||||
$handler->handle($this->getRecord(Logger::DEBUG));
|
||||
|
||||
$this->assertEquals(
|
||||
'X-Wf-1-1-1-5: 50|[{"Type":"LOG","File":"","Line":""},"test: test "]|',
|
||||
end($headers)
|
||||
);
|
||||
|
||||
$this->assertEquals(4, count($headers), "There should be 3 init headers & 1 message header");
|
||||
}
|
||||
|
||||
public function handlerProvider()
|
||||
|
Reference in New Issue
Block a user