FirePHPHandler.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Monolog\Handler;
  11. use Monolog\Logger;
  12. use Monolog\Formatter\WildfireFormatter;
  13. /**
  14. * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
  15. *
  16. * @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
  17. */
  18. class FirePHPHandler extends AbstractProcessingHandler
  19. {
  20. /**
  21. * WildFire JSON header message format
  22. */
  23. const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
  24. /**
  25. * FirePHP structure for parsing messages & their presentation
  26. */
  27. const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
  28. /**
  29. * Must reference a "known" plugin, otherwise headers won't display in FirePHP
  30. */
  31. const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
  32. /**
  33. * Header prefix for Wildfire to recognize & parse headers
  34. */
  35. const HEADER_PREFIX = 'X-Wf';
  36. /**
  37. * Whether or not Wildfire vendor-specific headers have been generated & sent yet
  38. */
  39. protected static $initialized = false;
  40. /**
  41. * Shared static message index between potentially multiple handlers
  42. * @var int
  43. */
  44. protected static $messageIndex = 1;
  45. protected $sendHeaders = true;
  46. /**
  47. * Base header creation function used by init headers & record headers
  48. *
  49. * @param array $meta Wildfire Plugin, Protocol & Structure Indexes
  50. * @param string $message Log message
  51. * @return array Complete header string ready for the client as key and message as value
  52. */
  53. protected function createHeader(array $meta, $message)
  54. {
  55. $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
  56. return array($header => $message);
  57. }
  58. /**
  59. * Creates message header from record
  60. *
  61. * @see createHeader()
  62. * @param array $record
  63. * @return string
  64. */
  65. protected function createRecordHeader(array $record)
  66. {
  67. // Wildfire is extensible to support multiple protocols & plugins in a single request,
  68. // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
  69. return $this->createHeader(
  70. array(1, 1, 1, self::$messageIndex++),
  71. $record['formatted']
  72. );
  73. }
  74. /**
  75. * {@inheritDoc}
  76. */
  77. protected function getDefaultFormatter()
  78. {
  79. return new WildfireFormatter();
  80. }
  81. /**
  82. * Wildfire initialization headers to enable message parsing
  83. *
  84. * @see createHeader()
  85. * @see sendHeader()
  86. * @return array
  87. */
  88. protected function getInitHeaders()
  89. {
  90. // Initial payload consists of required headers for Wildfire
  91. return array_merge(
  92. $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
  93. $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
  94. $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
  95. );
  96. }
  97. /**
  98. * Send header string to the client
  99. *
  100. * @param string $header
  101. * @param string $content
  102. */
  103. protected function sendHeader($header, $content)
  104. {
  105. if (!headers_sent() && $this->sendHeaders) {
  106. header(sprintf('%s: %s', $header, $content));
  107. }
  108. }
  109. /**
  110. * Creates & sends header for a record, ensuring init headers have been sent prior
  111. *
  112. * @see sendHeader()
  113. * @see sendInitHeaders()
  114. * @param array $record
  115. */
  116. protected function write(array $record)
  117. {
  118. // WildFire-specific headers must be sent prior to any messages
  119. if (!self::$initialized) {
  120. $this->sendHeaders = $this->headersAccepted();
  121. foreach ($this->getInitHeaders() as $header => $content) {
  122. $this->sendHeader($header, $content);
  123. }
  124. self::$initialized = true;
  125. }
  126. $header = $this->createRecordHeader($record);
  127. $this->sendHeader(key($header), current($header));
  128. }
  129. /**
  130. * Verifies if the headers are accepted by the current user agent
  131. *
  132. * @return Boolean
  133. */
  134. protected function headersAccepted()
  135. {
  136. return !isset($_SERVER['HTTP_USER_AGENT']) || preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT']);
  137. }
  138. }