のんラボ

S3みたいなストレージサーバーっぽいものを自前で用意する⑥【Logging実装】

2022/04/11 2022/05/29 S3みたいなストレージサーバーっぽいものを自前で用意する⑥【Logging実装】

S3みたいなストレージサーバーっぽいものを自前で用意する⑥【Logging実装】

こんにちは。のんです。

前回に引き続き自前でストレージサーバーを開発していこうと思います。

今回はロギングの実装について話していきたいと思います。

アプリケーション開発の基本中の基本ですね。

GitHubプロジェクトはこちら

ログにはMonologを採用します

PHPで人気のあるログシステムの一つですね。

とても使いやすく、PSR-3に対応しています。

実装していきます

MonologはPSR-3の LoggerInterface に対応しているので、コンテナに Psr\Log\LoggerInterface として Monolog\Logger を登録しておきます。

copied.$container->add(Psr\Log\LoggerInterface::class, Monolog\Logger::class)
    ->addArgument('storage')
    ->addMethodCall('pushHandler', [
        (new Monolog\Handler\RotatingFileHandler(
            sprintf('%s/../logs/application.log', __DIR__),
            30,
            Nonz250\Storage\App\Foundation\App::environment(Nonz250\Storage\App\Shared\ValueObject\Environment::PRODUCTION)
                ? Monolog\Logger::INFO
                : Monolog\Logger::DEBUG,
        ))->setFormatter(new Monolog\Formatter\JsonFormatter()),
    ]);

コンテナに登録するときに addMethodCallpushHandler メソッドを呼ぶようにしておきます。 pushHandler メソッドはMonologの関数です。

この関数に、 RotatingFileHandler クラスを渡すようにしておくとログをローテーションしてくれます。

copied.(new Monolog\Handler\RotatingFileHandler(
    sprintf('%s/../logs/application.log', __DIR__),
    30,
    Nonz250\Storage\App\Foundation\App::environment(Nonz250\Storage\App\Shared\ValueObject\Environment::PRODUCTION)
        ? Monolog\Logger::INFO
        : Monolog\Logger::DEBUG,

名前は application.log です。ローテーションの間隔は30日間ですね。本番環境ではinfoレベルまで、それ以外ではdebugレベルまでログに残すような仕組みになっています。

また、ログの内容はjson方式で登録できるようにしておきます。

後々、分解したり解析したりしやすくなるでしょう。

copied.->setFormatter(new Monolog\Formatter\JsonFormatter()),

JsonFormatter はMonologに標準で実装されていますね。フィールドなどをカスタマイズしたい場合は継承したりして自作しましょう。

Monologをコンテナに登録できたので、実際のコードを見てみる

実際にログに残しているところはこちら。

ファイルアップロードする処理の中でファイルのサイズをデバッグログとして記録します。

copied.public function uploadOriginImage(File $file): string
{
    $uploadStorageDirectory = getcwd() . self::UPLOAD_ORIGIN_DIRECTORY;
    $this->createDir($uploadStorageDirectory);

    $originFilePath = $uploadStorageDirectory . DIRECTORY_SEPARATOR . $file->uniqueFileNameWithOriginExtension();
    $byte = file_put_contents($originFilePath, (string)$file->fileString());
    if ($byte === false) {
        throw new UploadFileException('Failed to upload file.');
    }

    $this->logger->debug(sprintf('%s is %s bytes.', $file->fileNameWithOriginExtension(), $byte));

    return $originFilePath;
}

この関数はアップロードされたファイルの原寸大のファイルをそのまま保存します。
この時にどれくらいのイメージサイズなのかをログに残すのですが、

copied.$this->logger->debug(sprintf('%s is %s bytes.', $file->fileNameWithOriginExtension(), $byte));

で記録しています。

その結果がこちら

copied.{"message":"hoge.jpeg is 4006827 bytes.","context":{},"level":100,"level_name":"DEBUG","channel":"storage","datetime":"2022-04-23T06:37:25.545894+09:00","extra":{}}

ログなので余計な改行なく記録されています。

これをフォーマッターに通すと、

copied.{
    "message": "hoge.jpeg is 4006827 bytes.",
    "context": {},
    "level": 100,
    "level_name": "DEBUG",
    "channel": "storage",
    "datetime": "2022-04-23T06:37:25.545894+09:00",
    "extra": {}
}

という感じになります。

最後に

これで、本番運用中の調査も楽ちんになりました。

とは言っても自分で使うサービスなので、ログを確認することはほとんど無いかも知れません。

ログがあると開発中も色々便利なので入れた。という感じですかね。

次回は実際のファイルアップロードについて触れて最終回となるかも知れません。

今回は短かったですが次回は長くなりそう。長くなりすぎる場合は何個かに切り取りましょうかね。

また記事にします。

そのときはよしなに。

.