Skip to content

Commit c76a32b

Browse files
authored
Merge pull request #68 from sensiolabs/issue_51_logging
top-level logging section
2 parents ec707a3 + 5c220b6 commit c76a32b

7 files changed

+697
-612
lines changed

logging.rst

Lines changed: 322 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,328 @@
1-
Logging
2-
=======
1+
Logging with Monolog
2+
====================
3+
4+
Symfony comes with an outside library - called Monolog_ - that allows you to create
5+
logs that can be stored in a variety of different places.
6+
7+
Logging a Message
8+
-----------------
9+
10+
To log a message, fetch the ``logger`` service from the container in
11+
your controller::
12+
13+
public function indexAction()
14+
{
15+
$logger = $this->get('logger');
16+
$logger->info('I just got the logger');
17+
$logger->error('An error occurred');
18+
19+
$logger->critical('I left the oven on!', array(
20+
// include extra "context" info in your logs
21+
'cause' => 'in_hurry',
22+
));
23+
24+
// ...
25+
}
26+
27+
The ``logger`` service has different methods for different logging levels/priorities.
28+
You can configure the logger to do different things based on the *level* of a message
29+
(e.g. :doc:`send an email when an error occurs </logging/monolog_email>`).
30+
31+
See LoggerInterface_ for a list of all of the methods on the logger.
32+
33+
Where Logs are Stored
34+
---------------------
35+
36+
The configuration for *where* logs are stored lives in the specific
37+
:doc:`environment </configuration/environments>` configuration files: ``config_dev.yml``
38+
and ``config_prod.yml``.
39+
40+
By default, log entries are written to the ``app/logs/dev.log`` file when you're in
41+
the ``dev`` environment. In the ``prod`` environment, logs are written to ``app/logs/prod.log``,
42+
but *only* during a request where an error or high-priority log entry was made
43+
(i.e. ``error()`` , ``critical()``, ``alert()`` or ``emergency()``).
44+
45+
To control this, you'll configure different *handlers* that handle log entries, sometimes
46+
modify them, and ultimately store them.
47+
48+
Handlers: Writing Logs to different Locations
49+
---------------------------------------------
50+
51+
The logger has a stack of *handlers*, and each can be used to write the log entries
52+
to different locations (e.g. files, database, Slack, etc).
53+
54+
.. tip::
55+
56+
You can *also* configure logging "channels", which are like categories. Each
57+
channel can have its *own* handlers, which means you can store different log
58+
messages in different places. See :doc:`/logging/channels_handlers`.
59+
60+
Symfony pre-configures some basic handlers in the ``config_dev.yml`` and ``config_prod.yml``
61+
files. Check these out for some real-world examples.
62+
63+
This example uses *two* handlers: ``stream`` (to write to a file) and ``syslog``
64+
to write logs using the :phpfunction:`syslog` function:
65+
66+
.. configuration-block::
67+
68+
.. code-block:: yaml
69+
70+
# app/config/config.yml
71+
monolog:
72+
handlers:
73+
# this "file_log" key could be anything
74+
file_log:
75+
type: stream
76+
# log to app/logs/(environment).log
77+
path: "%kernel.logs_dir%/%kernel.environment%.log"
78+
# log *all* messages (debug is lowest level)
79+
level: debug
80+
81+
syslog_handler:
82+
type: syslog
83+
# log error-level messages and higher
84+
level: error
85+
86+
.. code-block:: xml
87+
88+
<!-- app/config/config.xml -->
89+
<?xml version="1.0" encoding="UTF-8" ?>
90+
<container xmlns="http://symfony.com/schema/dic/services"
91+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
92+
xmlns:monolog="http://symfony.com/schema/dic/monolog"
93+
xsi:schemaLocation="http://symfony.com/schema/dic/services
94+
http://symfony.com/schema/dic/services/services-1.0.xsd
95+
http://symfony.com/schema/dic/monolog
96+
http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
97+
98+
<monolog:config>
99+
<monolog:handler
100+
name="file_log"
101+
type="stream"
102+
path="%kernel.logs_dir%/%kernel.environment%.log"
103+
level="debug"
104+
/>
105+
<monolog:handler
106+
name="syslog_handler"
107+
type="syslog"
108+
level="error"
109+
/>
110+
</monolog:config>
111+
</container>
112+
113+
.. code-block:: php
114+
115+
// app/config/config.php
116+
$container->loadFromExtension('monolog', array(
117+
'handlers' => array(
118+
'file_log' => array(
119+
'type' => 'stream',
120+
'path' => '%kernel.logs_dir%/%kernel.environment%.log',
121+
'level' => 'debug',
122+
),
123+
'syslog_handler' => array(
124+
'type' => 'syslog',
125+
'level' => 'error',
126+
),
127+
),
128+
));
129+
130+
This defines a *stack* of handlers and each handler is called in the order that it's
131+
defined.
132+
133+
Handlers that Modify Log Entries
134+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135+
136+
Instead of writing log files somewhere, *some* handlers are used to filter or modify
137+
log entries before sending them to *other* handlers. One powerful, built-in handler
138+
called ``fingers_crossed`` is used in the ``prod`` environment by default. It stores
139+
*all* log messages during a request but *only* passes them to a second handler if
140+
one of the messages reaches an ``action_level``. Take this example:
141+
142+
.. configuration-block::
143+
144+
.. code-block:: yaml
145+
146+
# app/config/config.yml
147+
monolog:
148+
handlers:
149+
filter_for_errors:
150+
type: fingers_crossed
151+
# if *one* log is error or higher, pass *all* to file_log
152+
action_level: error
153+
handler: file_log
154+
155+
# now passed *all* logs, but only if one log is error or higher
156+
file_log:
157+
type: stream
158+
path: "%kernel.logs_dir%/%kernel.environment%.log"
159+
160+
# still passed *all* logs, and still only logs error or higher
161+
syslog_handler:
162+
type: syslog
163+
level: error
164+
165+
.. code-block:: xml
166+
167+
<!-- app/config/config.xml -->
168+
<?xml version="1.0" encoding="UTF-8" ?>
169+
<container xmlns="http://symfony.com/schema/dic/services"
170+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
171+
xmlns:monolog="http://symfony.com/schema/dic/monolog"
172+
xsi:schemaLocation="http://symfony.com/schema/dic/services
173+
http://symfony.com/schema/dic/services/services-1.0.xsd
174+
http://symfony.com/schema/dic/monolog
175+
http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
176+
177+
<monolog:config>
178+
<monolog:handler
179+
name="filter_for_errors"
180+
type="fingers_crossed"
181+
action-level="error"
182+
handler="file_log"
183+
/>
184+
<monolog:handler
185+
name="file_log"
186+
type="stream"
187+
path="%kernel.logs_dir%/%kernel.environment%.log"
188+
level="debug"
189+
/>
190+
<monolog:handler
191+
name="syslog_handler"
192+
type="syslog"
193+
level="error"
194+
/>
195+
</monolog:config>
196+
</container>
197+
198+
.. code-block:: php
199+
200+
// app/config/config.php
201+
$container->loadFromExtension('monolog', array(
202+
'handlers' => array(
203+
'filter_for_errors' => array(
204+
'type' => 'fingers_crossed',
205+
'action_level' => 'error',
206+
'handler' => 'file_log',
207+
),
208+
'file_log' => array(
209+
'type' => 'stream',
210+
'path' => '%kernel.logs_dir%/%kernel.environment%.log',
211+
'level' => 'debug',
212+
),
213+
'syslog_handler' => array(
214+
'type' => 'syslog',
215+
'level' => 'error',
216+
),
217+
),
218+
));
219+
220+
Now, if even one log entry has an ``error`` level or higher, then *all* log entries
221+
for that request are saved to a file via the ``file_log`` handler. That means that
222+
your log file will contain *all* the details about the problematic request - making
223+
debugging much easier!
224+
225+
.. tip::
226+
227+
The handler named "file_log" will not be included in the stack itself as
228+
it is used as a nested handler of the ``fingers_crossed`` handler.
229+
230+
.. note::
231+
232+
If you want to override the ``monolog`` configuration via another config
233+
file, you will need to redefine the entire ``handlers`` stack. The configuration
234+
from the two files cannot be merged because the order matters and a merge does
235+
not allow to control the order.
236+
237+
All Built-in Handlers
238+
---------------------
239+
240+
Monolog comes with *many* built-in handlers for emailing logs, sending them to Loggly,
241+
or notifying you in Slack. These are documented inside of MonologBundle itself. For
242+
a full list, see `Monolog Configuration`_.
243+
244+
How to Rotate your Log Files
245+
----------------------------
246+
247+
Over time, log files can grow to be *huge*, both while developing and on
248+
production. One best-practice solution is to use a tool like the `logrotate`_
249+
Linux command to rotate log files before they become too large.
250+
251+
Another option is to have Monolog rotate the files for you by using the
252+
``rotating_file`` handler. This handler creates a new log file every day
253+
and can also remove old files automatically. To use it, just set the ``type``
254+
option of your handler to ``rotating_file``:
255+
256+
.. configuration-block::
257+
258+
.. code-block:: yaml
259+
260+
# app/config/config_dev.yml
261+
monolog:
262+
handlers:
263+
main:
264+
type: rotating_file
265+
path: '%kernel.logs_dir%/%kernel.environment%.log'
266+
level: debug
267+
# max number of log files to keep
268+
# defaults to zero, which means infinite files
269+
max_files: 10
270+
271+
.. code-block:: xml
272+
273+
<!-- app/config/config_dev.xml -->
274+
<?xml version="1.0" encoding="UTF-8" ?>
275+
<container xmlns="http://symfony.com/schema/dic/services"
276+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
277+
xmlns:monolog="http://symfony.com/schema/dic/monolog"
278+
xsi:schemaLocation="http://symfony.com/schema/dic/services
279+
http://symfony.com/schema/dic/services/services-1.0.xsd
280+
http://symfony.com/schema/dic/monolog
281+
http://symfony.com/schema/dic/monolog/monolog-1.0.xsd">
282+
283+
<monolog:config>
284+
<!-- "max_files": max number of log files to keep
285+
defaults to zero, which means infinite files -->
286+
<monolog:handler name="main"
287+
type="rotating_file"
288+
path="%kernel.logs_dir%/%kernel.environment%.log"
289+
level="debug"
290+
max_files="10"
291+
/>
292+
</monolog:config>
293+
</container>
294+
295+
.. code-block:: php
296+
297+
// app/config/config_dev.php
298+
$container->loadFromExtension('monolog', array(
299+
'handlers' => array(
300+
'main' => array(
301+
'type' => 'rotating_file',
302+
'path' => '%kernel.logs_dir%/%kernel.environment%.log',
303+
'level' => 'debug',
304+
// max number of log files to keep
305+
// defaults to zero, which means infinite files
306+
'max_files' => 10,
307+
),
308+
),
309+
));
310+
311+
Adding extra Data to each Log (e.g. a unique request token)
312+
-----------------------------------------------------------
313+
314+
Monolog also supports *processors*: functions that can dynamically add extra
315+
information to your log entries.
316+
317+
See :doc:`/logging/processors` for details.
3318

4319
.. toctree::
5320
:maxdepth: 1
6321
:glob:
7322

8323
logging/*
324+
325+
.. _Monolog: https://github.com/Seldaek/monolog
326+
.. _LoggerInterface: https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php
327+
.. _`logrotate`: https://fedorahosted.org/logrotate/
328+
.. _`Monolog Configuration`: https://github.com/symfony/monolog-bundle/blob/master/DependencyInjection/Configuration.php#L25

logging/channels_handlers.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,3 @@ need to tag your services:
172172
173173
With this, you can now send log messages to the ``foo`` channel by using
174174
the automatically registered logger service ``monolog.logger.foo``.
175-
176-
Learn more from the Cookbook
177-
----------------------------
178-
179-
* :doc:`/logging/monolog`

0 commit comments

Comments
 (0)