前書き

効果的なロギングソリューションは、アプリケーションの成功にとって重要です。 このガイドでは、https://www.npmjs.com/package/winston [Winston]というロギングパッケージ、非常に汎用性の高いロギングライブラリ、およびhttps://nodejs.orgで利用できる最も一般的なロギングソリューションに焦点を当てます[ Node.js]アプリケーション、NPMダウンロード統計に基づきます。 Winstonの機能には、複数のストレージオプションとログレベル、ログクエリ、さらには組み込みのプロファイラのサポートが含まれます。 このチュートリアルでは、Winstonを使用して、このプロセスの一部として作成するNode / http://expressjs.com/ [Express]アプリケーションをログに記録する方法を示します。 また、Winstonと、https://www.npmjs.com/package/morgan [Morgan]というNode.js用の人気のあるHTTPリクエストミドルウェアロガーを組み合わせて、HTTPリクエストデータログを他の情報と統合する方法についても説明します。

このチュートリアルを完了すると、Ubuntuサーバーで小さなNode / Expressアプリケーションが実行されます。 また、Winstonを実装して、エラーとメッセージをファイルとコンソールに記録します。

前提条件

このガイドを始める前に、次のものが必要です。

これらの前提条件が整っていれば、アプリケーションをビルドしてWinstonをインストールできます。

ステップ1-基本的なNode / Expressアプリの作成

Winstonの一般的な使用法は、Node.jsで構築されたWebアプリケーションからのイベントを記録することです。 Winstonの組み込み方法を完全に示すために、Expressフレームワークを使用して簡単なNode.js Webアプリケーションを作成します。 基本的なWebアプリケーションの実行を支援するために、Nodes / Express Webアプリケーションを実行するためのコマンドラインツールであるhttps://www.npmjs.com/package/express-generator [+ express-generator +]を使用します早く。 前提条件の一部としてhttps://www.npmjs.org [Node Package Manager]をインストールしたため、 `+ npm `コマンドを使用して ` express-generator `をインストールできます。 また、パッケージをグローバルにインストールする ` -g +`フラグを使用して、既存のNodeプロジェクト/モジュールの外部でコマンドラインツールとして使用できるようにします。 次のコマンドでパッケージをインストールします。

sudo npm install express-generator -g

+ express-generator`をインストールしたら、 + express + `コマンドを使用してアプリを作成し、その後にプロジェクトに使用するディレクトリの名前を指定します。 これにより、開始するために必要なすべてのアプリケーションが作成されます。

express myApp

次に、https://www.npmjs.com/package/nodemon [Nodemon]をインストールします。これにより、変更を加えるたびにアプリケーションが自動的にリロードされます。 Node.jsアプリケーションは、それらの変更を有効にするために、ソースコードに変更が加えられるたびに再起動する必要があります。 Nodemonは自動的に変更を監視し、アプリケーションを再起動します。 そして、コマンドラインツールとして「+ nodemon 」を使用できるようにするため、「-g +」フラグを付けてインストールします。

sudo npm install nodemon -g

アプリケーションのセットアップを完了するには、アプリケーションディレクトリに移動し、次のように依存関係をインストールします。

cd myApp
npm install

デフォルトでは、 `+ express-generator`で作成されたアプリケーションはポート3000で実行されるため、ポートがファイアウォールによってブロックされていないことを確認する必要があります。 ポート3000を開くには、次のコマンドを実行します。

sudo ufw allow 3000

これで、Webアプリケーションを起動するために必要なすべてが揃いました。 これを行うには、次のコマンドを実行します。

nodemon bin/www

これにより、ポート3000で実行されているアプリケーションが開始されます。 Webブラウザーで「+ http://:3000+」に移動することで、機能することをテストできます。 このようなものが見えるはずです。

image:https://assets.digitalocean.com/articles/winston_logging_nodejs/winston_log_image_one.png [デフォルトのエクスプレスジェネレーターのホームページ]

