PageRenderTime 243ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/ezcomponents/EventLog/src/log.php

http://hppg.googlecode.com/
PHP | 608 lines | 141 code | 35 blank | 432 comment | 6 complexity | 0aa89d3296f66d08a376fbb965be72f8 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * File containing the ezcLog class.
  4. *
  5. * @package EventLog
  6. * @version 1.4
  7. * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. */
  10. /**
  11. * The ezcLog class records log messages and audit trails to one or multiple
  12. * writers.
  13. *
  14. * Available writers are:
  15. * - {@link ezcLogUnixFileWriter Unix File} writer
  16. * - {@link ezcLogDatabaseWriter Database} writer
  17. *
  18. * Extra writers can be added by implementing the {@link ezcLogWriter} interface.
  19. *
  20. * Use the {@link getMapper()} method to get an instance of the ezcLogMapper.
  21. * The ezcLogMapper classes specifies incoming log messages with the {@link ezcLogFilter}.
  22. * Log messages that are accepted, match with the filter, are sent to the
  23. * {@link ezcLogWriter}.
  24. *
  25. * The following example demonstrates how all log messages, except for the
  26. * audit trailing and debug messages, are written to a file.
  27. * <code>
  28. * $filter = new ezcLogFilter();
  29. * $filter->severity = ezcLog::INFO | ezcLog::NOTICE | ezcLog::WARNING | ezcLog::ERROR | ezcLog::FATAL;
  30. *
  31. * $log = ezcLog::getInstance();
  32. * $log->getMapper()->appendRule( new ezcLogFilterRule( $filter, new ezcLogUnixFileWriter( "/tmp/logs/", "error.log" ), true ) );
  33. * </code>
  34. *
  35. * The log messages with the severity: INFO, NOTICE, WARNING, ERROR, and FATAL will
  36. * be written to the file: "/tmp/logs/error.log". See {@link ezcLogUnixFileWriter} for
  37. * the description of the file format.
  38. *
  39. * The following example will write the audit trails to the database:
  40. * <code>
  41. * $filter = new ezcLogFilter();
  42. * $filter->severity = ezcLog::SUCCESS_AUDIT | ezcLog::FAILED_AUDIT;
  43. *
  44. * $log = ezcLog::getInstance();
  45. * $log->getMapper()->appendRule( new ezcLogFilterRule( $filter, new ezcLogDatabaseWriter( "audits" ), true ) );
  46. * </code>
  47. *
  48. * The audit trails will be stored in the table "audits". See {@link ezcLogDatabaseWriter}
  49. * for creating the appropriate tables and setting up the database. See the {@link ezcLogFilter}
  50. * for more details.
  51. *
  52. * Use the {@link log()} method to log messages at the specified writers. This
  53. * method expects a:
  54. * - Message, contains a single log message.
  55. * - Severity, indicates the level of importance.
  56. * - Extra attributes (optional).
  57. *
  58. * Although the interpretation of the severity levels are up to the programmer,
  59. * the most common interpretations are:
  60. * - DEBUG: Records information about the progress in the program and references
  61. * source code functions. Knowledge of the source code is needed to interpret
  62. * this log message.
  63. * - INFO: Informative logging at a detailed level. This logging method produces a
  64. * high level of logging, which is unmanageable on a production environment.
  65. * Usually INFO logging is only enabled to help by analysing a problem.
  66. * - NOTICE: Informative logging at a lower detail level than INFO logging.
  67. * Only major stages are recorded and is useful to monitor a low volume system.
  68. * - WARNING: Something unexpected happened, but did not cause any loss of service.
  69. * - ERROR: An error occured, which may cause partial loss of service. Usually the
  70. * system can recover.
  71. * - FATAL: An serious error occured and the system is unlikely to recover.
  72. * - SUCCESS_AUDIT: Informative logging about a successful completion of work by
  73. * a module completed. Useful to trace system changes directly or indirectly
  74. * done by a user.
  75. * - FAILED_AUDIT: Informative logging about an action from a module
  76. * with a negative result. A failed login will most likely added to this severity.
  77. *
  78. * The next example logs a fatal error and has no extra attributes:
  79. * <code>
  80. * ezcLog::getInstance()->log( "Cannot open ini file: <$file>", ezcLog::FATAL );
  81. * </code>
  82. *
  83. * The log message will get by default the category and source: "default". The
  84. * default values can be modified by changing, respectively, the properties
  85. * $category and $source.
  86. *
  87. * An example of a Payment checker is as follows:
  88. * <code>
  89. * // The start of the Payment module.
  90. * $log = ezcLog::getInstance();
  91. * $log->source = "Payment checker"; // Change the default source.
  92. *
  93. * $log->log( "Checking the received amount", ezcLog::INFO, array( "shop" ) );
  94. *
  95. * if ( !$eZPay->receivedAmount() != $requiredAmount )
  96. * {
  97. * $log->log( "Received amount: <".$eZPay->receivedAmount()."> expected: <$requiredAmount>.",
  98. * ezcLog::DEBUG,
  99. * array( "category" => "shop", "file" => __FILE__, "line" => __LINE )
  100. * );
  101. *
  102. * $log->log( "Insufficient amount.",
  103. * ezcLog::FAILED_AUDIT,
  104. * array( "UserName" => getCurrentUser(), category => "Payment" )
  105. * )
  106. *
  107. * $log->log( "Rollback amount not implemented, cannot recover, ezcLog::FATAL );
  108. * exit();
  109. * }
  110. * </code>
  111. *
  112. * Sometimes information repeats for specific severities or categories. For example that
  113. * for the audit trails an username is required. Convenience methods like:
  114. * {@link setSeverityAttributes()} and {@link setSourceAttributes()} exist to append
  115. * information automatically to the log message.
  116. *
  117. * The ezcLog class provides a {@link trigger_error()} log handler: {@link ezcLog::logHandler()}.
  118. * Using the trigger_error method makes your code less Log package dependent and
  119. * produces less overhead when logging is disabled.
  120. *
  121. * See the {@link ezcLog::logHandler()} method for more information about how to set up the
  122. * trigger_error functionality.
  123. *
  124. * See the {@link ezcDebug} package for more detailed information about writing DEBUG
  125. * messages.
  126. *
  127. * @property string $source
  128. * Definition of the global location where the log message comes
  129. * from. Some examples are: module, source file, extension, etc. The
  130. * source depends also on the severity of the message. For DEBUG
  131. * messages is the source file more important whereas for a FATAL
  132. * error the module is sufficient.
  133. * @property string $category
  134. * Definition of the message group. Again the category is related to
  135. * the severity. The non audit trails can group the log messages
  136. * like: Database (or even the database types), Templates, etc. For
  137. * audit trails it makes much sense to categorize the actions. For
  138. * example: security, modified content, published content, shop, etc.
  139. *
  140. * @package EventLog
  141. * @version 1.4
  142. * @mainclass
  143. */
  144. class ezcLog
  145. {
  146. /**
  147. * Debug severity constant.
  148. */
  149. const DEBUG = 1;
  150. /**
  151. * Success audit severity constant.
  152. */
  153. const SUCCESS_AUDIT = 2;
  154. /**
  155. * Failed audit severity constant.
  156. */
  157. const FAILED_AUDIT = 4;
  158. /**
  159. * Info severity constant.
  160. */
  161. const INFO = 8;
  162. /**
  163. * Notice severity constant.
  164. */
  165. const NOTICE = 16;
  166. /**
  167. * Warning severity constant.
  168. */
  169. const WARNING = 32;
  170. /**
  171. * Error severity constant.
  172. */
  173. const ERROR = 64;
  174. /**
  175. * Fatal severity constant.
  176. */
  177. const FATAL = 128;
  178. /**
  179. * Holds the properties of this class.
  180. *
  181. * @var array(string=>mixed)
  182. */
  183. private $properties = array();
  184. /**
  185. * Contains the logic of mapping an incoming log message to the writer.
  186. *
  187. * @var ezcLogFilterSet
  188. */
  189. protected $writers;
  190. /**
  191. * Stores the attributes from the eventTypes and eventSources.
  192. *
  193. * $var ezcLogContext
  194. */
  195. protected $context;
  196. /**
  197. * Stores the instance of this class.
  198. *
  199. * @var ezcLog
  200. */
  201. private static $instance = null;
  202. /**
  203. * Stores the setting whether writer exceptions should be thrown.
  204. *
  205. * @var bool
  206. */
  207. private $throwWriterExceptions = true;
  208. /**
  209. * Constructs an empty ezcLog instance.
  210. *
  211. * This constructor is private as this class should be used as a
  212. * singleton. Use the getInstance() method instead to get an ezcLog instance.
  213. */
  214. private function __construct()
  215. {
  216. $this->reset();
  217. }
  218. /**
  219. * Returns the instance of the class.
  220. *
  221. * @return ezcLog
  222. */
  223. public static function getInstance()
  224. {
  225. if ( is_null( self::$instance ) )
  226. {
  227. self::$instance = new self();
  228. ezcBaseInit::fetchConfig( 'ezcInitLog', self::$instance );
  229. }
  230. return self::$instance;
  231. }
  232. /**
  233. * Sets the property $name to $value.
  234. *
  235. * @throws ezcBasePropertyNotFoundException
  236. * If the property $name does not exist
  237. * @param string $name
  238. * @param mixed $value
  239. * @ignore
  240. */
  241. public function __set( $name, $value )
  242. {
  243. switch ( $name )
  244. {
  245. case "source":
  246. case "category":
  247. $this->properties[$name] = $value;
  248. return;
  249. }
  250. throw new ezcBasePropertyNotFoundException( $name );
  251. }
  252. /**
  253. * Returns the property $name.
  254. *
  255. * @throws ezcBasePropertyNotFoundException
  256. * If the property $name does not exist
  257. * @param string $name
  258. * @return mixed
  259. * @ignore
  260. */
  261. public function __get( $name )
  262. {
  263. switch ( $name )
  264. {
  265. case "source":
  266. case "category":
  267. return $this->properties[$name];
  268. }
  269. throw new ezcBasePropertyNotFoundException( $name );
  270. }
  271. /**
  272. * Returns true if the property $name is set, otherwise false.
  273. *
  274. * @param string $name
  275. * @return bool
  276. * @ignore
  277. */
  278. public function __isset( $name )
  279. {
  280. switch ( $name )
  281. {
  282. case 'source':
  283. case 'category':
  284. return isset( $this->properties[$name] );
  285. default:
  286. return false;
  287. }
  288. }
  289. /**
  290. * Resets the log instance to its initial state.
  291. *
  292. * All sourceAttributes, severityAttributes, and writers will be removed.
  293. * The default source and category are also reset.
  294. */
  295. public function reset()
  296. {
  297. $this->writers = new ezcLogFilterSet();
  298. $this->context = new ezcLogContext();
  299. $this->setDefaults();
  300. }
  301. /**
  302. * Sets the given ezcLogMapper $mapper as the log message to writer map.
  303. *
  304. * By default the ezcLogFilterSet is the default writer map. The default
  305. * ezcLogMapper can be replaced with this method.
  306. *
  307. * @param ezcLogMapper $mapper
  308. */
  309. public function setMapper( ezcLogMapper $mapper )
  310. {
  311. $this->writers = $mapper;
  312. }
  313. /**
  314. * Returns an instance of the current ezcLogMapper.
  315. *
  316. * @return ezcLogMapper
  317. */
  318. public function getMapper()
  319. {
  320. return $this->writers;
  321. }
  322. /**
  323. * Sets the source and category defaults to "default".
  324. */
  325. protected function setDefaults()
  326. {
  327. $this->properties['source'] = "default";
  328. $this->properties['category'] = "default";
  329. }
  330. /**
  331. * Enables or disables writer exceptions with the boolean $enable.
  332. *
  333. * Typically you want to have exceptions enabled while developing your application
  334. * in order to catch potential problems. A live server however, should not throw
  335. * a deadly exception when a relatively unimportant debug message could not be written to
  336. * the log file. For these setups you can disable writer exceptions.
  337. *
  338. * @param bool $enable
  339. */
  340. public function throwWriterExceptions( $enable )
  341. {
  342. $this->throwWriterExceptions = $enable;
  343. }
  344. /**
  345. * Write the message $message with additional information to one or multiple log writers.
  346. *
  347. * The log message $message, severity $severity, and extra attributes $attributes are sent to
  348. * the writers that matches with the {@link ezcLogFilter}. The following parameters are
  349. * taken in the comparation with the ezcLogFilter:
  350. * - $severity: the severity of the log message.
  351. * - $attributes[ "source" ]: the source from where the log message comes.
  352. * - $attributes[ "category" ]: the category of the log message.
  353. *
  354. * See for more information about filter matching the classes {@link ezcLog} and
  355. * {@link ezcLogFilter}.
  356. *
  357. * The message $message describes what happened. The severity $severity is one of the ezcLog constants:
  358. * - DEBUG: Records information about the progress in the program and references
  359. * source code functions. Knowledge of the source code is needed to interpret
  360. * this log message.
  361. * - INFO: Informative logging at a detailed level. This logging method produces a
  362. * high level of logging, which is unmanageable on a production environment.
  363. * Usually INFO logging is only enabled to help by analysing a problem.
  364. * - NOTICE: Informative logging at a lower detail level than INFO logging.
  365. * Only major stages are recorded and is useful to monitor a low volume system.
  366. * - WARNING: Something unexpected happened, but did not cause any loss of service.
  367. * - ERROR: An error occured, which may cause partial loss of service. Usually the
  368. * system can recover.
  369. * - FATAL: An serious error occured and the system is unlikely to recover.
  370. * - SUCCESS_AUDIT: Informative logging about a successful completion of work by
  371. * a module completed. Useful to trace system changes directly or indirectly
  372. * done by a user.
  373. * - FAILED_AUDIT: Informative logging about an action from a module
  374. * with a negative result. A failed login will most likely added to this severity.
  375. *
  376. * The attributes array $attributes can have one or multiple attributes that will
  377. * be added to the log. If source and category are given, they will override the default
  378. * source or category given as property to this object. Further more it is up to the
  379. * application what to include in the log. It may be useful to add the
  380. * file and linenumber to the attributes array. Use the magic PHP constants: {@link __FILE__}
  381. * and {@link __LINE__} for this purpose. The next example adds an warning to the log.
  382. *
  383. * <code>
  384. * ezcLog::getInstance()->source = "templateEngine"; // Set the default source.
  385. * ezcLog::getInstance()->log( "ezcPersistentObject <$obj> does not exist.",
  386. * ezcLog::WARNING,
  387. * array( "category" => "Database", "line" => __LINE__, "file" => __FILE__, "code" => 123 )
  388. * );
  389. * </code>
  390. *
  391. * The methods {@link setSeverityAttributes()} and {@link setSourceAttributes()} can automatically
  392. * add attributes to log messages based on, respectively, the severity and source.
  393. *
  394. * See also {@link logHandler()} on how to use {@link trigger_error()} to write log messages.
  395. *
  396. * @throws ezcLogWriterException if {@link throwWriterExceptions} are enabled and a log entry
  397. * could not be written.
  398. *
  399. * @param string $message
  400. * @param int $severity One of the following severity constants:
  401. * DEBUG, SUCCES_AUDIT, FAIL_AUDIT, INFO, NOTICE, WARNING, ERROR, or FATAL.
  402. * @param array(string=>string) $attributes
  403. */
  404. public function log( $message, $severity, array $attributes = array() )
  405. {
  406. $source = ( isset( $attributes["source"] ) ? $attributes["source"] : $this->properties["source"] );
  407. $category = ( isset( $attributes["category"] ) ? $attributes["category"] : $this->properties["category"] );
  408. unset( $attributes["source"] );
  409. unset( $attributes["category"] );
  410. $attributes = array_merge( $this->context->getContext( $severity, $source ), $attributes );
  411. $writers = $this->writers->get( $severity, $source, $category );
  412. foreach ( $writers as $writer )
  413. {
  414. try
  415. {
  416. $writer->writeLogMessage( $message, $severity, $source, $category, $attributes );
  417. }
  418. catch ( ezcLogWriterException $e )
  419. {
  420. if ( $this->throwWriterExceptions )
  421. {
  422. throw $e;
  423. }
  424. }
  425. }
  426. }
  427. /**
  428. * Sets the attributes $attributes for a group of severities $severityMask.
  429. *
  430. * The severities are specified with a bit mask. These attributes will be
  431. * added to the log message when the log severity is the same as specified
  432. * here.
  433. *
  434. * Example:
  435. * <code>
  436. * ezcLog::getInstance()->setSeverityAttributes(
  437. * ezcLog::SUCCESS_AUDIT | ezcLog::FAILED_AUDIT
  438. * array( "username" => "Jan K. Doodle" )
  439. * );
  440. * </code>
  441. *
  442. * Every log message that has the severity SUCCESS_AUDIT or FAILED_AUDIT
  443. * includes the user name: "Jan K. Doodle".
  444. *
  445. * @param integer $severityMask Multiple severities are specified with a logic-or.
  446. * @param array(string=>string) $attributes
  447. */
  448. public function setSeverityAttributes( $severityMask, $attributes )
  449. {
  450. $this->context->setSeverityContext( $severityMask, $attributes );
  451. }
  452. /**
  453. * Sets the attributes $attributes for a group of sources $sources.
  454. *
  455. * The sources are specified in an array. These attributes will be added to the
  456. * log message when it matches with the given $sources.
  457. *
  458. * Example:
  459. * <code>
  460. * ezcLog::getInstance()->setSourceAttributes(
  461. * array( "Paynet", "Bibit", "Paypal" ),
  462. * array( "MerchantID" => $merchantID )
  463. * );
  464. * </code>
  465. *
  466. * Every log message that comes from the payment module: Paynet, Bibit, or Paypal
  467. * includes the Merchant ID.
  468. *
  469. * @param array(string) $sources
  470. * @param array(string=>string) $attributes
  471. */
  472. public function setSourceAttributes ( $sources, $attributes )
  473. {
  474. $this->context->setSourceContext( $sources, $attributes );
  475. }
  476. /**
  477. * This method can be set as error_handler to log using {@link trigger_error()}.
  478. *
  479. * This method can be assigned with the {@link set_error_handler()} to handle the
  480. * trigger_error calls. This method will get the log instance and forward the
  481. * message. But includes the following information:
  482. * - The file and linenumber are automatically added.
  483. * - Source and category can be 'encoded' in the message.
  484. *
  485. * The message format is as follows:
  486. * <pre>
  487. * [ source, category ] Message
  488. * </pre>
  489. *
  490. * When one name is given between the brackets, the category will be set and the message has a default source:
  491. * <pre>
  492. * [ category ] Message
  493. * </pre>
  494. *
  495. * Without any names between the brackets, the default category and source are used:
  496. * <pre>
  497. * Message
  498. * </pre>
  499. *
  500. * The following example creates manually an error handler and forwards the
  501. * ERROR, WARNING and NOTICE severities.
  502. * <code>
  503. * function myLogHandler($errno, $errstr, $errfile, $errline)
  504. * {
  505. * switch ($errno)
  506. * {
  507. * case E_USER_ERROR:
  508. * case E_USER_WARNING:
  509. * case E_USER_NOTICE:
  510. * if ( $loggingEnabled )
  511. * { // Forward the message to the log handler.
  512. * ezcLog::LogHandler( $errno, $errstr, $errfile, $errline );
  513. * }
  514. * break;
  515. *
  516. * default:
  517. * print( "$errstr in $errfile on line $errline\n" );
  518. * break;
  519. * }
  520. * }
  521. *
  522. * // Register myLogHandler
  523. * set_error_handler( "myLogHandler" );
  524. *
  525. * // Write an warning to the log.
  526. * trigger_error( "[paynet, transaction] Didn't get a callback from the Paynet service", E_USER_WARNING );
  527. *
  528. * // Add a notice.
  529. * trigger_error( "Getting paynet status information", E_USER_NOTICE );
  530. *
  531. * </code>
  532. *
  533. * Notice that the ezcLog component is not loaded at all when the logging is disabled.
  534. *
  535. * @param int $errno
  536. * @param int $errstr
  537. * @param string $errfile
  538. * @param int $errline
  539. */
  540. public static function logHandler( $errno, $errstr, $errfile, $errline )
  541. {
  542. $log = ezcLog::getInstance();
  543. $lm = new ezcLogMessage( $errstr, $errno, $log->source, $log->category );
  544. $log->log(
  545. $lm->message, $lm->severity,
  546. array( "source" => $lm->source, "category" => $lm->category, "file" => $errfile, "line" => $errline )
  547. );
  548. }
  549. /**
  550. * Translates the severity constant to a string and returns this.
  551. *
  552. * Null is returned when the severity constant is invalid.
  553. *
  554. * @param int $severity
  555. * @return string
  556. */
  557. public static function translateSeverityName( $severity )
  558. {
  559. switch ( $severity )
  560. {
  561. case self::DEBUG: return "Debug";
  562. case self::SUCCESS_AUDIT: return "Success audit";
  563. case self::FAILED_AUDIT: return "Failed audit";
  564. case self::INFO: return "Info";
  565. case self::NOTICE: return "Notice";
  566. case self::WARNING: return "Warning";
  567. case self::ERROR: return "Error";
  568. case self::FATAL: return "Fatal";
  569. default: return null;
  570. }
  571. }
  572. }
  573. ?>