If you are using docker and cloud services to run your application live, you should manage your logs.
The most common method to store them is to put them in the text file. It’s the default configuration for most backend frameworks. This option is ok if you run your application locally or on the VPS server for test.
When you run your application in a production environment, you should choose a better option to manage your logs. Almost every cloud has a tool for rotating logs or if not, you can use for example Grafana Loki or ELK stack. Those solutions are better because give you interfaces to rotate and search your logs. Also, you have easy access to them, you no need to connect to your server to review them.
If you are using Docker containers, and you running your application in cloud services, often they will be automatically writing the logs of your containers to tools like AWS CloudWatch or GCloud Stackdriver.
But first, you need to redirect your log streams to the output of the Docker container to be able to use them.
Docker containers are running the Linux processes. In linux every running process has 3 streams,
STDIN it’s command input stream, that you can provide for ex. by your keyboard.
STDOUT is the stream where the running command may print the output.
STDERR is the standard error stream, but the name I think is a bit confusing, because it is basically intended for diagnostic output.
When you run the
docker logs [container] command in your terminal, you will see the output of
STDERR streams. So our goal is to redirect our logs to one of those streams.
In PHP we are often running our application using the PHP-FPM (Process Manager). If you run your docker with FPM inside a docker container, and you run the
docker logs command, you should see the output with processed requests, or errors.
So the PHP-FPM is already writing its output to
The PHP-FPM allow us to catch workers output and forward them to the
STDOUT. To do that we need to make sure that the FPM is configured properly. You can create new config file, and push it for example to the
[global] error_log = /proc/self/fd/2 [www] access.log = /proc/self/fd/2 catch_workers_output = yes decorate_workers_output = no
access.log parameters are configuration of streams of logs output.
catch_workers_output option is turning on the worker’s output caching. The
decorate_workers_output is the option that turns off the output decoration. If you leave this option turned on, FPM will decorate your application output like this:
[21-Mar-2016 14:10:02] WARNING: [pool www] child 12 said into stdout: "[your log line]"
decorate_workers_output option is available only for PHP 7.3.0 and higher.
If you are using official docker php-fpm image, this configuration is already set in the
/usr/local/etc/php-fpm.d/docker.conf file, so you no need to do anything more
Right now everything that will be put to the stdout from PHP workers will be shown in our docker logs. But when logs are forwarded to that stream in PHP?
To write something to
STDIN on PHP level, we need to just write to the
In the simplest way you can do this like that:
<?php file_put_contents('php://stdout', 'Hello world');
When you execute this code in php cli, you will get the
Hello world text on the output.
But it’s not the optimal way to push your logs to the
STDOUT. Every modern framework should have a PSR-3 Logger. I think that the most popular now is the monolog, so I will show you how to configure it in Symfony, Laravel, and in pure usage.
Monolog is great library to handle logs in your application. It’s easy and elastic in configuration.
If you are using monolog in your project with manual configuration, you need to configure handler in this way:
(Modified documentation example)
<?php use MonologLogger; use MonologHandlerStreamHandler; $log = new Logger('stdout'); $log->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG)); $log->debug('Foo');
You just need to configure StreamHandler, to write to the
Symfony Kernel since the Flex was provided, is using minimalist PSR-3 logger, that logs everything to
php://stderr by default.
In Symfony, monolog as other components is configured in YAML files. So the same configuration will look like this:
# config/packages/monolog.yaml monolog: handlers: stdout: type: stream path: "php://stdout" level: debug
Laravel use the arrays for configuration so the same thing will look like this:
# config/logging.php <?php use MonologHandlerStreamHandler; return [ 'channels' => 'stdout' => [ 'driver' => 'monolog', 'handler' => StreamHandler::class, 'level' => env('LOG_LEVEL', 'debug'), 'with' => [ 'stream' => 'php://stdout', ], ], ];
In some articles on the internet, you can read that someone uses stderr, and someone uses stdout streams to write logs there. Right now I cannot fin any reasons to choose one of them which is better.
The only information that I found on this topic is that post.
I think that stderr is more popular in some examples, also Fabien Potencier set it as default in his minimalistic logger, so I think we can assume that this one is better.
Personally, I always used the stdout, so that’s the reason why I use it in this post’s examples. If I will find a great reason for using one of them over another I will update this post.
Originally posted on https://mateuszcholewka.com