Cover of the book Symfony 5: The Fast Track

Symfony 5: The Fast Track is the best book to learn modern Symfony development, from zero to production. +300 pages showcasing Symfony with Docker, APIs, queues & async tasks, Webpack, SPAs, etc.

Logging in Symfony and the Cloud

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:

--- a/config/packages/prod/monolog.yaml
+++ b/config/packages/prod/monolog.yaml
@@ -11,7 +11,7 @@ monolog:
            members: [nested, buffer]
            type: stream
-            path: "%kernel.logs_dir%/%kernel.environment%.log"
+            path: php://stderr
            level: debug
            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!):

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

Help the Symfony project!

As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.


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 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:
Also from official docker lib:

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

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.