この時点で、サーバーへの2番目のSSHセッションを開始してこのチュートリアルの残りの部分で使用し、元のセッションで実行を開始したWebアプリケーションをそのままにしておくことをお勧めします。 この記事の残りの部分では、これまで使用してきたSSHセッションを参照し、現在セッションAとしてアプリケーションを実行しています。 コマンドの実行とファイルの編集に新しいSSHセッションを使用します。このセッションをセッションBと呼びます。 特に注記がない限り、残りのコマンドはすべてセッションBで実行する必要があります。

ステップ2-Node.jsアプリケーションのカスタマイズ

`+ express-generator +`によって作成されたデフォルトのアプリケーションは、私たちが始めるのに非常に役立ち、すべてのHTTPリクエストに関するデータを記録するために使用するMorgan HTTPロギングミドルウェアも含まれています。 また、Morganは出力ストリームをサポートしているため、Winstonに組み込まれているストリームサポートとうまく組み合わせて、HTTPリクエストデータログをWinstonで記録することを選択した他のものと統合できます。

デフォルトでは、 `+ morgan `パッケージを参照するときに、 ` express-generator `ボイラープレートは変数* logger *を使用します。 ロギングパッケージである ` morgan `と ` winston `を使用するため、これらのいずれかを* logger *と呼ぶと混乱する可能性があります。 それでは、プロジェクトのルートにある ` app.js +`ファイルを編集し、いくつかの変更を加えてそれを変更しましょう。

編集のために + app.js`を開くには、 + nano`コマンドを使用します:

nano ~/myApp/app.js

ファイルの上部近くにある次の行を見つけます。

〜/ myApp / app.js

...
var logger = require('morgan');
...

次のように変更してください。

〜/ myApp / app.js

...
var morgan = require('morgan');
...

また、変数* logger *がファイル内で参照された場所を見つけて、それを `+ morgan `に変更する必要があります。 作業中に、 ` morgan `パッケージで使用されるログ形式を ` combined +`に変更します。これは、標準のApacheログ形式であり、リモートIPアドレスやユーザーエージェントなどの有用な情報がログに含まれます。 HTTP要求ヘッダー。

これを行うには、次の行を見つけます。

〜/ myApp / app.js

...
app.use(logger('dev'));
...

次のように変更してください。

〜/ myApp / app.js

...
app.use(morgan('combined'));
...

これらの変更は、Winston構成を統合した後、いつでも参照しているロギングパッケージをよりよく理解するのに役立ちます。

「+ CTRL-X 」、「 Y 」、「 ENTER +」の順に入力して、ファイルを終了して保存します。

これでアプリがセットアップされたので、Winstonで作業を開始する準備が整いました。

手順3-Winstonのインストールと構成

これで、Winstonをインストールして構成する準備ができました。 このステップでは、 `+ winston +`パッケージの一部として利用可能な設定オプションのいくつかを調べ、ファイルとコンソールに情報を記録するロガーを作成します。

`+ winston +`をインストールするには、次のコマンドを実行します。

cd ~/myApp
npm install winston

アプリケーションのあらゆるタイプのサポートまたはユーティリティ設定ファイルを特別なディレクトリに保存しておくと便利な場合が多いので、 `+ winston `設定を含む ` config +`フォルダーを作成しましょう。

mkdir ~/myApp/config

それでは、 `+ winston.js `と呼ぶ ` winston +`設定を含むファイルを作成しましょう。

touch ~/myApp/config/winston.js

次に、ログファイルを含むフォルダーを作成します。

mkdir ~/myApp/logs

最後に、Node.jsでパスを指定するときに役立つパッケージである `+ app-root-path +`をインストールしましょう。 このパッケージはWinstonに直接関連していませんが、Node.jsコードでファイルへのパスを指定する際に非常に役立ちます。 これを使用して、プロジェクトのルートからWinstonログファイルの場所を指定し、andい相対パス構文を回避します。

npm install app-root-path --save

ロギングの処理方法を構成するために必要なものはすべて揃っているため、構成設定の定義に進むことができます。 編集のために `+〜/ myApp / config / winston.js +`を開くことから始めます:

nano ~/myApp/config/winston.js

次に、 + app-root-path`と + winston`パッケージが必要です:

〜/ myApp / config / winston.js

var appRoot = require('app-root-path');
var winston = require('winston');

