scratch – Blame information for rev
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
115 | office | 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) → |