diff options
Diffstat (limited to 'framework/Log/EventLog/log.php')
-rw-r--r-- | framework/Log/EventLog/log.php | 644 |
1 files changed, 644 insertions, 0 deletions
diff --git a/framework/Log/EventLog/log.php b/framework/Log/EventLog/log.php new file mode 100644 index 00000000..a99569dd --- /dev/null +++ b/framework/Log/EventLog/log.php @@ -0,0 +1,644 @@ +<?php +/** + * File containing the ezcLog class. + * + * @package EventLog + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 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 ezcLogWriterUnixFile Unix File} writer + * - {@link ezcLogWriterDatabase Database} writer + * + * Extra writers can be added by implementing the the {@link ezcLogWriter} interface. + * + * Use the {@link map()} method to attach an additional writer to the ezcLog + * class. This method filters 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->map( $filter, new ezcLogWriterUnixFile( "/tmp/logs/", "error.log" ) ); + * </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 ezcLogWriterUnixFile} 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->map( $filter, new ezcLogWriterDatabase( "audits" ) ); + * </code> + * + * The audit trails will be stored in the table "audits". See {@link ezcLogWriterDatabase} + * for creating the appropriate tables and setting up the database. + * + * It is also possible to exclude messages from going to a specific writer. + * This is done via the {@link unmap()} method. The following example shows + * how all messages, except for the DEBUG severity, are written to a file: + * <code> + * $fileWriter = ezcLogWriterUnixFile( "/tmp/logs/", "all.log" ); + * $filter = new ezcLogFilter(); + * $ezcLog::getInstance()->map( $filter, $fileWriter ); // All severities. + * + * $filter->severity = ezcLog::DEBUG; + * ezcLog::getInstance()->unmap( $filter, $fileWriter ); // Remove DEBUG severity. + * </code> + * + * 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. Their use is as follows: + * - 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. + * - 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. + * + * 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. + * + * @package EventLog + * @version //autogentag// + */ +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 ezcLogMap + */ + 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(); + } + return self::$instance; + } + + /** + * Sets the property $name to $value. + * + * @throws ezcBasePropertyNotFoundException if the property does not exist. + * @param string $name + * @param mixed $value + * @return void + */ + 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 does not exist. + * @param string $name + * @return mixed + */ + public function __get( $name ) + { + switch ( $name ) + { + case "source": + case "category": + return $this->properties[$name]; + } + + throw new ezcBasePropertyNotFoundException( $name ); + } + + /** + * Resets the log instance to its initial state. + * + * All sourceAttributes, severityAttributes, and writers will be removed. + * The default source and category are also reset. + * + * @return void + */ + public function reset() + { + $this->writers = new ezcLogMap(); + $this->context = new ezcLogContext(); + + $this->setDefaults(); + } + + /** + * Sets the source and category defaults to "default". + * + * @return void + */ + protected function setDefaults() + { + $this->source = "default"; + $this->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 + * @return void + */ + 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 + * @return void + */ + public function log( $message, $severity, $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"] ); + + $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; + } + } + } + } + + /** + * Attaches the writer $writer with the filter $logFilter to this ezcLog. + * + * The log filter $logFilter describes which severities, categories, and + * sources are accepted by the writer $writer. Those messages that + * match are send to the writer. + * + * Multiple logFilters with their writer can be attached to the ezcLog class. + * Every log message will be sent to the writer for which the log filter matches. + * + * Available writers are: + * - {@link ezcLogWriterUnixFile Unix File} writer + * - {@link ezcLogWriterDatabase Database} writer + * + * Extra writers can be added by implementing the the {@link ezcLogWriter} interface. + * + * The following example maps the Unix file writer to all the log messages that + * are from the category "template", source "content_module" and severities + * WARNING, ERROR, or FATAL. + * <code> + * $f = new ezclogFilter(); + * $f->severity = ezcLog::WARNING | ezcLog::ERROR | ezcLog::FATAL; + * $f->source = "template"; + * $f->category = "content_module"; + * + * $w = new ezcLogWriterUnixFile("/tmp/logs/content_module/", "template.log" ); + * + * $ezcLog::getInstance()->map( $f, $w ); + * </code> + * + * See also {@link unmap()} + * + * @param ezcLogFilter $logFilter + * @param ezcLogWriter $writer + * @return void + */ + public function map( ezcLogFilter $logFilter, ezcLogWriter $writer ) + { + $this->writers->map( $logFilter->severity, $logFilter->source, $logFilter->category, $writer ); + } + + /** + * Detaches the writer $writer for specific log messages, specified by the log filter $logFilter. + * + * The log filter $logFilter describes which severities, categories, and + * sources are no longer accepted by the writer $writer. + * + * See the {@link map()} method for information about attaching a filter. + * + * The following example shows how to log all messages, except the debug message: + * <code> + * $fileWriter = ezcLogWriterUnixFile( "/tmp/logs/", "all.log" ); + * $filter = new ezcLogFilter(); + * $ezcLog::getInstance()->map( $filter, $fileWriter ); // All severities. + * + * $filter->severity = ezcLog::DEBUG; + * ezcLog::getInstance()->unmap( $filter, $fileWriter ); // Remove DEBUG severity. + * </code> + * + * See also {@link map()} + * + * @param ezcLogFilter $logFilter + * @param ezcLogWriter $writer + * @return void + */ + public function unmap( ezcLogFilter $logFilter, ezcLogWriter $writer ) + { + $this->writers->unmap( $logFilter->severity, $logFilter->source, $logFilter->category, $writer ); + } + + /** + * 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 + * @return void + */ + 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 + * @return void + */ + 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> + * public 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 $erstr + * @param string $errfile + * @param int $errline + * @return void + */ + 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; + } + } +} +?> |