これらの変数を設定すると、transports_の構成設定を定義できます。 トランスポートは、ログに使用されるストレージ/出力メカニズムを参照するWinstonによって導入された概念です。 Winstonには、_console _、 file HTTP_の3つのコアトランスポートが付属しています。 このチュートリアルでは、コンソールとファイルトランスポートに焦点を当てます。コンソールトランスポートはコンソールに情報を記録し、ファイルトランスポートは指定されたファイルに情報を記録します。 各トランスポート定義には、ファイルサイズ、ログレベル、ログ形式などの独自の構成設定を含めることができます。 各トランスポートで使用する設定の概要は次のとおりです。

  • * level *-ログに記録するメッセージのレベル。

  • * filename *-ログデータの書き込みに使用するファイル。

  • * handleExceptions *-未処理の例外をキャッチして記録します。

  • * json *-ログデータをJSON形式で記録します。

  • * maxsize *-新しいファイルが作成される前のログファイルの最大サイズ(バイト単位)。

  • * maxFiles *-ログファイルのサイズを超えたときに作成されるファイルの数を制限します。

  • * colorize *-出力を色付けします。 これは、コンソールログを見るときに役立ちます。

_ロギングレベル_はメッセージの優先度を示し、整数で示されます。 Winstonは、0から5(最高から最低)の優先順位が付けられた `+ npm +`ロギングレベルを使用します。

  • * 0 *:エラー

  • * 1 *:警告

  • * 2 *:情報

  • * 3 *:詳細

  • * 4 *:デバッグ

  • * 5 *:愚かな

特定のトランスポートのログレベルを指定すると、そのレベル以上のログが記録されます。 たとえば、レベル「+ info 」を指定すると、レベル「 error」、「+ warn」、または「+ info」のすべてがログに記録されます。 ログレベルは、ロガーを呼び出すときに指定されます。つまり、次のようにしてエラーを記録できます: + logger.error( 'test error message')+

次のように、 + winston`設定の + file`および `+ console`トランスポートの設定を定義できます:

〜/ myApp / config / winston.js

...
var options = {
 file: {
   level: 'info',
   filename: `${appRoot}/logs/app.log`,
   handleExceptions: true,
   json: true,
   maxsize: 5242880, // 5MB
   maxFiles: 5,
   colorize: false,
 },
 console: {
   level: 'debug',
   handleExceptions: true,
   json: false,
   colorize: true,
 },
};

次に、 `+ options `変数で定義されたプロパティを使用して、ファイルとコンソールのトランスポートで新しい ` winston +`ロガーをインスタンス化します。

〜/ myApp / config / winston.js

...
var logger = new winston.Logger({
 transports: [
   new winston.transports.File(options.file),
   new winston.transports.Console(options.console)
 ],
 exitOnError: false, // do not exit on handled exceptions
});

デフォルトでは、「+ morgan 」はコンソールにのみ出力するため、「 morgan 」で生成された出力を「 winston 」ログファイルに取得できるストリーム関数を定義しましょう。 出力が両方のトランスポート(ファイルとコンソール)によって取得されるように、 ` info +`レベルを使用します。

〜/ myApp / config / winston.js

...
logger.stream = {
 write: function(message, encoding) {
   logger.info(message);
 },
};

最後に、アプリケーションの他の部分で使用できるようにロガーをエクスポートします。

〜/ myApp / config / winston.js

...
module.exports = logger;

完成した `+ winston +`設定ファイルは次のようになります。

〜/ myApp / config / winston.js

var appRoot = require('app-root-path');
var winston = require('winston');

// define the custom settings for each transport (file, console)
var options = {
 file: {
   level: 'info',
   filename: `${appRoot}/logs/app.log`,
   handleExceptions: true,
   json: true,
   maxsize: 5242880, // 5MB
   maxFiles: 5,
   colorize: false,
 },
 console: {
   level: 'debug',
   handleExceptions: true,
   json: false,
   colorize: true,
 },
};

// instantiate a new Winston Logger with the settings defined above
var logger = new winston.Logger({
 transports: [
   new winston.transports.File(options.file),
   new winston.transports.Console(options.console)
 ],
 exitOnError: false, // do not exit on handled exceptions
});

