ツイートしてて自己完結してしまったので記録のために。
あーそういや今更だけど、stdoutとstderrはまとめてlogging driverに渡されちゃうのか。どちらなのかはdriverには渡っているのでfluentdに出せばラベル付いてるので、ログのことだけ考えれば仕組み的にはどちらに出しても扱うこと自体には問題が無さそう。
— Aki (@nekoruri) June 22, 2019
デーモンアプリケーションで想定外のエラーが出うるのであれば、構造化ログをstdoutという分離は全然ありうると思う。
— Aki (@nekoruri) June 22, 2019
でもそうしちゃうとエコシステムから外れちゃうので、やっぱり最大公約数としてはparseableなテキストでstdout/stderrかなあという気がしてきた。やはりDockerにfile descripterの概念が欲しい。チャンネル2個じゃ足りない。
— Aki (@nekoruri) June 22, 2019
理想論はさておき、現実的にはやはりコンソールアプリならstderr、デーモンアプリケーションならstdoutに構造化ログ(JSON)を出してlogging driverで振り分けてparse、stderrは想定外の非構造化エラーログに備える、が万能そう。
— Aki (@nekoruri) June 22, 2019
Dockerを使う最大のメリットは、その「踏み込んだ割り切り」という制約によるエコシステムなので、エコシステムから外れた時点で負けなんだよなあ……。Railsで車輪ガン無視しても別にアプリ書けるけどそれRailsじゃなくていいよねって話と同じ。
— Aki (@nekoruri) June 22, 2019
前提と考察
- Unixの世界では、stdout(標準出力)とstderr(標準エラー出力)という二つの出力チャンネルが標準として提供されている。
- Twelve-Factor Appでは、アプリケーション側はログをイベントストリームとして出力し、実行環境側のほうで開発環境であればstdout、運用環境ならばfluentdなどに送って処理するべきとされている。
- 近年[要出典]のログは、そもそも古臭いNCSA combinedアクセスログのような複雑怪奇な正規表現で取り出すようなテキストではなく、最初からJSONやLTSVなど構造化されたデータとして扱われるべきものである。
- Dockerではコンテナのログをlogging driverという仕組みで処理し、stdoutとstderrを1行1エントリとしてloggin driverに送る。logging driverは標準出力なりFluentdなりAWS CloudWatch Logsなりに送る。
- コンソールアプリでパイプ使う場合は、docker runに-aでstdoutだけ出力できるので、きちんとやる必要があれば出力はstdoutでパイプにつなぎ、ログはstderr経由でloggin driver送り、という使い分けができそう(未確認)
参考リンク
sourceでstdoutかstderrか取れる。