Logger.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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;
  9. use UnexpectedValueException;
  10. /**
  11. * The `Logger` class provides a consistent, application-wide interface for configuring and writing
  12. * log messages. As with other subclasses of `Adaptable`, `Logger` can be configured with a series
  13. * of named configurations, each containing a log adapter to write to. `Logger` exposes a single
  14. * method, `write()`, which can write to one or more log adapters.
  15. *
  16. * When configuring adapters, you may specify one or more priorities for each, using the
  17. * `'priority'` key. This key can be a single priority level (string), or an array of multiple
  18. * levels. When a log message is written, all adapters that are configured to accept the priority
  19. * level with which the message was written will receive the message.
  20. *
  21. * {{{
  22. * Logger::config(array(
  23. * 'default' => array('adapter' => 'Syslog'),
  24. * 'badnews' => array(
  25. * 'adapter' => 'File',
  26. * 'priority' => array('emergency', 'alert', 'critical', 'error')
  27. * )
  28. * ));
  29. * }}}
  30. *
  31. * In the above configuration, all messages will be written to the system log (`syslogd`), but only
  32. * messages with the priority `error` or higher will be logged to a file. Messages can then be
  33. * written to the log(s) using the `write()` method:
  34. *
  35. * {{{ Logger::write('alert', 'This is an alert-level message that will be logged in 2 places'); }}}
  36. *
  37. * Messages can also be written using the log priority as a method name:
  38. *
  39. * {{{ Logger::alert('This is an alert-level message that will be logged in 2 places'); }}}
  40. *
  41. * This works identically to the above. The message priority levels which `Logger` supports are as
  42. * follows: `emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info` and `debug`.
  43. * Attempting to use any other priority level will raise an exception. See the list of available
  44. * adapters for more information on what adapters are available, and how to configure them.
  45. *
  46. * @see lithium\analysis\logger\adapter
  47. */
  48. class Logger extends \lithium\core\Adaptable {
  49. /**
  50. * Stores configurations for cache adapters.
  51. *
  52. * @var object `Collection` of logger configurations.
  53. */
  54. protected static $_configurations = array();
  55. /**
  56. * Libraries::locate() compatible path to adapters for this class.
  57. *
  58. * @see lithium\core\Libraries::locate()
  59. * @var string Dot-delimited path.
  60. */
  61. protected static $_adapters = 'adapter.analysis.logger';
  62. /**
  63. * An array of valid message priorities.
  64. *
  65. * @var array
  66. */
  67. protected static $_priorities = array(
  68. 'emergency' => 0,
  69. 'alert' => 1,
  70. 'critical' => 2,
  71. 'error' => 3,
  72. 'warning' => 4,
  73. 'notice' => 5,
  74. 'info' => 6,
  75. 'debug' => 7
  76. );
  77. /**
  78. * Writes a message to one or more log adapters, where the adapters that are written to are the
  79. * ones that respond to the given priority level.
  80. *
  81. * @param string $priority The priority of the log message to be written.
  82. * @param string $message The message to be written.
  83. * @param array $options An array of adapter-specific options that may be passed when writing
  84. * log messages. Some options are also handled by `Logger` itself:
  85. * - `'name'` _string_: This option can be specified if you wish to write to a
  86. * specific adapter configuration, instead of writing to the adapter(s) that
  87. * respond to the given priority.
  88. * @return boolean Returns `true` if all log writes succeeded, or `false` if _any or all_ writes
  89. * failed.
  90. * @throws UnexpectedValueException If the value of `$priority` is not a defined priority value,
  91. * an `UnexpectedValueException` will be thrown.
  92. * @filter
  93. */
  94. public static function write($priority, $message, array $options = array()) {
  95. $defaults = array('name' => null);
  96. $options += $defaults;
  97. $result = true;
  98. if (isset(self::$_configurations[$options['name']])) {
  99. $name = $options['name'];
  100. $methods = array($name => static::adapter($name)->write($priority, $message, $options));
  101. } elseif (!isset(static::$_priorities[$priority])) {
  102. $message = "Attempted to write log message with invalid priority `{$priority}`.";
  103. throw new UnexpectedValueException($message);
  104. } else {
  105. $methods = static::_configsByPriority($priority, $message, $options);
  106. }
  107. foreach ($methods as $name => $method) {
  108. $params = compact('priority', 'message', 'options');
  109. $config = static::_config($name);
  110. $result &= static::_filter(__FUNCTION__, $params, $method, $config['filters']);
  111. }
  112. return $methods ? $result : false;
  113. }
  114. /**
  115. * Acts as a proxy for the `write()` method, allowing log message priority names to be called as
  116. * methods, i.e.:
  117. * {{{
  118. * Logger::emergency('Something bad happened.');
  119. * // This is equivalent to Logger::write('emergency', 'Something bad happened')
  120. * }}}
  121. *
  122. * @param string $priority The name of the method called on the `Logger` class. This should map
  123. * to a log type.
  124. * @param array $params An array of parameters passed in the method.
  125. * @return boolean Returns `true` or `false`, depending on the success of the `write()` method.
  126. */
  127. public static function __callStatic($priority, $params) {
  128. $params += array(null, array());
  129. return static::write($priority, $params[0], $params[1]);
  130. }
  131. /**
  132. * Custom check to determine if our given magic methods can be responded to.
  133. *
  134. * @param string $method Method name.
  135. * @param bool $internal Interal call or not.
  136. * @return bool
  137. */
  138. public static function respondsTo($method, $internal = false) {
  139. return isset(static::$_priorities[$method]) || parent::respondsTo($method, $internal);
  140. }
  141. /**
  142. * This method is called automatically to initialize the default configuration of a log adapter,
  143. * such that the adapter defaults to accepting log messages of any priority (i.e. the
  144. * `'priority'` key is set to `true`).
  145. *
  146. * @param string $name The name of the logger configuration.
  147. * @param array $config The logger configuration as specified in application code.
  148. * @return array Returns an array of configuration data, merged with default values.
  149. */
  150. protected static function _initConfig($name, $config) {
  151. $defaults = array('priority' => true);
  152. return parent::_initConfig($name, $config) + $defaults;
  153. }
  154. /**
  155. * Gets the names of the adapter configurations that respond to a specific priority. The list
  156. * of adapter configurations returned will be used to write a message with the given priority.
  157. *
  158. * @param string $priority The priority level of a message to be written.
  159. * @param string $message The message to write to the adapter.
  160. * @param array $options Adapter-specific options.
  161. * @return array Returns an array of names of configurations which are set up to respond to the
  162. * message priority specified in `$priority`, or configured to respond to _all_ message
  163. * priorities.
  164. */
  165. protected static function _configsByPriority($priority, $message, array $options = array()) {
  166. $configs = array();
  167. $key = 'priority';
  168. foreach (array_keys(static::$_configurations) as $name) {
  169. $config = static::config($name);
  170. $nameMatch = ($config[$key] === true || $config[$key] === $priority);
  171. $arrayMatch = (is_array($config[$key]) && in_array($priority, $config[$key]));
  172. if ($nameMatch || $arrayMatch) {
  173. $method = static::adapter($name)->write($priority, $message, $options);
  174. $method ? $configs[$name] = $method : null;
  175. }
  176. }
  177. return $configs;
  178. }
  179. }
  180. ?>