// create a stream object with a 'write' function that will be used by `morgan`
logger.stream = {
 write: function(message, encoding) {
   // use the 'info' log level so the output will be picked up by both transports (file and console)
   logger.info(message);
 },
};

module.exports = logger;

ファイルを終了して保存します。

ロガーを構成しましたが、アプリケーションはまだロガーまたはその使用方法を認識していません。 ロガーをアプリケーションに統合します。

ステップ4-Winstonとアプリケーションの統合

ロガーをアプリケーションで動作させるには、 `+ express `にそれを認識させる必要があります。 ステップ2で、 ` express `設定が ` app.js`にあることを既に見たので、ロガーをこのファイルにインポートしましょう。 以下を実行して、編集するファイルを開きます。

nano ~/myApp/app.js

他のrequireステートメントを使用して、ファイルの上部近くに `+ winston +`をインポートします。

〜/ myApp / app.js

...
var winston = require('./config/winston');
...

最初に実際に「+ winston 」を使用するのは、「 morgan 」です。 ` stream `オプションを使用し、 ` winston +`設定の一部として作成したストリームインターフェースに設定します。 これを行うには、次の行を見つけます。

〜/ myApp / app.js

...
app.use(morgan('combined'));
...

これに変更してください。

〜/ myApp / app.js

...
app.use(morgan('combined', { stream: winston.stream }));
...

ファイルを終了して保存します。

ログデータを表示する準備ができました! Webブラウザーでページをリロードすると、SSHセッションAのコンソールに次のようなものが表示されます。

Output[nodemon] restarting due to changes...
[nodemon] starting `node bin/www`
info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:29:36 +0000] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"

info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:29:37 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://167.99.4.120:3000/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"

ここには2つのログエントリがあります。1つ目はHTMLページへのリクエスト用で、2つ目は付随するスタイルシート用です。 各トランスポートは「+ info 」レベルのログデータを処理するように設定されているため、「〜/ myApp / logs / app.log 」にあるファイルトランスポートにも同様の情報が表示されるはずです。 ただし、ファイルトランスポート構成で ` json:true +`を指定したため、ファイルトランスポートの出力はJSONオブジェクトとして記述する必要があります。 JSONの詳細については、https://www.digitalocean.com/community/tutorials/an-introduction-to-json [JSONチュートリアルの紹介]をご覧ください。 ログファイルの内容を表示するには、次のコマンドを実行します。

tail ~/myApp/logs/app.log

次のようなものが表示されるはずです。

{"level":"info","message":"::ffff:72.80.124.207 - - [07/Mar/2018:17:29:36 +0000] \"GET / HTTP/1.1\" 304 - \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\"\n","timestamp":"2018-03-07T17:29:36.962Z"}
{"level":"info","message":"::ffff:72.80.124.207 - - [07/Mar/2018:17:29:37 +0000] \"GET /stylesheets/style.css HTTP/1.1\" 304 - \"http://167.99.4.120:3000/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\"\n","timestamp":"2018-03-07T17:29:37.067Z"}

これまでのところ、ロガーはHTTPリクエストと関連データのみを記録しています。 これはログに記録する非常に重要な情報ですが、カスタムログメッセージをどのように記録しますか? たとえば、エラーの記録やデータベースクエリパフォーマンスのプロファイリングなどにこの機能が必要な場合があります。 これを行う方法を説明するために、エラーハンドラールートからロガーを呼び出しましょう。

`+ express-generator `パッケージには、デフォルトで404および500エラーハンドラールートが含まれているため、これを使用します。 `〜/ myApp / app.js +`ファイルを開きます:

nano ~/myApp/app.js

ファイルの下部で次のようなコードブロックを見つけます。

〜/ myApp / app.js

...
// error handler
app.use(function(err, req, res, next) {
 // set locals, only providing error in development
 res.locals.message = err.message;
 res.locals.error = req.app.get('env') === 'development' ? err : {};

 // render the error page
 res.status(err.status || 500);
 res.render('error');
});
...

これは、最終的にエラー応答をクライアントに送り返す最終的なエラー処理ルートです。 すべてのサーバー側エラーはこのルートを介して実行されるため、これは `+ winston +`ロガーを含めるのに適した場所です。

