| <?php |
| /** |
| * File containing the ezcLog class. |
| * |
| * @package EventLog |
| * @version //autogentag// |
| * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved. |
| * @license http://ez.no/licenses/new_bsd New BSD License |
| */ |
| |
| /** |
| * The ezcLog class records log messages and audit trails to one or multiple |
| * writers. |
| * |
| * Available writers are: |
| * - {@link ezcLogUnixFileWriter Unix File} writer |
| * - {@link ezcLogDatabaseWriter Database} writer |
| * |
| * Extra writers can be added by implementing the {@link ezcLogWriter} interface. |
| * |
| * Use the {@link getMapper()} method to get an instance of the ezcLogMapper. |
| * The ezcLogMapper classes specifies incoming log messages with the {@link ezcLogFilter}. |
| * Log messages that are accepted, match with the filter, are sent to the |
| * {@link ezcLogWriter}. |
| * |
| * The following example demonstrates how all log messages, except for the |
| * audit trailing and debug messages, are written to a file. |
| * <code> |
| * $filter = new ezcLogFilter(); |
| * $filter->severity = ezcLog::INFO | ezcLog::NOTICE | ezcLog::WARNING | ezcLog::ERROR | ezcLog::FATAL; |
| * |
| * $log = ezcLog::getInstance(); |
| * $log->getMapper()->appendRule( new ezcLogFilterRule( $filter, new ezcLogUnixFileWriter( "/tmp/logs/", "error.log" ), true ) ); |
| * </code> |
| * |
| * The log messages with the severity: INFO, NOTICE, WARNING, ERROR, and FATAL will |
| * be written to the file: "/tmp/logs/error.log". See {@link ezcLogUnixFileWriter} for |
| * the description of the file format. |
| * |
| * The following example will write the audit trails to the database: |
| * <code> |
| * $filter = new ezcLogFilter(); |
| * $filter->severity = ezcLog::SUCCESS_AUDIT | ezcLog::FAILED_AUDIT; |
| * |
| * $log = ezcLog::getInstance(); |
| * $log->getMapper()->appendRule( new ezcLogFilterRule( $filter, new ezcLogDatabaseWriter( "audits" ), true ) ); |
| * </code> |
| * |
| * The audit trails will be stored in the table "audits". See {@link ezcLogDatabaseWriter} |
| * for creating the appropriate tables and setting up the database. See the {@link ezcLogFilter} |
| * for more details. |
| * |
| * Use the {@link log()} method to log messages at the specified writers. This |
| * method expects a: |
| * - Message, contains a single log message. |
| * - Severity, indicates the level of importance. |
| * - Extra attributes (optional). |
| * |
| * Although the interpretation of the severity levels are up to the programmer, |
| * the most common interpretations are: |
| * - DEBUG: Records information about the progress in the program and references |
| * source code functions. Knowledge of the source code is needed to interpret |
| * this log message. |
| * - INFO: Informative logging at a detailed level. This logging method produces a |
| * high level of logging, which is unmanageable on a production environment. |
| * Usually INFO logging is only enabled to help by analysing a problem. |
| * - NOTICE: Informative logging at a lower detail level than INFO logging. |
| * Only major stages are recorded and is useful to monitor a low volume system. |
| * - WARNING: Something unexpected happened, but did not cause any loss of service. |
| * - ERROR: An error occured, which may cause partial loss of service. Usually the |
| * system can recover. |
| * - FATAL: An serious error occured and the system is unlikely to recover. |
| * - SUCCESS_AUDIT: Informative logging about a successful completion of work by |
| * a module completed. Useful to trace system changes directly or indirectly |
| * done by a user. |
| * - FAILED_AUDIT: Informative logging about an action from a module |
| * with a negative result. A failed login will most likely added to this severity. |
| * |
| * The next example logs a fatal error and has no extra attributes: |
| * <code> |
| * ezcLog::getInstance()->log( "Cannot open ini file: <$file>", ezcLog::FATAL ); |
| * </code> |
| * |
| * The log message will get by default the category and source: "default". The |
| * default values can be modified by changing, respectively, the properties |
| * $category and $source. |
| * |
| * An example of a Payment checker is as follows: |
| * <code> |
| * // The start of the Payment module. |
| * $log = ezcLog::getInstance(); |
| * $log->source = "Payment checker"; // Change the default source. |
| * |
| * $log->log( "Checking the received amount", ezcLog::INFO, array( "shop" ) ); |
| * |
| * if ( !$eZPay->receivedAmount() != $requiredAmount ) |
| * { |
| * $log->log( "Received amount: <".$eZPay->receivedAmount()."> expected: <$requiredAmount>.", |
| * ezcLog::DEBUG, |
| * array( "category" => "shop", "file" => __FILE__, "line" => __LINE ) |
| * ); |
| * |
| * $log->log( "Insufficient amount.", |
| * ezcLog::FAILED_AUDIT, |
| * array( "UserName" => getCurrentUser(), category => "Payment" ) |
| * ) |
| * |
| * $log->log( "Rollback amount not implemented, cannot recover, ezcLog::FATAL ); |
| * exit(); |
| * } |
| * </code> |
| * |
| * Sometimes information repeats for specific severities or categories. For example that |
| * for the audit trails an username is required. Convenience methods like: |
| * {@link setSeverityAttributes()} and {@link setSourceAttributes()} exist to append |
| * information automatically to the log message. |
| * |
| * The ezcLog class provides a {@link trigger_error()} log handler: {@link ezcLog::logHandler()}. |
| * Using the trigger_error method makes your code less Log package dependent and |
| * produces less overhead when logging is disabled. |
| * |
| * See the {@link ezcLog::logHandler()} method for more information about how to set up the |
| * trigger_error functionality. |
| * |
| * See the {@link ezcDebug} package for more detailed information about writing DEBUG |
| * messages. |
| * |
| * @property string $source |
| * Definition of the global location where the log message comes |
| * from. Some examples are: module, source file, extension, etc. The |
| * source depends also on the severity of the message. For DEBUG |
| * messages is the source file more important whereas for a FATAL |
| * error the module is sufficient. |
| * @property string $category |
| * Definition of the message group. Again the category is related to |
| * the severity. The non audit trails can group the log messages |
| * like: Database (or even the database types), Templates, etc. For |
| * audit trails it makes much sense to categorize the actions. For |
| * example: security, modified content, published content, shop, etc. |
| * |
| * @package EventLog |
| * @version //autogentag// |
| * @mainclass |
| */ |
| class ezcLog |
| { |
| /** |
| * Debug severity constant. |
| */ |
| const DEBUG = 1; |
| |
| /** |
| * Success audit severity constant. |
| */ |
| const SUCCESS_AUDIT = 2; |
| |
| /** |
| * Failed audit severity constant. |
| */ |
| const FAILED_AUDIT = 4; |
| |
| /** |
| * Info severity constant. |
| */ |
| const INFO = 8; |
| |
| /** |
| * Notice severity constant. |
| */ |
| const NOTICE = 16; |
| |
| /** |
| * Warning severity constant. |
| */ |
| const WARNING = 32; |
| |
| /** |
| * Error severity constant. |
| */ |
| const ERROR = 64; |
| |
| /** |
| * Fatal severity constant. |
| */ |
| const FATAL = 128; |
| |
| /** |
| * Holds the properties of this class. |
| * |
| * @var array(string=>mixed) |
| */ |
| private $properties = array(); |
| |
| /** |
| * Contains the logic of mapping an incoming log message to the writer. |
| * |
| * @var ezcLogFilterSet |
| */ |
| protected $writers; |
| |
| /** |
| * Stores the attributes from the eventTypes and eventSources. |
| * |
| * $var ezcLogContext |
| */ |
| protected $context; |
| |
| /** |
| * Stores the instance of this class. |
| * |
| * @var ezcLog |
| */ |
| private static $instance = null; |
| |
| /** |
| * Stores the setting whether writer exceptions should be thrown. |
| * |
| * @var bool |
| */ |
| private $throwWriterExceptions = true; |
| |
| /** |
| * Constructs an empty ezcLog instance. |
| * |
| * This constructor is private as this class should be used as a |
| * singleton. Use the getInstance() method instead to get an ezcLog instance. |
| */ |
| private function __construct() |
| { |
| $this->reset(); |
| } |
| |
| /** |
| * Returns the instance of the class. |
| * |
| * @return ezcLog |
| */ |
| public static function getInstance() |
| { |
| if ( is_null( self::$instance ) ) |
| { |
| self::$instance = new self(); |
| ezcBaseInit::fetchConfig( 'ezcInitLog', self::$instance ); |
| } |
| return self::$instance; |
| } |
| |
| /** |
| * Sets the property $name to $value. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * If the property $name does not exist |
| * @param string $name |
| * @param mixed $value |
| * @ignore |
| */ |
| public function __set( $name, $value ) |
| { |
| switch ( $name ) |
| { |
| case "source": |
| case "category": |
| $this->properties[$name] = $value; |
| return; |
| } |
| |
| throw new ezcBasePropertyNotFoundException( $name ); |
| } |
| |
| /** |
| * Returns the property $name. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * If the property $name does not exist |
| * @param string $name |
| * @return mixed |
| * @ignore |
| */ |
| public function __get( $name ) |
| { |
| switch ( $name ) |
| { |
| case "source": |
| case "category": |
| return $this->properties[$name]; |
| } |
| |
| throw new ezcBasePropertyNotFoundException( $name ); |
| } |
| |
| /** |
| * Returns true if the property $name is set, otherwise false. |
| * |
| * @param string $name |
| * @return bool |
| * @ignore |
| */ |
| public function __isset( $name ) |
| { |
| switch ( $name ) |
| { |
| case 'source': |
| case 'category': |
| return isset( $this->properties[$name] ); |
| |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Resets the log instance to its initial state. |
| * |
| * All sourceAttributes, severityAttributes, and writers will be removed. |
| * The default source and category are also reset. |
| */ |
| public function reset() |
| { |
| $this->writers = new ezcLogFilterSet(); |
| $this->context = new ezcLogContext(); |
| |
| $this->setDefaults(); |
| } |
| |
| /** |
| * Sets the given ezcLogMapper $mapper as the log message to writer map. |
| * |
| * By default the ezcLogFilterSet is the default writer map. The default |
| * ezcLogMapper can be replaced with this method. |
| * |
| * @param ezcLogMapper $mapper |
| */ |
| public function setMapper( ezcLogMapper $mapper ) |
| { |
| $this->writers = $mapper; |
| } |
| |
| /** |
| * Returns an instance of the current ezcLogMapper. |
| * |
| * @return ezcLogMapper |
| */ |
| public function getMapper() |
| { |
| return $this->writers; |
| } |
| |
| /** |
| * Sets the source and category defaults to "default". |
| */ |
| protected function setDefaults() |
| { |
| $this->properties['source'] = "default"; |
| $this->properties['category'] = "default"; |
| } |
| |
| /** |
| * Enables or disables writer exceptions with the boolean $enable. |
| * |
| * Typically you want to have exceptions enabled while developing your application |
| * in order to catch potential problems. A live server however, should not throw |
| * a deadly exception when a relatively unimportant debug message could not be written to |
| * the log file. For these setups you can disable writer exceptions. |
| * |
| * @param bool $enable |
| */ |
| public function throwWriterExceptions( $enable ) |
| { |
| $this->throwWriterExceptions = $enable; |
| } |
| |
| /** |
| * Write the message $message with additional information to one or multiple log writers. |
| * |
| * The log message $message, severity $severity, and extra attributes $attributes are sent to |
| * the writers that matches with the {@link ezcLogFilter}. The following parameters are |
| * taken in the comparation with the ezcLogFilter: |
| * - $severity: the severity of the log message. |
| * - $attributes[ "source" ]: the source from where the log message comes. |
| * - $attributes[ "category" ]: the category of the log message. |
| * |
| * See for more information about filter matching the classes {@link ezcLog} and |
| * {@link ezcLogFilter}. |
| * |
| * The message $message describes what happened. The severity $severity is one of the ezcLog constants: |
| * - DEBUG: Records information about the progress in the program and references |
| * source code functions. Knowledge of the source code is needed to interpret |
| * this log message. |
| * - INFO: Informative logging at a detailed level. This logging method produces a |
| * high level of logging, which is unmanageable on a production environment. |
| * Usually INFO logging is only enabled to help by analysing a problem. |
| * - NOTICE: Informative logging at a lower detail level than INFO logging. |
| * Only major stages are recorded and is useful to monitor a low volume system. |
| * - WARNING: Something unexpected happened, but did not cause any loss of service. |
| * - ERROR: An error occured, which may cause partial loss of service. Usually the |
| * system can recover. |
| * - FATAL: An serious error occured and the system is unlikely to recover. |
| * - SUCCESS_AUDIT: Informative logging about a successful completion of work by |
| * a module completed. Useful to trace system changes directly or indirectly |
| * done by a user. |
| * - FAILED_AUDIT: Informative logging about an action from a module |
| * with a negative result. A failed login will most likely added to this severity. |
| * |
| * The attributes array $attributes can have one or multiple attributes that will |
| * be added to the log. If source and category are given, they will override the default |
| * source or category given as property to this object. Further more it is up to the |
| * application what to include in the log. It may be useful to add the |
| * file and linenumber to the attributes array. Use the magic PHP constants: {@link __FILE__} |
| * and {@link __LINE__} for this purpose. The next example adds an warning to the log. |
| * |
| * <code> |
| * ezcLog::getInstance()->source = "templateEngine"; // Set the default source. |
| * ezcLog::getInstance()->log( "ezcPersistentObject <$obj> does not exist.", |
| * ezcLog::WARNING, |
| * array( "category" => "Database", "line" => __LINE__, "file" => __FILE__, "code" => 123 ) |
| * ); |
| * </code> |
| * |
| * The methods {@link setSeverityAttributes()} and {@link setSourceAttributes()} can automatically |
| * add attributes to log messages based on, respectively, the severity and source. |
| * |
| * See also {@link logHandler()} on how to use {@link trigger_error()} to write log messages. |
| * |
| * @throws ezcLogWriterException if {@link throwWriterExceptions} are enabled and a log entry |
| * could not be written. |
| * |
| * @param string $message |
| * @param int $severity One of the following severity constants: |
| * DEBUG, SUCCES_AUDIT, FAIL_AUDIT, INFO, NOTICE, WARNING, ERROR, or FATAL. |
| * @param array(string=>string) $attributes |
| */ |
| public function log( $message, $severity, array $attributes = array() ) |
| { |
| $source = ( isset( $attributes["source"] ) ? $attributes["source"] : $this->properties["source"] ); |
| $category = ( isset( $attributes["category"] ) ? $attributes["category"] : $this->properties["category"] ); |
| |
| unset( $attributes["source"] ); |
| unset( $attributes["category"] ); |
| |
| $attributes = array_merge( $this->context->getContext( $severity, $source ), $attributes ); |
| |
| $writers = $this->writers->get( $severity, $source, $category ); |
| foreach ( $writers as $writer ) |
| { |
| try |
| { |
| $writer->writeLogMessage( $message, $severity, $source, $category, $attributes ); |
| } |
| catch ( ezcLogWriterException $e ) |
| { |
| if ( $this->throwWriterExceptions ) |
| { |
| throw $e; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Sets the attributes $attributes for a group of severities $severityMask. |
| * |
| * The severities are specified with a bit mask. These attributes will be |
| * added to the log message when the log severity is the same as specified |
| * here. |
| * |
| * Example: |
| * <code> |
| * ezcLog::getInstance()->setSeverityAttributes( |
| * ezcLog::SUCCESS_AUDIT | ezcLog::FAILED_AUDIT |
| * array( "username" => "Jan K. Doodle" ) |
| * ); |
| * </code> |
| * |
| * Every log message that has the severity SUCCESS_AUDIT or FAILED_AUDIT |
| * includes the user name: "Jan K. Doodle". |
| * |
| * @param integer $severityMask Multiple severities are specified with a logic-or. |
| * @param array(string=>string) $attributes |
| */ |
| public function setSeverityAttributes( $severityMask, $attributes ) |
| { |
| $this->context->setSeverityContext( $severityMask, $attributes ); |
| } |
| |
| /** |
| * Sets the attributes $attributes for a group of sources $sources. |
| * |
| * The sources are specified in an array. These attributes will be added to the |
| * log message when it matches with the given $sources. |
| * |
| * Example: |
| * <code> |
| * ezcLog::getInstance()->setSourceAttributes( |
| * array( "Paynet", "Bibit", "Paypal" ), |
| * array( "MerchantID" => $merchantID ) |
| * ); |
| * </code> |
| * |
| * Every log message that comes from the payment module: Paynet, Bibit, or Paypal |
| * includes the Merchant ID. |
| * |
| * @param array(string) $sources |
| * @param array(string=>string) $attributes |
| */ |
| public function setSourceAttributes ( $sources, $attributes ) |
| { |
| $this->context->setSourceContext( $sources, $attributes ); |
| } |
| |
| /** |
| * This method can be set as error_handler to log using {@link trigger_error()}. |
| * |
| * This method can be assigned with the {@link set_error_handler()} to handle the |
| * trigger_error calls. This method will get the log instance and forward the |
| * message. But includes the following information: |
| * - The file and linenumber are automatically added. |
| * - Source and category can be 'encoded' in the message. |
| * |
| * The message format is as follows: |
| * <pre> |
| * [ source, category ] Message |
| * </pre> |
| * |
| * When one name is given between the brackets, the category will be set and the message has a default source: |
| * <pre> |
| * [ category ] Message |
| * </pre> |
| * |
| * Without any names between the brackets, the default category and source are used: |
| * <pre> |
| * Message |
| * </pre> |
| * |
| * The following example creates manually an error handler and forwards the |
| * ERROR, WARNING and NOTICE severities. |
| * <code> |
| * function myLogHandler($errno, $errstr, $errfile, $errline) |
| * { |
| * switch ($errno) |
| * { |
| * case E_USER_ERROR: |
| * case E_USER_WARNING: |
| * case E_USER_NOTICE: |
| * if ( $loggingEnabled ) |
| * { // Forward the message to the log handler. |
| * ezcLog::LogHandler( $errno, $errstr, $errfile, $errline ); |
| * } |
| * break; |
| * |
| * default: |
| * print( "$errstr in $errfile on line $errline\n" ); |
| * break; |
| * } |
| * } |
| * |
| * // Register myLogHandler |
| * set_error_handler( "myLogHandler" ); |
| * |
| * // Write an warning to the log. |
| * trigger_error( "[paynet, transaction] Didn't get a callback from the Paynet service", E_USER_WARNING ); |
| * |
| * // Add a notice. |
| * trigger_error( "Getting paynet status information", E_USER_NOTICE ); |
| * |
| * </code> |
| * |
| * Notice that the ezcLog component is not loaded at all when the logging is disabled. |
| * |
| * @param int $errno |
| * @param int $errstr |
| * @param string $errfile |
| * @param int $errline |
| */ |
| public static function logHandler( $errno, $errstr, $errfile, $errline ) |
| { |
| $log = ezcLog::getInstance(); |
| $lm = new ezcLogMessage( $errstr, $errno, $log->source, $log->category ); |
| $log->log( |
| $lm->message, $lm->severity, |
| array( "source" => $lm->source, "category" => $lm->category, "file" => $errfile, "line" => $errline ) |
| ); |
| } |
| |
| /** |
| * Translates the severity constant to a string and returns this. |
| * |
| * Null is returned when the severity constant is invalid. |
| * |
| * @param int $severity |
| * @return string |
| */ |
| public static function translateSeverityName( $severity ) |
| { |
| switch ( $severity ) |
| { |
| case self::DEBUG: return "Debug"; |
| case self::SUCCESS_AUDIT: return "Success audit"; |
| case self::FAILED_AUDIT: return "Failed audit"; |
| case self::INFO: return "Info"; |
| case self::NOTICE: return "Notice"; |
| case self::WARNING: return "Warning"; |
| case self::ERROR: return "Error"; |
| case self::FATAL: return "Fatal"; |
| default: return null; |
| } |
| } |
| } |
| ?> |