なぜあなたのノードですか?JSアプリケーションのログルーティングを処理しない?


当初公開coreycleary.me . これは私のコンテンツブログからのクロスポストです.私は新しいコンテンツを毎週または2sign up to my newsletter あなたの受信トレイに直接私の記事を受信したい場合は!私も定期的にチートシートや他の景品を送信します.
It is not the responsibility of the application to route logs.

12 Factor says that logs should go to STDOUT. WAT? WHY?

I just configured my whole application code to write logs to custom log files. What's wrong with that?

ロギングは、時々開発者のための黒い箱でありえるそれらのもののうちの1つです.多分、あなたはあなたのために基盤を記録することを気にする専用のdevops人を持っているかもしれません、あるいは、多分、それは物事のこの側で働いているあなたの最初です.
それは、あなたがコードを書くことに忙しすぎている間、世話をするために最後まで去るそれらのもののうちの1つでありえます.多くのことを行うには、“ベストプラクティス”のログを回避するだけで無視することができます何かのように見える場合は、最初の場所でも理解してください.
私たちは、あなたのアプリケーションからあなたのログを切り離すベストプラクティスの背後にある理由を解読し、実際にどこにログインすべきかを見てみます.そして、このポストの目的のために、「ログルーティング」-タイトルで参照されるように-あなたのアプリケーションまたはアプリケーション・プロセスでない意図されたロギング目標に、拾い上げて、ログを押すことを指します.

ベストプラクティス


あなたは、現代のスケーラブルなアプリケーションを作成する周りの標準的な“ベストプラクティス”ドキュメントと見なされている前に、12因子アプリの前に聞いたことがあります.
から12 Factor App best practices regarding logs "
A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout.... In staging or production deploys, each process’ stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment.

それは解読するのにたくさんあるので、それを壊しましょう.
"A twelve-factor app never concerns itself with routing or storage of its output stream."

あなたがログコードのルーティングを処理するためにあなたのアプリケーションコードを望まない最初の主な理由は、懸念の分離のためです.私たちはしばしばサービスの間のコードの断片とサービス自身の間でこの分離を考えます、しかし、これは同様により「インフラストラクチャー」コンポーネントにも当てはまります.アプリケーションコードはインフラストラクチャによって処理されるべきものを処理してはなりません.
以下のコードは非常に結合されたアプリケーションコードの例です.
const { createLogger, transports, winston } = require('winston');
const winston-mongodb = require('winston-mongodb');

// log to two different files
const logger = createLogger({
  transports: [
    new transports.File({ filename: 'combined.log' }),

  ],
  exceptionHandlers: [
    new transports.File({ filename: 'exceptions.log' })
  ]
});

// log to MongoDB
winston.add(winston.transports.MongoDB, options);
展開環境については、しばらくの間それを見てみましょう.
ちょうどアプリケーションがログを処理することによって、それは今その翼の下で別の“懸念”に撮影している.ログ出力が何であるかを定義することによって、アプリケーションは現在、両方のアプリケーション/ビジネスロジックとログロジックを処理します.
あなたのロギング場所を後で変更する必要がある場合はどうですか?それは別のコードの変更と展開(そして、あなたが激しいQA/変更制御/展開プロセスを持っている場合).そして、もしあなたがログファイルの名前を間違って取得?再び、別のコードの変更と展開.
これは、アプリケーションがログを記録し、ログ文を避けるために極端なスタンスを取るべきではないということではありません.
次は
"It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout." (Side note: although it specifically mentions `stdout`, I take it to mean `stdout` and `stderr`, and cursory Google searches seem to confirm this.)

私はすでにファイルやデータベースのような出力にログオンする理由は、懸念の視点の分離から良い実践ではない上で既に議論した.しかし、これは環境懸念が対処され始めるところです.
ノードで.JSアプリケーションは、まだ何かにログインしているコンソールconsole.log() or console.error() ).
ボンネットの下にあるコンソールはstdout for console.log() and stderr for console.error() , したがって、単にこのモジュールを使用することによって、私たちがこのテストに合格するように見えます.
そして、このテストは理由のために存在します:あなたが以前に身体的であるか仮想(しかし、コンテナ/雲でない)サーバーで働いたならば、あなたは彼らの一握りだけを持っていたかもしれません、あるいは、少なくともログファイル、彼らの場所と他のセットアップを手動で構成するのに十分管理されていたサイズ.
今すぐあなたのアプリケーションはいくつかの大きな成功を収めていると想像して、新しいユーザーの何百ものオンボードです.あなたのチームは雲ベースの環境に移行し始めました、そして、あなたは1つのインスタンスから50までオンデマンドをあなたのアプリケーションスケーリングに計画しなければなりません.これらのインスタンスが実行されている場所を知りませんので、正確にログファイルがどこに書き込まれるかを制御できません.
持っている方が役に立つstream | target , 対照的にtarget -> (your routing solution) -> target . ストリームは、我々は強力なパイプラインを組み合わせて、どこにパイプに能力を与える.Linux/Unixを使ったことがあるなら、単にファイル内のテキストを検索するように、ストリームを一緒にパイピングするだけで強力な操作を構築できます.cat example.txt | grep sometext . stdout/stderr あなたにこの力を与えます.たとえば、パイプからstdout あなたが望むならば、ログファイルに.
さらに、クラウド・アプリケーションは一時的である.彼らはスピン、スピンダウン、クラッシュなどを記録することができます.
そこで、アプリケーションがファイル/データベース/他の永続的なストレージターゲットにルーティングログを処理してはならない理由を見始めましたが、これは問題を引き起こします.
次は
"In staging or production deploys, each process’ stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead are completely managed by the execution environment."