現在エラーを処理しているため、 `+ error`ログレベルを使用します。 繰り返しますが、両方のトランスポートは `+ error`レベルのメッセージを記録するように設定されているため、コンソールとファイルのログに出力が表示されます。 必要なものはすべてログに含めることができるため、次のような役立つ情報を必ず含めてください。

  • * err.status *-HTTPエラーステータスコード。 まだ存在しない場合は、デフォルトで500になります。

  • * err.message *-エラーの詳細。

  • * req.originalUrl *-要求されたURL。

  • * req.path *-リクエストURLのパス部分。

  • * req.method *-リクエストのHTTPメソッド(GET、POST、PUTなど)。

  • * req.ip *-要求のリモートIPアドレス。

エラーハンドラールートを更新して、次と一致するようにします。

〜/ myApp / app.js

...
// error handler
app.use(function(err, req, res, next) {
 // set locals, only providing error in development
 res.locals.message = err.message;
 res.locals.error = req.app.get('env') === 'development' ? err : {};

 // add this line to include winston logging
 winston.error(`${err.status || 500} - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`);

 // render the error page
 res.status(err.status || 500);
 res.render('error');
});
...

ファイルを終了して保存します。

これをテストするために、プロジェクト内の存在しないページにアクセスしてみてください。404エラーがスローされます。 Webブラウザーに戻り、次のURLをロードしてください: + http://:3000 / foo +。 アプリケーションは、 `+ express-generator +`によって作成されたボイラープレートのおかげで、そのようなエラーに応答するように既に設定されています。 ブラウザには、次のようなエラーメッセージが表示されます(エラーメッセージは、表示されているものよりも詳細な場合があります)。

image:https://assets.digitalocean.com/articles/winston_logging_nodejs/winston_log_image_two.png [ブラウザエラーメッセージ]

次に、SSHセッションAのコンソールをもう一度見てください。 エラーのログエントリが必要です。色付け設定のおかげで、簡単に見つけることができます。

Output[nodemon] starting `node bin/www`
: 404 - Not Found - /foo - GET - ::ffff:72.80.124.207
info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:40:11 +0000] "GET /foo HTTP/1.1" 404 985 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"

info: ::ffff:72.80.124.207 - - [07/Mar/2018:17:40:11 +0000] "GET /stylesheets/style.css HTTP/1.1" 304 - "http://167.99.4.120:3000/foo" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"

ファイルロガーに関しては、 `+ tail +`コマンドを再度実行すると、新しいログレコードが表示されます:

tail ~/myApp/logs/app.log

次のようなメッセージが表示されます。

{"level":"error","message":"404 - Not Found - /foo - GET - ::ffff:72.80.124.207","timestamp":"2018-03-07T17:40:10.622Z"}

エラーメッセージには、エラーステータス(404-見つかりません)、要求されたURL(localhost / foo)、要求メソッド(GET)など、エラーハンドラーの一部としてログに記録するように具体的に指示したすべてのデータが含まれます。要求を行うIPアドレス、および要求が行われたときのタイムスタンプ。

結論

このチュートリアルでは、単純なNode.js Webアプリケーションを構築し、アプリケーションのパフォーマンスに関する洞察を提供する効果的なツールとして機能するWinstonロギングソリューションを統合しました。 特にニーズが複雑になるにつれて、アプリケーションの堅牢なログソリューションを構築するためにさらに多くのことができます。 時間をかけて、これらの他のドキュメントのいくつかを確認することをお勧めします。

  • Winstonトランスポートの詳細については、https://github.com/winstonjs/winston/blob/master/docs/transports.md [Winston Transports Documentation]を参照してください。

  • 独自のトランスポートの作成の詳細については、https://www.npmjs.com/package/winston#adding-custom-transports [カスタムトランスポートの追加]を参照してください。

  • HTTPコアトランスポートで使用するHTTPエンドポイントを作成するには、https://www.npmjs.com/package/winstond [+ winstond +]を参照してください。

  • Winstonをプロファイリングツールとして使用するには、https://www.npmjs.com/package/winston#profiling [プロファイリング]を参照してください。