GCP(GCE)でLaravelのログをStackDriverに出力する


GCPでLaravelのログをStackDriverに出力するには

TL;DR

  • monolog-stackdriver を使うことで、LaravelログをstackDriverで表示できる
  • envファイルの設定で、ログの出力先を通常ログ or StackDriverの切り替え可能
  • インタンスを設定しないと、StackDriverの グローバル カテゴリに出力される
  • GCEのinstance_id を指定することで、コンピュータに紐付けた出力もできるがid取得方法までは調べていない

ログ送信手順

composerでパッケージ導入

こちらのパッケージを使います。
https://packagist.org/packages/codeinternetapplications/monolog-stackdriver

ライブラリ導入コマンド
composer require codeinternetapplications/monolog-stackdriver

ログの送信先を設定する

1.ENVファイルの設定

2.config/logging.php設定

config/logging.phpはStackDriverでの表示先で設定量が異なります

  • グローバル ->共通の設定を行うだけ
  • インタンス名単位(今回はGCE) ->インスタンス名のみ設定
  • インスタンス(マシーン)単位 ->インスタンIDも設定

ENVファイルを設定する

ログを表示したいレベルに合わせて、envを記載します。

env
# 必須
LOG_CHANNEL=stackdriver

# インスタンス名別のログ保存する場合
GCP_LOG_RESOURCE_NAME=hoge_resource

# インスタンス(マシーン)単位のログ保存する場合
GCP_LOG_INSTANCE_ID=hoge_xxxxxx
GCP_LOG_PROJECT_ID=hoge_id
GCP_LOG_ZONE=hoge_zone

hoge_ の値は適切な値に変更してください。

config/logging.phpを設定する

グローバルで表示されるように設定する場合

config/logging.php

'channels' => [

    // ( ... )

    'stackdriver' => [
        'driver' => 'custom',
        'via' => CodeInternetApplications\MonologStackdriver\Laravel\CreateStackdriverLogger::class,
        'logName' => env('APP_NAME', 'my-project-log'),

        //GCP内部からの保存には必要ない
        // 'loggingClientOptions' => [
            // 'keyFilePath' => '/path/to/service-account-key-file.json',
        // ],

        // 'loggerOptions' => [],
        // 'lineFormat' => '%message%',
        // 'entryOptionsWrapper' => 'stackdriver',
    ],
]

logName項目は適切な名前をつけてください

loggingClientOptions 項目で、jsonのキーファイルを指定しますが、GCP内部でのログ送信にjsonは必要ありません。
他のクラウド(AWSなど)から送信する場合に指定します。

ログ表示例

下で説明している項目でログを送信

良い点
- 設定が簡単
- 多くの場合で適用できる
- 複数のインスタンのプログラムからのログを集約できる

悪い点
- 複数のマシーンからのログを識別する工夫が別途必要
-エラー調査の際、グローバルとマシンログを往復して比較する必要がある

インスタンス名別で表示されるように設定する場合

config/logging.php

'channels' => [

    // ( ... )

    'stackdriver' => [
        'driver' => 'custom',
        'via' => CodeInternetApplications\MonologStackdriver\Laravel\CreateStackdriverLogger::class,
        'logName' => env('APP_NAME', 'my-project-log'),

        'loggerOptions' => [
              'labels' => [
                  'compute.googleapis.com/resource_name' => env('GCP_LOG_RESOURCE_NAME', 'dev-web-instance'),
              ],
              'resource' => [
                  'type' => 'gce_instance',
              ],
        ]

        //GCP内部からの保存には必要ない
        // 'loggingClientOptions' => [
            // 'keyFilePath' => '/path/to/service-account-key-file.json',
        // ],

        // 'loggerOptions' => [],
        // 'lineFormat' => '%message%',
        // 'entryOptionsWrapper' => 'stackdriver',
    ],
]

グローバル設定に、 loggerOptions を追加しています。
ここでは、GCEのログなのでインスタンにGCEを指定しています。
指定したい箇所のログで実際に指定されている項目を設定ファイルにコピーすれば、その箇所に入るようになります。

ログ表示例

下で説明している項目でログを送信

良い点
- サーバと同じカテゴリなので、時間軸に沿った把握ができる
- マシーンをグループ化していなければ、マシーン名とログが一致する
- オートスケールマシーンでもグループに集約される形で取得できる

悪い点
- マシーンの識別はできない
- instance_idが空でも表示できているが、正常なログの仕様として問題ないか不明(なんらかのログサービスと連携した時の挙動が心配)

インスタンス(マシーン)単位で表示されるように設定する場合

config/logging.php

'channels' => [

    // ( ... )

    'stackdriver' => [
        'driver' => 'custom',
        'via' => CodeInternetApplications\MonologStackdriver\Laravel\CreateStackdriverLogger::class,
        'logName' => env('APP_NAME', 'my-project-log'),

        'loggerOptions' => [
              'labels' => [
                  'compute.googleapis.com/resource_name' => env('GCP_LOG_RESOURCE_NAME', 'dev-web-instance'),
              ],
              'resource' => [
                    'type' => 'gce_instance',
                    'labels' => [
                        'instance_id' =>  env('GCP_LOG_INSTANCE_ID'),
                        'project_id' =>  env('GCP_LOG_PROJECT_ID'),
                        'zone' =>  env('GCP_LOG_ZONE'),
                    ]
                ],
        ]

        //GCP内部からの保存には必要ない
        // 'loggingClientOptions' => [
            // 'keyFilePath' => '/path/to/service-account-key-file.json',
        // ],

        // 'loggerOptions' => [],
        // 'lineFormat' => '%message%',
        // 'entryOptionsWrapper' => 'stackdriver',
    ],
]

インスタンス名別の設定に、 loggerOptions.resource.labels を追加しています。

instance_idは、Compute Engineの詳細ページ

project_idは、TOPページに記載されています

ログ表示例

(省略)

良い点
- サーバの情報と同じ場所に格納されるので時間軸に沿った把握が簡単
- マシーンの識別もできる
悪い点
- オートスケールでidが変わる場合の対応を考える必要がある

ログ送信

Laravelの標準的なコードで送信が行える

ログ送信コード例

//infoレベルログ
Log::info('InfoLogInfoTest', ['logItem1' => 'メッセージはあとから分かりやすいものを', 'logItem2' => ['ItemSub1' => '配列形式で自由にデータを入れられる', 'ItemSub2' => '入れ子も問題なし'] ]);

// errorレベルログ
Log::error('InfoLogErrorTest', ['logItem1' => 'エラーもStackDriverで正しく識別', 'logItem2' => ['ItemSub1' => '配列形式で自由にデータを入れられる', 'ItemSub2' => '入れ子も問題なし'] ]);

第1引数は、 message に格納される
第2引数は、 jsonPayload に格納される

StackDriverにログレベルも認識されているので、 Errorの絞り込みも行える

以上です。