これは、その質問に答えることができます.実行環境がstdOUT/stdERRログからこのルーティングをするならば、永続的な保管(そして、あなたは、実際に、絶対的になければならない)にログを発送するのはOKです.
これはまた、以前にカバーされた懸念の分離を再確認します.私たちはログファイルがどこで終わるかもわからない.そして、コンテナがクラッシュして、ログファイルが最初にログルータで拾われていないならば、あなたはねじ込みました.あなたのアプリケーションが最初にクラッシュした理由をデバッグしている幸運.
しかし、どのように生産のログを管理するのですか?何かを送られるものを拾う道具はありますかstdout/stderr ?
これは実際にログルーティング部分が入っているところです.この投稿は、アプリケーションのコード内からの処理からあなたを失望させようとしています.
シンプルのために、あなたが使用していると仮定Docker クラウド環境の一部としてコンテナを.Dockerホスト上で動作するDockerデーモン-あなたのコンテナーではありません-デフォルトではログをstdout/stderr あなたの容器から.
Dockerデーモンをロギングドライバを使用するように設定します.これは、実際のログルーティング作業を行います.
daemon.json ファイル
{
  "log-driver": "splunk", // just using Splunk as an example, it could be another storage type
  "log-opts": {
    "splunk-token": "",
    "splunk-url": "",
    ...
  }
}
ログのドライバのリストを表示することができます-もう一度、ログを拾う仕事を行うし、それらをルーティング- Dockerhere . このリストには、greylog、splunk、syslog、および他のログアグリゲーターがあります.
ログをどこかにルーティングすることは重要です.アプリケーションがクラッシュした場合、スケーリングアップで起動し、スケーリングダウンしてシャットダウンすると、永続的なストレージの場所が表示されます.
しかし、これが上で議論された理由のためにインフラストラクチャレベルでされることは、重要です.
ここで議論されていることに基づく完全なロギング画像は次のようになります.

ラッピング


その理由を要約するには、アプリケーションからのルーティングや、拡張子によってstdout/stderr :
  • アプリケーションのコードからログルーティングの責任を保つ
  • コードクリーナー
  • 展開せずにログルーティングの場所を変更する
  • スケーリングアプリケーション/コンテナは、ログファイルを制御するのが難しいことを意味します
  • また、スケーリングアプリケーションは、それらがより一時的であることを意味します
  • ファイルまたはデータベースを言うstdout/stderr これらのログターゲットにあなたをダウンして、パイプの出力に柔軟性を取りますstdout/stderr あなたが望むどんな目標にでも
  • あなたが持つかもしれない1つの最後の質問に対処するために:あなたがクラウド環境またはコンテナを使用していないならば、どうですか?
    私のこの考えは次の通りです.私がここに置いたアプローチはまだ役に立ちます.
  • ある日、物理的または仮想的なサーバーからクラウド/コンテナーのアプローチに移行することができます.そして、マイグレーションパスを自分自身や仕事をしているチームでより簡単にします
  • あなたは、まだ懸念のその分離を保ちます
  • ログファイルや他の永続的なストレージターゲットに` stdout `をパイプするだけで、Dockerデーモンが提供するのと同じ利点を得ることができます
  • ロギングフレームワークを使用することを決定している場合は、現在のログコードをログオンまたは再実行する作業に取り組んでいるconsole.log() and console.error() , 私はそれにポストを書いたthat can help you make the decision here . ちょっとこのポストを心に留めておくようにしてくださいstdout/stderr あなたが絶対に何か他に書く理由がない限り、ロギングフレームワークから.
    私はノードとJavaScriptを理解しやすくするために多くの新しいコンテンツを書いています.より簡単に、私は時々それが複雑である必要があると思いません.あなたがこのポストを楽しんで、それが役に立つとわかるならばhere's that link again 私のニュースレターを購読するには!