FirePhp.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\analysis\logger\adapter;
  9. /**
  10. * The `FirePhp` log adapter allows you to log messages to [ FirePHP](http://www.firephp.org/).
  11. *
  12. * This allows you to inspect native PHP values and objects inside the FireBug console.
  13. *
  14. * Because this adapter interacts directly with the `Response` object, some additional code is
  15. * required to use it. The simplest way to achieve this is to add a filter to the `Dispatcher`. For
  16. * example, the following can be placed in a bootstrap file:
  17. *
  18. * {{{
  19. * use lithium\action\Dispatcher;
  20. * use lithium\analysis\Logger;
  21. *
  22. * Logger::config(array(
  23. * 'default' => array('adapter' => 'FirePhp')
  24. * ));
  25. *
  26. * Dispatcher::applyFilter('_call', function($self, $params, $chain) {
  27. * if (isset($params['callable']->response)) {
  28. * Logger::adapter('default')->bind($params['callable']->response);
  29. * }
  30. * return $chain->next($self, $params, $chain);
  31. * });
  32. * }}}
  33. *
  34. * This will cause the message and other debug settings added to the header of the
  35. * response, where FirePHP is able to locate and print it accordingly. As this adapter
  36. * implements the protocol specification directly, you don't need another vendor library to
  37. * use it.
  38. *
  39. * Now, in you can use the logger in your application code (like controllers, views and models).
  40. *
  41. * {{{
  42. * class PagesController extends \lithium\action\Controller {
  43. * public function view() {
  44. * //...
  45. * Logger::error("Something bad happened!");
  46. * //...
  47. * }
  48. * }
  49. * }}}
  50. *
  51. * Because this adapter also has a queue implemented, it is possible to log messages even when the
  52. * `Response` object is not yet generated. When it gets generated (and bound), all queued messages
  53. * get flushed instantly.
  54. *
  55. * Because FirePHP is not a conventional logging destination like a file or a database, you can
  56. * pass everything (except resources) to the logger and inspect it further in FirePHP. In fact,
  57. * every message that is passed will be encoded via `json_encode()`, so check out this built-in
  58. * method for more information on how your message will be encoded.
  59. *
  60. * {{{
  61. * Logger::debug(array('debug' => 'me'));
  62. * Logger::debug(new \lithium\action\Response());
  63. * }}}
  64. *
  65. * @see lithium\action\Response
  66. * @see lithium\net\http\Message::headers()
  67. * @link http://www.firephp.org/ FirePHP
  68. * @link http://www.firephp.org/Wiki/Reference/Protocol FirePHP Protocol Reference
  69. * @link http://php.net/manual/en/function.json-encode.php PHP Manual: `json_encode()`
  70. */
  71. class FirePhp extends \lithium\core\Object {
  72. /**
  73. * These headers are specified by FirePHP and get added as headers to the response.
  74. *
  75. * @var array
  76. */
  77. protected $_headers = array(
  78. 'X-Wf-Protocol-1' => 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2',
  79. 'X-Wf-1-Plugin-1' =>
  80. 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3',
  81. 'X-Wf-1-Structure-1' =>
  82. 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'
  83. );
  84. /**
  85. * This is a mapping table that maps Lithium log levels to FirePHP log levels as they
  86. * do not correlate directly and FirePHP only accepts a distinct set.
  87. *
  88. * @var array
  89. */
  90. protected $_levels = array(
  91. 'emergency' => 'ERROR',
  92. 'alert' => 'ERROR',
  93. 'critical' => 'ERROR',
  94. 'error' => 'ERROR',
  95. 'warning' => 'WARN',
  96. 'notice' => 'INFO',
  97. 'info' => 'INFO',
  98. 'debug' => 'LOG'
  99. );
  100. /**
  101. * This self-incrementing counter allows the user to log more than one message per request.
  102. *
  103. * @var integer
  104. */
  105. protected $_counter = 1;
  106. /**
  107. * Holds the response object where the headers will be inserted.
  108. */
  109. protected $_response = null;
  110. /**
  111. * Contains messages that have been written to the log before the bind() call.
  112. */
  113. protected $_queue = array();
  114. /**
  115. * Binds the response object to the logger and sets the required Wildfire
  116. * protocol headers.
  117. *
  118. * @param object $response An instance of a response object (usually `lithium\action\Response`)
  119. * with HTTP request information.
  120. * @return void
  121. */
  122. public function bind($response) {
  123. $this->_response = $response;
  124. $this->_response->headers += $this->_headers;
  125. foreach ($this->_queue as $message) {
  126. $this->_write($message);
  127. }
  128. }
  129. /**
  130. * Appends a log message to the response header for FirePHP.
  131. *
  132. * @param string $priority Represents the message priority.
  133. * @param string $message Contains the actual message to store.
  134. * @return boolean Always returns `true`. Note that in order for message-writing to take effect,
  135. * the adapter must be bound to the `Response` object instance associated with
  136. * the current request. See the `bind()` method.
  137. */
  138. public function write($priority, $message) {
  139. $_self =& $this;
  140. return function($self, $params) use (&$_self) {
  141. $priority = $params['priority'];
  142. $message = $params['message'];
  143. $message = $_self->invokeMethod('_format', array($priority, $message));
  144. $_self->invokeMethod('_write', array($message));
  145. return true;
  146. };
  147. }
  148. /**
  149. * Heper method that writes the message to the header of a bound `Response` object. If no
  150. * `Response` object is bound when this method is called, it is stored in a message queue.
  151. *
  152. * @see lithium\analysis\logger\adapter\FirePhp::_format()
  153. * @param array $message A message containing the key and the content to store.
  154. * @return void
  155. */
  156. protected function _write($message) {
  157. if (!$this->_response) {
  158. return $this->_queue[] = $message;
  159. }
  160. $this->_response->headers[$message['key']] = $message['content'];
  161. }
  162. /**
  163. * Generates a string representation of the type and message, suitable for FirePHP.
  164. *
  165. * @param string $type Represents the message priority.
  166. * @param string $message Contains the actual message to store.
  167. * @return array Returns the encoded string representations of the priority and message, in the
  168. * `'key'` and `'content'` keys, respectively.
  169. */
  170. protected function _format($type, $message) {
  171. $key = 'X-Wf-1-1-1-' . $this->_counter++;
  172. $content = array(array('Type' => $this->_levels[$type]), $message);
  173. $content = json_encode($content);
  174. $content = strlen($content) . '|' . $content . '|';
  175. return compact('key', 'content');
  176. }
  177. }
  178. ?>