================= The Log Package ================= -------------------- User Documentation -------------------- :Author: Jon Parise :Contact: jon@php.net :Date: $Date: 2003/11/15 07:49:49 $ :Revision: $Revision: 1.4 $ .. contents:: Contents .. section-numbering:: Using Log Handlers ================== The Log package is implemented as a framework that supports the notion of backend-specific log handlers. The base logging object (defined by the `Log class`_) is primarily an abstract interface to the currently configured handler. A wide variety of handlers are distributed with the Log package, and, should none of them fit your application's needs, it's easy to `write your own`__. .. _Log class: http://cvs.php.net/co.php/pear/Log/Log.php __ `Writing Custom Handlers`_ Creating a Log Object --------------------- There are three ways to create Log objects: - Using the ``Log::factory()`` method - Using the ``Log::singleton()`` method - Direct instantiation The Factory Method ~~~~~~~~~~~~~~~~~~ The ``Log::factory()`` method implements the `Factory Pattern`_. It allows for the parameterized construction of concrete Log instances at runtime. The first parameter to the ``Log::factory()`` method indicates the name of the concrete handler to create. The rest of the parameters will be passed on to the handler's constructor (see `Configuring a Handler`_ below). The new ``Log`` instance is returned by reference. :: require_once 'Log.php'; $console = &Log::factory('console', '', 'TEST'); $console->log('Logging to the console.'); $file = &Log::factory('file', 'out.log', 'TEST'); $file->log('Logging to out.log.'); .. _Factory Pattern: http://www.phppatterns.com/index.php/article/articleview/49/1/1/ The Singleton Method ~~~~~~~~~~~~~~~~~~~~ The ``Log::singleton()`` method implements the `Singleton Pattern`_. The singleton pattern ensures that only a single instance of a given log type and configuration is ever created. This has two benefits: first, it prevents duplicate ``Log`` instances from being constructed, and, second, it gives all of your code access to the same ``Log`` instance. The latter is especially important when logging to files because only a single file handler will need to be managed. The ``Log::singleton()`` method's parameters match the ``Log::factory()`` method. The new ``Log`` instance is returned by reference. :: require_once 'Log.php'; /* Same construction parameters */ $a = &Log::singleton('console', '', 'TEST'); $b = &Log::singleton('console', '', 'TEST'); if ($a === $b) { echo '$a and $b point to the same Log instance.' . "\n"; } /* Different construction parameters */ $c = &Log::singleton('console', '', 'TEST1'); $d = &Log::singleton('console', '', 'TEST2'); if ($c !== $d) { echo '$c and $d point to different Log instances.' . "\n"; } .. _Singleton Pattern: http://www.phppatterns.com/index.php/article/articleview/6/1/1/ Direct Instantiation ~~~~~~~~~~~~~~~~~~~~ It is also possible to directly instantiate concrete ``Log`` handler instances. However, this method is **not recommended** because it creates a tighter coupling between your application code and the Log package than is necessary. Use of `the factory method`_ or `the singleton method`_ is preferred. Configuring a Handler --------------------- A log handler's configuration is determined by the arguments used in its construction. Here's an overview of those parameters:: /* Using the factory method ... */ &Log::factory($handler, $name, $ident, $conf, $maxLevel); /* Using the singleton method ... */ &Log::singleton($handler, $name, $ident, $conf, $maxLevel); /* Using direct instantiation ... */ new Log_handler($name, $ident, $conf, $maxLevel); +---------------+-----------+-----------------------------------------------+ | Parameter | Type | Description | +===============+===========+===============================================+ | ``$handler`` | String | The type of Log handler to construct. This | | | | parameter is only available when `the factory | | | | method`_ or `the singleton method`_ are used. | +---------------+-----------+-----------------------------------------------+ | ``$name`` | String | The name of the log resource to which the | | | | events will be logged. The use of this value | | | | is determined by the handler's implementation.| | | | It defaults to an empty string. | +---------------+-----------+-----------------------------------------------+ | ``$ident`` | String | An identification string that will be included| | | | in all log events logged by this handler. | | | | This value defaults to an empty string and can| | | | be changed at runtime using the ``setIdent()``| | | | method. | +---------------+-----------+-----------------------------------------------+ | ``$conf`` | Array | Associative array of key-value pairs that are | | | | used to specify any handler-specific settings.| +---------------+-----------+-----------------------------------------------+ | ``$level`` | Integer | Log messages up to and including this level. | | | | This value defaults to ``PEAR_LOG_DEBUG``. | | | | See `Log Levels`_ and `Log Level Masks`_. | +---------------+-----------+-----------------------------------------------+ Logging an Event ---------------- Events are logged using the ``log()`` method:: $logger->log('Message', PEAR_LOG_NOTICE); The first argument contains the log event's message. Even though the event is always logged as a string, it is possible to pass an object to the ``log()`` method. If the object implements a ``getString()`` method, a ``toString()`` method or Zend Engine 2's special ``__toString()`` casting method, it will be used to determine the object's string representation. Otherwise, the `serialized`_ form of the object will be logged. The second, optional argument specifies the log event's priority. See the `Log Levels`_ table for the complete list of priorities. The default priority is PEAR_LOG_INFO. The ``log()`` method will return ``true`` if the event was successfully logged. "Shortcut" methods are also available for logging an event at a specific log level. See the `Log Levels`_ table for the complete list. .. _serialized: http://www.php.net/manual/en/function.serialize.php Log Levels ---------- This table is ordered by highest priority (``PEAR_LOG_EMERG``) to lowest priority (``PEAR_LOG_DEBUG``). +-----------------------+---------------+-----------------------------------+ | Level | Shortcut | Description | +=======================+===============+===================================+ | ``PEAR_LOG_EMERG`` | ``emerg()`` | System is unusable | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_ALERT`` | ``alert()`` | Immediate action required | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_CRIT`` | ``crit()`` | Critical conditions | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_ERR`` | ``err()`` | Error conditions | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_WARNING`` | ``warning()`` | Warning conditions | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_NOTICE`` | ``notice()`` | Normal but significant | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_INFO`` | ``info()`` | Informational | +-----------------------+---------------+-----------------------------------+ | ``PEAR_LOG_DEBUG`` | ``debug()`` | Debug-level messages | +-----------------------+---------------+-----------------------------------+ Log Level Masks --------------- Defining a log level mask allows you to include and/or exclude specific levels of events from being logged. The ``$level`` construction parameter (see `Configuring a Handler`_) uses this mechanism to exclude log events below a certain priority, and it's possible to define more complex masks once the Log object has been constructed. Each priority has a specific mask associated with it. To compute a priority's mask, use the static ``Log::MASK()`` method:: $mask = Log::MASK(PEAR_LOG_INFO); To compute the mask for all priorities up to a certain level, use the ``Log::UPTO()`` method:: $mask = Log::UPTO(PEAR_LOG_INFO); The apply the mask, use the ``setMask()`` method:: $logger->setMask($mask); Masks can be be combined using bitwise operations. To restrict logging to only those events marked as ``PEAR_LOG_NOTICE`` or ``PEAR_LOG_DEBUG``:: $mask = Log::MASK(PEAR_LOG_NOTICE) | Log::MASK(PEAR_LOG_DEBUG); $logger->setMask($mask); For convenience, two special masks are predefined: ``PEAR_LOG_NONE`` and ``PEAR_LOG_ALL``. ``PEAR_LOG_ALL`` is especially useful for exluding only specific priorities:: $mask = PEAR_LOG_ALL ^ Log::MASK(PEAR_LOG_NOTICE); $logger->setMask($mask); It is also possible to retrieve and modify a Log object's existing mask:: $mask = $logger->getMask() | Log::MASK(PEAR_LOG_INFO); $logger->setMask($mask); Standard Log Handlers ===================== The Console Handler ------------------- The Console handler outputs log events directly to the console. It supports output buffering and configurable string formats. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``stream`` | File | STDOUT_ | The output stream to use. | +-------------------+-----------+---------------+---------------------------+ | ``buffering`` | Boolean | False | Should the output be | | | | | buffered until shutdown? | +-------------------+-----------+---------------+---------------------------+ | ``lineFormat`` | String | ``%1$s %2$s | Log line format | | | | [%3$s] %4$s`` | specification. | +-------------------+-----------+---------------+---------------------------+ | ``timeFormat`` | String | ``%b %d | Time stamp format | | | | %H:%M:%S`` | (for strftime_). | +-------------------+-----------+---------------+---------------------------+ .. _STDOUT: http://www.php.net/wrappers.php .. _strftime: http://www.php.net/manual/en/function.strftime.php Example ~~~~~~~ :: $logger = &Log::singleton('console', '', 'ident'); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The Display Handler ------------------- The Display handler simply prints the log events back to the browser. It respects the ``error_prepend_string`` and ``error_append_string`` `error handling values`_ and is useful when `logging from standard error handlers`_. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``error_prepend`` | String | PHP INI value | This string will be | | | | | prepended to the log | | | | | output. | +-------------------+-----------+---------------+---------------------------+ | ``error_append`` | String | PHP INI value | This string will be | | | | | appended to the log | | | | | output. | +-------------------+-----------+---------------+---------------------------+ .. _error handling values: http://www.php.net/manual/en/ref.errorfunc.php Example ~~~~~~~ :: $conf = array('error_prepend' => '', 'error_append' => ''); $logger = &Log::singleton('display', '', '', $conf, PEAR_LOG_DEBUG); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The Error_Log Handler --------------------- The Error_Log handler sends log events to PHP's `error_log()`_ function. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``destination`` | String | '' `(empty)` | Optional destination value| | | | | for `error_log()`_. See | | | | | `Error_Log Types`_ for | | | | | more details. | +-------------------+-----------+---------------+---------------------------+ | ``extra_headers`` | String | '' `(empty)` | Additional headers to pass| | | | | to the `mail()`_ function | | | | | when the | | | | | ``PEAR_LOG_TYPE_MAIL`` | | | | | type is specified. | +-------------------+-----------+---------------+---------------------------+ Error_Log Types ~~~~~~~~~~~~~~~ All of the available log types are detailed in the `error_log()`_ section of the PHP manual. For your convenience, the Log package also defines the following constants that can be used for the ``$name`` handler construction parameter. +---------------------------+-----------------------------------------------+ | Constant | Description | +===========================+===============================================+ | ``PEAR_LOG_TYPE_SYSTEM`` | Log events are sent to PHP's system logger, | | | which uses the operating system's logging | | | mechanism or a file (depending on the value | | | of the `error_log configuration directive`_). | +---------------------------+-----------------------------------------------+ | ``PEAR_LOG_TYPE_MAIL`` | Log events are sent via email to the address | | | specified in the ``destination`` value. | +---------------------------+-----------------------------------------------+ | ``PEAR_LOG_TYPE_DEBUG`` | Log events are sent through PHP's debugging | | | connection. This will only work if | | | `remote debugging`_ has been enabled. The | | | ``destination`` value is used to specify the | | | host name or IP address of the target socket. | +---------------------------+-----------------------------------------------+ | ``PEAR_LOG_TYPE_FILE`` | Log events will be appended to the file named | | | by the ``destination`` value. | +---------------------------+-----------------------------------------------+ .. _error_log(): http://www.php.net/manual/en/function.error-log.php .. _mail(): http://www.php.net/manual/en/function.mail.php .. _error_log configuration directive: http://www.php.net/manual/en/ref.errorfunc.php#ini.error-log .. _remote debugging: http://www.php.net/manual/en/install.configure.php#install.configure.enable-debugger Example ~~~~~~~ :: $logger = &Log::singleton('error_log', PEAR_LOG_TYPE_SYSTEM, 'ident'); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The File Handler ---------------- The File handler writes log events to a text file using configurable string formats. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``append`` | Boolean | True | Should new log entries be | | | | | append to an existing log | | | | | file, or should the a new | | | | | log file overwrite an | | | | | existing one? | +-------------------+-----------+---------------+---------------------------+ | ``mode`` | Integer | 0644 | Octal representation of | | | | | the log file's permissions| | | | | mode. | +-------------------+-----------+---------------+---------------------------+ | ``eol`` | String | OS default | The end-on-line character | | | | | sequence. | +-------------------+-----------+---------------+---------------------------+ | ``lineFormat`` | String | ``%1$s %2$s | Log line format | | | | [%3$s] %4$s`` | specification. | +-------------------+-----------+---------------+---------------------------+ | ``timeFormat`` | String | ``%b %d | Time stamp format | | | | %H:%M:%S`` | (for strftime_). | +-------------------+-----------+---------------+---------------------------+ .. _strftime: http://www.php.net/manual/en/function.strftime.php Example ~~~~~~~ :: $conf = array('mode' => 0600, 'timeFormat' => '%X %x'); $logger = &Log::singleton('file', 'out.log', 'ident', $conf); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The Mail Handler ---------------- The Mail handler aggregates a session's log events and sends them in the body of an email message using PHP's `mail()`_ function. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``from`` | String | '' `(empty)` | Value for the message's | | | | | ``From:`` header. | +-------------------+-----------+---------------+---------------------------+ | ``subject`` | String | ``[Log_mail] | Value for the message's | | | | Log message`` | ``Subject:`` header. | +-------------------+-----------+---------------+---------------------------+ | ``preamble`` | String | `` `(empty)` | Preamble for the message. | +-------------------+-----------+---------------+---------------------------+ .. _mail(): http://www.php.net/manual/en/function.mail.php Example ~~~~~~~ :: $conf = array('subject' => 'Important Log Events'); $logger = &Log::singleton('mail', 'webmaster@example.com', 'ident', $conf); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The SQL (DB) Handler -------------------- The SQL handler sends log events to a database using `PEAR's DB abstraction layer`_. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``dsn`` | String | '' `(empty)` | A `Data Source Name`_. | +-------------------+-----------+---------------+---------------------------+ | ``db`` | Object | NULL | An existing `DB`_ object. | | | | | If specified, this object | | | | | will be used, and ``dsn`` | | | | | will be ignored. | +-------------------+-----------+---------------+---------------------------+ .. _DB: http://pear.php.net/package/DB .. _PEAR's DB abstraction layer: DB_ .. _Data Source Name: http://pear.php.net/manual/en/package.database.db.intro-dsn.php Examples ~~~~~~~~ Using a `Data Source Name`_ to create a new database connection:: $conf = array('dsn' => 'pgsql://jon@localhost+unix/logs'); $logger = &Log::singleton('sql', 'log_table', 'ident', $conf); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } Using an existing `DB`_ object:: require_once 'DB.php'; $db = &DB::connect('pgsql://jon@localhost+unix/logs'); $conf['db'] = $db; $logger = &Log::singleton('sql', 'log_table', 'ident', $conf); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The Syslog Handler ------------------ The Syslog handler sends log events to the system logging service (syslog on Unix-like environments or the Event Log on Windows systems). The events are sent using PHP's `syslog()`_ function. Facilities ~~~~~~~~~~ +-------------------+-------------------------------------------------------+ | Constant | Category Description | +===================+=======================================================+ | ``LOG_AUTH`` | Security / authorization messages; ``LOG_AUTHPRIV`` is| | | preferred on systems where it is defined. | +-------------------+-------------------------------------------------------+ | ``LOG_AUTHPRIV`` | Private security / authorization messages | +-------------------+-------------------------------------------------------+ | ``LOG_CRON`` | Clock daemon (``cron`` and ``at``) | +-------------------+-------------------------------------------------------+ | ``LOG_DAEMON`` | System daemon processes | +-------------------+-------------------------------------------------------+ | ``LOG_KERN`` | Kernel messages | +-------------------+-------------------------------------------------------+ | ``LOG_LOCAL0`` .. | Reserved for local use; **not** available under | | ``LOG_LOCAL7`` | Windows. | +-------------------+-------------------------------------------------------+ | ``LOG_LPR`` | Printer subsystem | +-------------------+-------------------------------------------------------+ | ``LOG_MAIL`` | Mail subsystem | +-------------------+-------------------------------------------------------+ | ``LOG_NEWS`` | USENET news subsystem | +-------------------+-------------------------------------------------------+ | ``LOG_SYSLOG`` | Internal syslog messages | +-------------------+-------------------------------------------------------+ | ``LOG_USER`` | Generic user-level messages | +-------------------+-------------------------------------------------------+ | ``LOG_UUCP`` | UUCP subsystem | +-------------------+-------------------------------------------------------+ .. _syslog(): http://www.php.net/manual/en/function.syslog.php Example ~~~~~~~ :: $logger = &Log::singleton('syslog', LOG_LOCAL0, 'ident'); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } The Window Handler ------------------ The Window handler sends log events to a separate browser window. The original idea for this handler was inspired by Craig Davis' Zend.com article entitled `"JavaScript Power PHP Debugging"`_. Configuration ~~~~~~~~~~~~~ +-------------------+-----------+---------------+---------------------------+ | Parameter | Type | Default | Description | +===================+===========+===============+===========================+ | ``title`` | String | ``Log Output | The title of the output | | | | Window`` | window. | +-------------------+-----------+---------------+---------------------------+ | ``colors`` | Array | `ROY G BIV`_ | Mapping of log priorities | | | | (high to low) | to colors. | +-------------------+-----------+---------------+---------------------------+ .. _"JavaScript Power PHP Debugging": http://www.zend.com/zend/tut/tutorial-DebugLib.php .. _ROY G BIV: http://www.cis.rit.edu/ Example ~~~~~~~ :: $conf = array('title' => 'Sample Log Output'); $logger = &Log::singleton('win', 'LogWindow', 'ident', $conf); for ($i = 0; $i < 10; $i++) { $logger->log("Log entry $i"); } Composite Handlers ================== It is often useful to log events to multiple handlers. The Log package provides a compositing system that marks this task trivial. Start by creating the individual log handlers:: $console = &Log::singleton('console', '', 'TEST'); $file = &Log::singleton('file', 'out.log', 'TEST'); Then, construct a composite handler and add the individual handlers as children of the composite:: $composite = &Log::singleton('composite'); $composite->addChild($console); $composite->addChild($file); The composite handler implements the standard ``Log`` interface so you can use it just like any of the other handlers:: $composite->log('This event will be logged to both handlers.'); Children can be removed from the composite when they're not longer needed:: $composite->removeChild($file); Log Observers ============= Log observers provide an implementation of the `observer pattern`_. In the content of the Log package, they provide a mechanism by which you can examine (i.e. observe) each event as it is logged. This allows the implementation of special behavior based on the contents of a log event. For example, the observer code could send an alert email if a log event contained the string ``PANIC``. Creating a log observer involves implementing a subclass of the ``Log_observer`` class. The subclass must override the base class's ``notify()`` method. This method is passed a hash containing the event's priority and event. The subclass's implementation is free to act upon this information in any way it likes. Log observers are attached to ``Log`` instances via the ``attach()`` method:: $observer = &Log_observer::factory('yourType'); $logger->attach($observer); Observers can be detached using the ``detach()`` method:: $logger->detach($observer); At this time, no concrete ``Log_observer`` implementations are distributed with the Log package. .. _observer pattern: http://phppatterns.com/index.php/article/articleview/27/1/1/ Logging From Standard Error Handlers ==================================== Logging PHP Errors ------------------ PHP's default error handler can be overridden using the `set_error_handler()`_ function. The custom error handling function can use a global Log instance to log the PHP errors. **Note:** Fatal PHP errors cannot be handled by a custom error handler at this time. :: function errorHandler($code, $message, $file, $line) { global $logger; /* Map the PHP error to a Log priority. */ switch ($code) { case E_WARNING: case E_USER_WARNING: $priority = PEAR_LOG_WARNING; break; case E_NOTICE: case E_USER_NOTICE: $priority = PEAR_LOG_NOTICE; break; case E_ERROR: case E_USER_ERROR: $priority = PEAR_LOG_ERR; break; default: $priotity = PEAR_LOG_INFO; } $logger->log($message . ' in ' . $file . ' at line ' . $line, $priority); } set_error_handler('errorHandler'); trigger_error('This is an information log message.', E_USER_NOTICE); .. _set_error_handler(): http://www.php.net/manual/en/function.set-error-handler.php Logging PEAR Errors ------------------- The Log package can be used with `PEAR::setErrorHandling()`_'s ``PEAR_ERROR_CALLBACK`` mechanism by writing an error handling function that uses a global Log instance. Here's an example:: function errorHandler($error) { global $logger; $message = $error->getMessage(); if (!empty($error->backtrace[1]['file'])) { $message .= ' (' . $error->backtrace[1]['file']; if (!empty($error->backtrace[1]['line'])) { $message .= ' at line ' . $error->backtrace[1]['line']; } $message .= ')'; } $logger->log($message, $error->code); } PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errorHandler'); PEAR::raiseError('This is an information log message.', PEAR_LOG_INFO); .. _PEAR::setErrorHandling(): http://pear.php.net/manual/en/core.pear.pear.seterrorhandling.php Writing Custom Handlers ======================= Writing New Handlers -------------------- TODO Extending Existing Handlers --------------------------- TODO .. vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=78: