Skip to main content

アプリケーションコードでログのルーティングを処理してはいけません



一段落説明

アプリケーションコードはログルーティングを扱うべきではなく、代わりにロガーユーティリティを使用して stdout/stderr に書き込むべきです。「ログルーティング」とは、ログを拾ってアプリケーションやアプリケーションプロセスとは別の場所にプッシュすること、例えば、ファイルやデータベースなどにログを書き込むことを意味します。その理由は主に2つあります: 1)懸念事項の分離と、2) 12-Factor best practices for modern applications(現代のアプリケーションのための12ファクターのベストプラクティス)

私たちはしばしば、サービス間やサービス自体の間のコードの断片という意味で「懸念の分離」を考えますが、これはより「インフラストラクチャ的」なコンポーネントにも適用されます。あなたのアプリケーションコードは、インフラストラクチャ/実行環境(最近ではコンテナが多い)で処理すべきものを処理すべきではありません。アプリケーションでログの場所を定義していて、後でその場所を変更する必要がある場合はどうなるでしょう? その結果、コードの変更とデプロイが必要になります。コンテナベース/クラウドベースのプラットフォームで作業する場合、パフォーマンスの要求に合わせてスケーリングする際にコンテナがスピンアップしたり、シャットダウンしたりすることがあるので、ログファイルがどこで終わるかわからないのです。そのため、ログファイルの行き先は実行環境 (コンテナ) が決めるべきです。アプリケーションは必要なものを stdout / stderr にログを記録し、実行環境はそこからログストリームを拾い、必要な場所にルートするように設定する必要があります。また、ログの送信先を指定したり変更したりする必要があるチームの人々は、アプリケーション開発者ではなく DevOps の一員であることが多く、アプリケーションのコードに精通していない可能性があります。このため、彼らが簡単に変更を行うことができません。



コード例 – アンチパターン: アプリケーションと密接に結合されたログルーティング

const { createLogger, transports, winston } = require('winston');
/**
* `winston-mongodb` を require すると
* `winston.transports.MongoDB` が公開されます。
*/
require('winston-mongodb');

// ログを2つの異なるファイルに保存します。これはアプリケーションが考慮する必要があります。
const logger = createLogger({
transports: [
new transports.File({ filename: 'combined.log' }),
],
exceptionHandlers: [
new transports.File({ filename: 'exceptions.log' })
]
});

// ログをMongoDBに保存します。これはアプリケーションが考慮する必要があります。
winston.add(winston.transports.MongoDB, options);

このようにして、アプリケーションはアプリケーション/ビジネスロジックとログルーティングロジックの両方を処理するようになりました。



コード例 – より良いログ処理 + Docker の例

アプリケーション内部:

const logger = new winston.Logger({
level: 'info',
transports: [
new (winston.transports.Console)()
]
});

logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });

そして、dockerコンテナの daemon.json で:

{
"log-driver": "splunk", // Splunk を例に挙げていますが、別のストレージタイプを入力する可能性があります。
"log-opts": {
"splunk-token": "",
"splunk-url": "",
//...
}
}

そのため、この例では log -> stdout -> Docker container -> Splunk のようになります。



ブログ引用: 「オライリー・ジャパン

オライリーブログ より、

一定数のサーバ上に一定数のインスタンスがある場合、ディスク上にログを保存することは理にかなっているように思えます。しかし、アプリケーションが実行中の1つのインスタンスから100のインスタンスへと動的に変化し、それらのインスタンスがどこで実行されているのか分からない場合は、クラウドプロバイダーにログの集計を代行してもらう必要があります。



引用: 「12ファクター」

12-Factor best practices for logging(ロギングのための12ファクターのベストプラクティス) より、

12 ファクターのアプリは、出力ストリームのルーティングやストレージには決して関心を持ちません。ログファイルへの書き込みや管理を試みるべきではありません。その代わり、各実行中のプロセスは、バッファリングされていないイベントストリームを標準出力に書き込みます。

ステージングまたは本番環境では、各プロセスのストリームは実行環境によってキャプチャされ、アプリからの他のすべてのストリームと照合され、1つまたはそれ以上の最終目的地にルーティングされて、表示および長期間アーカイブされます。これらのアーカイブ先は、アプリからは見えませんし、アプリで設定することもできず、代わりに実行環境によって完全に管理されます。



例: Docker と Splunk を例にしたアーキテクチャの概要

alt text