=================
 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' => '<font color="#ff0000"><tt>',
                  'error_append'  => '</tt></font>');
    $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: