103 |
- |
1 |
# Using Monolog
|
|
|
2 |
|
|
|
3 |
- [Installation](#installation)
|
|
|
4 |
- [Core Concepts](#core-concepts)
|
|
|
5 |
- [Log Levels](#log-levels)
|
|
|
6 |
- [Configuring a logger](#configuring-a-logger)
|
|
|
7 |
- [Adding extra data in the records](#adding-extra-data-in-the-records)
|
|
|
8 |
- [Leveraging channels](#leveraging-channels)
|
|
|
9 |
- [Customizing the log format](#customizing-the-log-format)
|
|
|
10 |
|
|
|
11 |
## Installation
|
|
|
12 |
|
|
|
13 |
Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog))
|
|
|
14 |
and as such installable via [Composer](http://getcomposer.org/).
|
|
|
15 |
|
|
|
16 |
```bash
|
|
|
17 |
composer require monolog/monolog
|
|
|
18 |
```
|
|
|
19 |
|
|
|
20 |
If you do not use Composer, you can grab the code from GitHub, and use any
|
|
|
21 |
PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader))
|
|
|
22 |
to load Monolog classes.
|
|
|
23 |
|
|
|
24 |
## Core Concepts
|
|
|
25 |
|
|
|
26 |
Every `Logger` instance has a channel (name) and a stack of handlers. Whenever
|
|
|
27 |
you add a record to the logger, it traverses the handler stack. Each handler
|
|
|
28 |
decides whether it fully handled the record, and if so, the propagation of the
|
|
|
29 |
record ends there.
|
|
|
30 |
|
|
|
31 |
This allows for flexible logging setups, for example having a `StreamHandler` at
|
|
|
32 |
the bottom of the stack that will log anything to disk, and on top of that add
|
|
|
33 |
a `MailHandler` that will send emails only when an error message is logged.
|
|
|
34 |
Handlers also have a `$bubble` property which defines whether they block the
|
|
|
35 |
record or not if they handled it. In this example, setting the `MailHandler`'s
|
|
|
36 |
`$bubble` argument to false means that records handled by the `MailHandler` will
|
|
|
37 |
not propagate to the `StreamHandler` anymore.
|
|
|
38 |
|
|
|
39 |
You can create many `Logger`s, each defining a channel (e.g.: db, request,
|
|
|
40 |
router, ..) and each of them combining various handlers, which can be shared
|
|
|
41 |
or not. The channel is reflected in the logs and allows you to easily see or
|
|
|
42 |
filter records.
|
|
|
43 |
|
|
|
44 |
Each Handler also has a Formatter, a default one with settings that make sense
|
|
|
45 |
will be created if you don't set one. The formatters normalize and format
|
|
|
46 |
incoming records so that they can be used by the handlers to output useful
|
|
|
47 |
information.
|
|
|
48 |
|
|
|
49 |
Custom severity levels are not available. Only the eight
|
|
|
50 |
[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice,
|
|
|
51 |
warning, error, critical, alert, emergency) are present for basic filtering
|
|
|
52 |
purposes, but for sorting and other use cases that would require
|
|
|
53 |
flexibility, you should add Processors to the Logger that can add extra
|
|
|
54 |
information (tags, user ip, ..) to the records before they are handled.
|
|
|
55 |
|
|
|
56 |
## Log Levels
|
|
|
57 |
|
|
|
58 |
Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424).
|
|
|
59 |
|
|
|
60 |
- **DEBUG** (100): Detailed debug information.
|
|
|
61 |
|
|
|
62 |
- **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
|
|
|
63 |
|
|
|
64 |
- **NOTICE** (250): Normal but significant events.
|
|
|
65 |
|
|
|
66 |
- **WARNING** (300): Exceptional occurrences that are not errors. Examples:
|
|
|
67 |
Use of deprecated APIs, poor use of an API, undesirable things that are not
|
|
|
68 |
necessarily wrong.
|
|
|
69 |
|
|
|
70 |
- **ERROR** (400): Runtime errors that do not require immediate action but
|
|
|
71 |
should typically be logged and monitored.
|
|
|
72 |
|
|
|
73 |
- **CRITICAL** (500): Critical conditions. Example: Application component
|
|
|
74 |
unavailable, unexpected exception.
|
|
|
75 |
|
|
|
76 |
- **ALERT** (550): Action must be taken immediately. Example: Entire website
|
|
|
77 |
down, database unavailable, etc. This should trigger the SMS alerts and wake
|
|
|
78 |
you up.
|
|
|
79 |
|
|
|
80 |
- **EMERGENCY** (600): Emergency: system is unusable.
|
|
|
81 |
|
|
|
82 |
## Configuring a logger
|
|
|
83 |
|
|
|
84 |
Here is a basic setup to log to a file and to firephp on the DEBUG level:
|
|
|
85 |
|
|
|
86 |
```php
|
|
|
87 |
<?php
|
|
|
88 |
|
|
|
89 |
use Monolog\Logger;
|
|
|
90 |
use Monolog\Handler\StreamHandler;
|
|
|
91 |
use Monolog\Handler\FirePHPHandler;
|
|
|
92 |
|
|
|
93 |
// Create the logger
|
|
|
94 |
$logger = new Logger('my_logger');
|
|
|
95 |
// Now add some handlers
|
|
|
96 |
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
|
|
|
97 |
$logger->pushHandler(new FirePHPHandler());
|
|
|
98 |
|
|
|
99 |
// You can now use your logger
|
|
|
100 |
$logger->addInfo('My logger is now ready');
|
|
|
101 |
```
|
|
|
102 |
|
|
|
103 |
Let's explain it. The first step is to create the logger instance which will
|
|
|
104 |
be used in your code. The argument is a channel name, which is useful when
|
|
|
105 |
you use several loggers (see below for more details about it).
|
|
|
106 |
|
|
|
107 |
The logger itself does not know how to handle a record. It delegates it to
|
|
|
108 |
some handlers. The code above registers two handlers in the stack to allow
|
|
|
109 |
handling records in two different ways.
|
|
|
110 |
|
|
|
111 |
Note that the FirePHPHandler is called first as it is added on top of the
|
|
|
112 |
stack. This allows you to temporarily add a logger with bubbling disabled if
|
|
|
113 |
you want to override other configured loggers.
|
|
|
114 |
|
|
|
115 |
> If you use Monolog standalone and are looking for an easy way to
|
|
|
116 |
> configure many handlers, the [theorchard/monolog-cascade](https://github.com/theorchard/monolog-cascade)
|
|
|
117 |
> can help you build complex logging configs via PHP arrays, yaml or json configs.
|
|
|
118 |
|
|
|
119 |
## Adding extra data in the records
|
|
|
120 |
|
|
|
121 |
Monolog provides two different ways to add extra informations along the simple
|
|
|
122 |
textual message.
|
|
|
123 |
|
|
|
124 |
### Using the logging context
|
|
|
125 |
|
|
|
126 |
The first way is the context, allowing to pass an array of data along the
|
|
|
127 |
record:
|
|
|
128 |
|
|
|
129 |
```php
|
|
|
130 |
<?php
|
|
|
131 |
|
|
|
132 |
$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));
|
|
|
133 |
```
|
|
|
134 |
|
|
|
135 |
Simple handlers (like the StreamHandler for instance) will simply format
|
|
|
136 |
the array to a string but richer handlers can take advantage of the context
|
|
|
137 |
(FirePHP is able to display arrays in pretty way for instance).
|
|
|
138 |
|
|
|
139 |
### Using processors
|
|
|
140 |
|
|
|
141 |
The second way is to add extra data for all records by using a processor.
|
|
|
142 |
Processors can be any callable. They will get the record as parameter and
|
|
|
143 |
must return it after having eventually changed the `extra` part of it. Let's
|
|
|
144 |
write a processor adding some dummy data in the record:
|
|
|
145 |
|
|
|
146 |
```php
|
|
|
147 |
<?php
|
|
|
148 |
|
|
|
149 |
$logger->pushProcessor(function ($record) {
|
|
|
150 |
$record['extra']['dummy'] = 'Hello world!';
|
|
|
151 |
|
|
|
152 |
return $record;
|
|
|
153 |
});
|
|
|
154 |
```
|
|
|
155 |
|
|
|
156 |
Monolog provides some built-in processors that can be used in your project.
|
|
|
157 |
Look at the [dedicated chapter](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#processors) for the list.
|
|
|
158 |
|
|
|
159 |
> Tip: processors can also be registered on a specific handler instead of
|
|
|
160 |
the logger to apply only for this handler.
|
|
|
161 |
|
|
|
162 |
## Leveraging channels
|
|
|
163 |
|
|
|
164 |
Channels are a great way to identify to which part of the application a record
|
|
|
165 |
is related. This is useful in big applications (and is leveraged by
|
|
|
166 |
MonologBundle in Symfony2).
|
|
|
167 |
|
|
|
168 |
Picture two loggers sharing a handler that writes to a single log file.
|
|
|
169 |
Channels would allow you to identify the logger that issued every record.
|
|
|
170 |
You can easily grep through the log files filtering this or that channel.
|
|
|
171 |
|
|
|
172 |
```php
|
|
|
173 |
<?php
|
|
|
174 |
|
|
|
175 |
use Monolog\Logger;
|
|
|
176 |
use Monolog\Handler\StreamHandler;
|
|
|
177 |
use Monolog\Handler\FirePHPHandler;
|
|
|
178 |
|
|
|
179 |
// Create some handlers
|
|
|
180 |
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
|
|
181 |
$firephp = new FirePHPHandler();
|
|
|
182 |
|
|
|
183 |
// Create the main logger of the app
|
|
|
184 |
$logger = new Logger('my_logger');
|
|
|
185 |
$logger->pushHandler($stream);
|
|
|
186 |
$logger->pushHandler($firephp);
|
|
|
187 |
|
|
|
188 |
// Create a logger for the security-related stuff with a different channel
|
|
|
189 |
$securityLogger = new Logger('security');
|
|
|
190 |
$securityLogger->pushHandler($stream);
|
|
|
191 |
$securityLogger->pushHandler($firephp);
|
|
|
192 |
|
|
|
193 |
// Or clone the first one to only change the channel
|
|
|
194 |
$securityLogger = $logger->withName('security');
|
|
|
195 |
```
|
|
|
196 |
|
|
|
197 |
## Customizing the log format
|
|
|
198 |
|
|
|
199 |
In Monolog it's easy to customize the format of the logs written into files,
|
|
|
200 |
sockets, mails, databases and other handlers. Most of the handlers use the
|
|
|
201 |
|
|
|
202 |
```php
|
|
|
203 |
$record['formatted']
|
|
|
204 |
```
|
|
|
205 |
|
|
|
206 |
value to be automatically put into the log device. This value depends on the
|
|
|
207 |
formatter settings. You can choose between predefined formatter classes or
|
|
|
208 |
write your own (e.g. a multiline text file for human-readable output).
|
|
|
209 |
|
|
|
210 |
To configure a predefined formatter class, just set it as the handler's field:
|
|
|
211 |
|
|
|
212 |
```php
|
|
|
213 |
// the default date format is "Y-m-d H:i:s"
|
|
|
214 |
$dateFormat = "Y n j, g:i a";
|
|
|
215 |
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
|
|
|
216 |
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
|
|
|
217 |
// finally, create a formatter
|
|
|
218 |
$formatter = new LineFormatter($output, $dateFormat);
|
|
|
219 |
|
|
|
220 |
// Create a handler
|
|
|
221 |
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
|
|
222 |
$stream->setFormatter($formatter);
|
|
|
223 |
// bind it to a logger object
|
|
|
224 |
$securityLogger = new Logger('security');
|
|
|
225 |
$securityLogger->pushHandler($stream);
|
|
|
226 |
```
|
|
|
227 |
|
|
|
228 |
You may also reuse the same formatter between multiple handlers and share those
|
|
|
229 |
handlers between multiple loggers.
|
|
|
230 |
|
|
|
231 |
[Handlers, Formatters and Processors](02-handlers-formatters-processors.md) →
|