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 ;) )