# Writers

A **_writer_** is an object that inherits from `Zend\Log\Writer\AbstractWriter`.
A writer's responsibility is to record log data to a storage backend.

## Writing to Streams

`Zend\Log\Writer\Stream` sends log data to a [PHP stream](http://www.php.net/stream).

To write log data to the PHP output buffer, use the `php://output` stream.
Alternately, you can send log data directly to a stream like `STDERR`
(`php://stderr`).

```php
$writer = new Zend\Log\Writer\Stream('php://output');
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

To write data to a file, use one of the [filesystem
streams](http://www.php.net/manual/en/wrappers.php#wrappers.file):

```php
$writer = new Zend\Log\Writer\Stream('/path/to/logfile');
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

By default, the stream opens in the append access mode ("a"). To open it with a
different access mode, the `Zend\Log\Writer\Stream` constructor accepts an
optional second parameter for the stream mode.

The constructor of `Zend\Log\Writer\Stream` also accepts an existing stream resource:

```php
$stream = @fopen('/path/to/logfile', 'a', false);
if (! $stream) {
    throw new Exception('Failed to open stream');
}

$writer = new Zend\Log\Writer\Stream($stream);
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

You cannot specify the stream access mode for existing stream resources. Doing
so causes a `Zend\Log\Exception` to be thrown.

You can use an array of options in place of the stream argument when
constructing a `Stream` instance; when doing so, the `stream` key is required:

```php
$writer = new Zend\Log\Writer\Stream([
    'stream' => 'php://output',
]);
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

The following table details all allowed constructor arguments and their
corresponding configuration options.

Constructor Argument | Option Name | Default | Description
-------------------- | ----------- | ------- | -----------
`$streamOrUrl` | stream | None; required | Stream resource or URL to open and log to
`$mode` | mode | "a" | Stream access mode to use when opening a stream URL
`$logSeparator` | log\_separator | `PHP_EOL` | Separator string to use between entries
`$filePermissions` | chmod | `null` | Permissions mode to use for stream resource; defaults to existing file/stream permissions

## Writing to Databases

`Zend\Log\Writer\Db` writes log information to a database table using
`Zend\Db\Adapter\Adapter`. The constructor of `Zend\Log\Writer\Db` receives a
`Zend\Db\Adapter\Adapter` instance, a table name, an optional mapping of event
data to database columns, and an optional string contains the character
separator for the log array:

```php
$dbconfig = [
    // Sqlite Configuration
    'driver' => 'Pdo',
    'dsn' => 'sqlite:' . __DIR__ . '/tmp/sqlite.db',
];
$db = new Zend\Db\Adapter\Adapter($dbconfig);

$writer = new Zend\Log\Writer\Db($db, 'log_table_name');
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

The example above writes a single row of log data to the database table named
`log_table_name` table. The database columns will be created according to the
event array generated by the `Zend\Log\Logger` instance.

If we specify the mapping of the events with the database columns, the log will
store only to the selected fields in the database:

```php
$dbconfig = [
    // Sqlite Configuration
    'driver' => 'Pdo',
    'dsn' => 'sqlite:' . __DIR__ . '/tmp/sqlite.db',
];
$db = new Zend\Db\Adapter\Adapter($dbconfig);

$mapping = [
    'timestamp' => 'date',
    'priority'  => 'type',
    'message'   => 'event',
];
$writer = new Zend\Log\Writer\Db($db, 'log_table_name', $mapping);
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

In this example, the writer stores only the log timestamp, priority, and
message, in the database fields date, type, and event, respectively.

`Zend\Log\Writer\Db` has a fourth optional parameter in the constructor. This
parameter is the character separator for array fields in the log event. For
instance, if we have a log event that contains the field `extra`, and that field
is an array, its elements will be translated as 'extra-field', where '-' is the
character separator (default), and 'field' is the subname of the specific field
found in the `extra` array.

## Writing to FirePHP

`Zend\Log\Writer\FirePHP` writes log information to the
[FirePHP](http://www.firephp.org/) Firefox extension. In order to use it, you
must install the FirePHPCore server library and the FirePHP browser extension.

To install the FirePHPCore library you can use
[Composer](https://getcomposer.org):

```bash
$ composer require firephp/firephp-core
```

## Writing to ChromePHP

`Zend\Log\Writer\ChromePHP` sends log data to the
[ChromePHP](https://chrome.google.com/webstore/detail/chrome-logger/noaneddfkdjfnfdakjjmocngnfkfehhd)
Chrome extension.

To use the ChromePHP writer, you will also need to include the [ChromePHP
Library](http://craig.is/writing/chrome-logger) library in your application. Use
[Composer](https://getcomposer.org) to do this:

```bash
$ composer require ccampbell/chromephp
```

## Writing to Mail

`Zend\Log\Writer\Mail` takes a configuration array or `Zend\Mail\Message`. Basic usage looks like

```php
$message = new \Zend\Mail\Message();
$message->setTo('email@example.com');

$writer = new \Zend\Log\Writer\Mail($message);
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to mail message
$logger->info('Informational message');
```

An email of the logged information will be sent via `sendmail` by default. You may also provide a `Zend\Mail\Transport`
during construction. For configuration options checkout the `Zend\Mail\Transport` documentation.

```php
$writer = new Zend\Log\Writer\Mail($mail, $transport);
```

`Zend\Log\Writer\mail` may also be constructed with a configuration array. The configuration array accepts the following
keys:

```php
[
    'subject_prepend_text' => '',
    'transport' => $transport
    'mail' => $mail,
    'filters' => [],
    'formatter' => []
]
```

And expects the following data:

Array Index | Accepted Values | Description
----------- | --------------- | -----------
`subject_prepend_text` | string | Mail message
`transport` | `Transport\TransportInterface` | Transport method
`mail` | `Zend\Mail\Message` | mail message
`mail` | `array` | `Zend\Mail\Message` factory array
`filters` | array, int, string, Zend\Log\Filter\FilterInterface | Log filter(s)
`formatter` | array, string, Zend\Log\Formatter\FormatterInterface | Log formatter(s)

Basic usage of the configuration array looks like:

```php
$transport = new \Zend\Mail\Transport\Smtp();
// TODO configure the SMTP transport

$message = new \Zend\Mail\Message();
// TODO configure the Mail message

$writer = new \Zend\Log\Writer\Mail([
    'subject_prepend_text' => 'Start of the subject',
    'transport' => $transport,
    'mail' => $mail,
    'filters' => [],
    'formatter' => []
]);

$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to mail message
$logger->info('Informational message');
```

To use the `Zend\Mail\Message` factory array construction will look like:

```php
$transport = new \Zend\Mail\Transport\Smtp();
// TODO configure the SMTP transport

$writer = new \Zend\Log\Writer\Mail([
    'subject_prepend_text' => 'Start of the subject',
    'transport' => $transport,
    'mail' => [
        'to' => 'email@example.com'
    ],
    'filters' => [],
    'formatter' => []
]);

$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to mail message
$logger->info('Informational message');
```

## Writing to MongoDB

In this example `Zend\Log\Writer\MongoDB` uses an array for construction. Available keys include:

```php
[
    'save_options' => [],
    'collection' => '',
    'database' => '',
    'mongo' => $mongo,
    'filters' => [],
    'formatter' => []
]
```

`collection`, `database`, and `mongo` are required. Each key accepts:

Array Index | Accepted Values | Description
----------- | --------------- | -----------
`save_options` | array | MongoDB driver options
`collection` | string | collection name
`database` | string | database name
`mongo` | `Mongo` or `MongoClient` | MongoDB connection object
`filters` | array, int, string, Zend\Log\Filter\FilterInterface | Log filter(s)
`formatter` | array, string, Zend\Log\Formatter\FormatterInterface | Log formatter(s)

And `Zend\Log\Writer\MongoDB` is used like this:

```php
$mongo = new MongoClient();

$writer = new \Zend\Log\Writer\MongoDB([
    'save_options' => [], // MongoDB Driver Options
    'collection' => 'collectionName',
    'database' => 'databaseName',
    'mongo' => $mongo,
    'filters' => [],
    'formatter' => []
]);

$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to Mongo DB
$logger->info('Informational message');
```

It may also be constructed by passing the arguments directly

```php
$mongo = new MongoClient();
$database = 'databaseName';
$collection = 'collectionName';
$saveOptions = [];

$writer = new \Zend\Log\Writer\MongoDB($mongo, $database, $collection, $saveOptions);
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to Mongo DB
$logger->info('Informational message');
```

## Writing to Syslog

`Zend\Log\Writer\Syslog` is a writer generates system log messages from the data it receives.

```php
$writer = new \Zend\Log\Writer\Syslog();
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to system log
$logger->info('Informational message');
```

The application name and syslog facility may be set

Array Index | Accepted Values | Description
----------- | --------------- | -----------
`application` | string | application name
`facility` | string | syslog facility (list of facilities)[http://php.net/openlog]
`filters` | array, int, string, Zend\Log\Filter\FilterInterface | Log filter(s)
`formatter` | array, string, Zend\Log\Formatter\FormatterInterface | Log formatter(s)

```php
$writer = new \Zend\Log\Writer\Syslog([
    'application' => '',
    'facility' => '',
    'filters' => [],
    'formatter' => []
]);

$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

$logger->info('Informational message');
```

## Writing to Zend Monitor

`Zend\Log\Writer\ZendMonitor` writes log data to the Zend Monitor on a Zend Server. If the web server is not a Zend
Server or Zend Monitor is not enabled it will fail silently.

```php
$writer = new \Zend\Log\Writer\ZendMonitor();
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to Zend Monitor
$logger->info('Informational message');
```

`Zend\Log\Writer\AbstractWriter` options are available.

Array Index | Accepted Values | Description
----------- | --------------- | -----------
`filters` | array, int, string, Zend\Log\Filter\FilterInterface | Log filter(s)
`formatter` | array, string, Zend\Log\Formatter\FormatterInterface | Log formatter(s)

```php
$writer = new \Zend\Log\Writer\ZendMonitor([
    'filters' => [],
    'formatter' => []
]);

$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);

// goes to Zend Monitor
$logger->info('Informational message');
```

## Stubbing Out the Writer

`Zend\Log\Writer\Noop` is a stub that does not write log data to anything; it is
useful for disabling logging or stubbing out logging during tests:

```php
$writer = new Zend\Log\Writer\Noop;
$logger = new Zend\Log\Logger();
$logger->addWriter($writer);

// goes nowhere
$logger->info('Informational message');
```

### Migration from 2.0-2.3 to 2.4+

Version 2.4 adds support for PHP 7. In PHP 7, `null` is a reserved keyword, which required renaming
the `Null` log writer. If you were using the `Null` writer directly previously, you will now receive
an `E_USER_DEPRECATED` notice on instantiation. Please update your code to refer to the `Noop` class
instead.

Users pulling their `Null` writer instance from the writer plugin manager receive a `Noop` instance
instead starting in 2.4.0.

## Testing with the Mock Writer

`Zend\Log\Writer\Mock` is a simple writer that records the raw data it receives
in an array that it exposes as a public property.

```php
$mock = new Zend\Log\Writer\Mock;
$logger = new Zend\Log\Logger();
$logger->addWriter($mock);

$logger->info('Informational message');

var_dump($mock->events[0]);

// Array
// (
//    [timestamp] => 2007-04-06T07:16:37-07:00
//    [message] => Informational message
//    [priority] => 6
//    [priorityName] => INFO
// )
```

To clear the events logged by the mock, reset the `$events` property:

```php
$mock->events = [];
```

## Compositing Writers

There is no composite writer object. However, a `Logger` instance can write to
any number of writers, effectively making it a composite logger.

To utilize this functionality, add writers via the `Logger::addWriter()` method:

```php
$writer1 = new Zend\Log\Writer\Stream('/path/to/first/logfile');
$writer2 = new Zend\Log\Writer\Stream('/path/to/second/logfile');

$logger = new Zend\Log\Logger();
$logger->addWriter($writer1);
$logger->addWriter($writer2);

// goes to both writers
$logger->info('Informational message');
```

You can also specify the priority number for each writer to change the order of writing. The
priority number is an integer number passed as second parameter in the
`addWriter()` method. Internally, `SplPriorityQueue` is used to manage writers,
which means that:

- higher integer values indicate higher priority (triggered earliest);
- lower integer values (including negative values) have lower priority
(triggered last).
