LoginSignup
11
4

More than 3 years have passed since last update.

CakePHP4 でログ出力を標準出力(stdout, stderr) にする

Last updated at Posted at 2020-03-21

本番環境をコンテナで実行する場合(例えば、AWSの ECS, Fargate で実行する場合)、ログ出力は標準出力にするのがベストな方法の1つです。

CakePHP4 プロジェクトでログを標準出力に出すようにしてみます。

この記事でわかること

参考

事前準備

docker-compose up -d
バージョン
docker Docker version 19.03.8, build afacb8b
docker-compose docker-compose version 1.25.4, build 8d51620a
CakePHP4 4.0.4

ログ出力方法の変更

./config/app.php の Log の設定を変更します。

config/app.php
use Cake\Console\ConsoleOutput;
use Cake\Log\Engine\ConsoleLog;

// ...

    'Log' => [
        'debug' => [
            'className' => ConsoleLog::class,
            'stream' => 'php://stdout',
            'outputAs' => ConsoleOutput::PLAIN,
            'url' => env('LOG_DEBUG_URL', null),
            'scopes' => false,
            'levels' => ['notice', 'info', 'debug'],
        ],
        'error' => [
            'className' => ConsoleLog::class,
            'stream' => 'php://stderr',
            'outputAs' => ConsoleOutput::PLAIN,
            'url' => env('LOG_ERROR_URL', null),
            'scopes' => false,
            'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
        ],
        // To enable this dedicated query log, you need set your datasource's log flag to true
        'queries' => [
            'className' => ConsoleLog::class,
            'stream' => 'php://stdout',
            'outputAs' => ConsoleOutput::PLAIN,
            'url' => env('LOG_QUERIES_URL', null),
            'scopes' => ['queriesLog'],
        ],
    ],

// ...

classNameConsoleLog::class を指定します。
ConsoleLog::class 固有で指定できるパラメータは stream outputAs の2つです。
残りのパラメータ scopes levels は BaseLog から引き継いでいる情報なので、 FileLog::class を指定しているときから変更する必要はありません。
また、 url については後述します。

stream は、標準出力( php://stdout )または、標準エラー( php://stderr )を指定します。
outputAs は3つのモード(RAW, PLAIN, COLOR)があります。
COLOR にすると、コンソールが対応していればエラーだと赤文字で出力されますっというような制御の指定です。
たまにログによくわからない制御文字が入っている場合、大概、この COLOR での色情報が出てるんじゃないかなっと思います。
PLAIN が純粋で一番良いと思っています。

標準出力と言っても困ることもある

ログ出力を標準出力に変えてしまうと、テスト実行時に余計なログが出たり、開発時にログを追うのが難しいケースもあると思います。

そのときはやはりファイルに出力したくなります。

その場合、 ./config/.env で設定を上書きすることが可能です。そのときに使うのが url です。

config.env
export LOG_DEBUG_URL="file://logs/?file=debug&path=/var/www/html/logs/"
export LOG_ERROR_URL="file://logs/?file=error&path=/var/www/html/logs/"
export LOG_QUERIES_URL="file://logs/?file=queries&path=/var/www/html/logs/"

上記のように環境変数を用意することで、ファイルログ出力に切り替えることができます。
Docker 環境の場合、 path を固定で指定しても問題はありません(どの開発者でもマウントされている volume は同じなので)。

忘れないように ./config/.env.example にも同様の内容を追加しておきます。

補足) 本番環境を意識する

少し前までは、ログはローテーションさせつつ、どこかに待避させつつ、、、っと煩雑な作業の1つだったと思います。
でも、本番環境をコンテナで実行する場合、かなり簡単になりました。

AWS ECS / Fargate 環境の場合、標準出力・標準エラーで出しておけば、CloudWatch logs へ転送されます。
CloudWatch logs で失効期間を指定すれば、古いログを自動で削除できます。
また、 CloudWatch logs へ転送されれば、メトリクスフィルターでキーワード(「Exception」等)を指定して、フィルターにかけることでアラート通知を行うこともできます。

Fluentd 等を使いより柔軟なログ転送を行うこともできますが、まずは、気軽な上記の方法から試すのが良いのではないかなっと思っています。

AWS しか利用していないため、詳しくは把握していませんが、他クラウドサービスも似た機能はあると思います。

ログ出力は手軽に標準出力・標準エラーで解決するのが、手間のかからない良い方法だと思います。

補足) nginx のログはどうなっているか

nginx のコンテナを立ち上げた場合、 default.conf でファイル出力しているに見えますが、実は、シンボリックリンクで標準出力・標準エラーに変えられています。

ホスト-コンテナへ入る
docker exec -it web /bin/sh
コンテナ
ls -l /var/log/nginx/
total 0
lrwxrwxrwx    1 root     root            11 May 11  2019 access.log -> /dev/stdout
lrwxrwxrwx    1 root     root            11 May 11  2019 error.log -> /dev/stderr

そのため docker logs -f web をするとログを参照することができます。

補足) php-fpm のログはどうなっているか

docker logs -f app するとプログラムでは出力していない

192.168.96.3 -  21/Mar/2020:06:01:15 +0000 "GET /index.php" 200

のようなログが出ていると思います。
これは、php-fpm コンテナ内の /usr/local/etc/php-fpm.d/docker.conf にて設定されている内容で出力されています。

ホスト-コンテナへ入る
docker exec -it app /bin/bash
コンテナ
cat /usr/local/etc/php-fpm.d/docker.conf
/usr/local/etc/php-fpm.d/docker.conf
[global]
error_log = /proc/self/fd/2

; https://github.com/docker-library/php/pull/725#issuecomment-443540114
log_limit = 8192

[www]
; if we send this to /proc/self/fd/1, it never appears
access.log = /proc/self/fd/2

clear_env = no

; Ensure worker stdout and stderr are sent to the main error log.
catch_workers_output = yes
decorate_workers_output = no

/proc/self/fd/2 について、詳しくは把握していないですが、コメントにあるように 2 を 1 へ変えればでなくなるみたいです。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4