In the last few years, the way applications log messages has changed. Using
files was the common way to store logs but with the Cloud (read containers,
Docker, and the likes), using stderr
to stream logs is recommended.
Did you know that you don't need Monolog to capture application logs? Since
Symfony 3.4, the Symfony HttpKernel component comes with a default PSR3 logger that
logs everything in stderr
, without the help of any other packages. This
feature was added along side the introduction of Flex as new applications start
with no extra packages, and so no logger. Loggin via `stderr` was chosen with
containers in mind.
By default, new Symfony applications log in stderr
via this default
HttpKernel logger. It is probably enough for small applications; I'm using it
for fabbot and Twig's website for instance.
Using Monolog is still very useful as it comes with way more options and
configurability. But for historical reasons, and probably practicability on
dedicated servers, Monolog default recipe still uses a file to store logs
(%kernel.logs_dir%/%kernel.environment%.log
). The Symfony Kernel class even
has a getLogDir()
method as defined in the Kernel interface.
It might make sense on a development server (more on that later), but in
production, stderr
is a better option, especially when using Docker,
SymfonyCloud, lambdas, ... So, I now recommend to use php://stderr
as the
path for Monolog:
1 2 3 4 5 6 7 8 9 10 11
--- a/config/packages/prod/monolog.yaml
+++ b/config/packages/prod/monolog.yaml
@@ -11,7 +11,7 @@ monolog:
members: [nested, buffer]
nested:
type: stream
- path: "%kernel.logs_dir%/%kernel.environment%.log"
+ path: php://stderr
level: debug
buffer:
type: buffer
On SymfonyCloud, using stderr
also has a few added benefits (the same
should apply to most containerized platforms). Even if in the end, the logs
sent to stderr
end up in a file as well: app.log
. You might wonder how
this could be better than using a dedicated file then. First, the app.log
file is "managed" by SymfonyCloud: it is automatically rotated (no more log
files growing indefinitely until it fills up your disk), the app.log
file
is stored in a local and fast disk instead of a network disk (which is used
when storing files under var/log/
). It might also be less expensive as you
don't "waste" network disk capacity with ephemeral logs.
Using stderr
also means that there is one less write-able directory needed
by Symfony (don't forget to log deprecation notices in stderr
as well and
check that no third-party bundles write into the getLogDir()
directory).
What about development? Can you use stderr
as well? The answer is yes and I
recommend you to do so as well.
If you are using PHP-FPM, you need to configure it to "forward" logs to FPM
logs (which can be streamed on stderr
as well!):
1 2 3
; Ensure worker stdout and stderr are sent to the main error log
catch_workers_output = yes
decorate_workers_output = no (7.3+ only)
If you are using Symfony CLI, that's the default configuration for PHP-FPM and logs are automatically "un-decorated" for all PHP versions.
Happy logging!
Thanks for this article!
Why stderr all the time? Why not stdout by default and use stderr for error level and more?
@Benoit Galati stderr is not only for errors, but also for any diagnostic messages.
Why stderr? Because when using CGI, the stdout is sent to the browser (stdin receives HTTP Post data). In console, the stdout (and stdin) is for communication with user.
It looks like nginx doesn't like this solution... I just tried it and I'm getting the following error:
"[error] 6#6: *1 upstream sent too big header while reading response header from upstream"
I found that this commit https://github.com/symfony/symfony/commit/5f829bd changed default $option argument for Logger from 'php://stderr' to null. So is it still true that such logger logs everything in stderr?
I still think using stderr as general log output is rather wrong.
Its not symfony fault though but a PHP short, as it seems. Here is the bug report: https://bugs.php.net/bug.php?id=73886 Also from official docker lib: https://github.com/docker-library/php/issues/358#issuecomment-271033464
For example GCP log collector will label the log as error when coming from stderr and this will result in unwanted alerts by default in case you want to log some more bits then just errors from php. (Might happen even in production ;) )