メインコンテンツへ移動

Node サービスのデバッグ方法

無料2016-03-27#Node#Node调试#Node调试工具#Node Debugger#node inspector

なぜデバッグが必要なのか?デバッグする場合、どうすればよいのか?

前言

Q:Node はどのようにデバッグしますか?

A:デバッグとは何ですか?

一般的に言う「デバッグ」とは、ステップオーバー、ステップイン、ステップアウトで、ソースコードを 1 行ずつ実行することでしょう。この場合、サーバーサイドプログラムのデバッグと一般的なクライアントプログラム没什么区别で、どちらも実行フロー、コールスタック、変数の現在値などを覗き見したいのです。つまり、Node サービスのデバッグとページ中の JS スクリプトのデバッグ方法は同じです

もちろん、サーバーサイドにはサーバーサイドの特殊性があり、多くのコードはクライアント環境と密接に関連しています。例えば Cookie、Request Header、localStorage などです。1 行ずつデバッグするのは現実的ではないようです。まず、サービスの入力(クライアントリクエスト)はどこから来るのか?リクエストをシミュレートすることも、直接データをシミュレートすることもできます。。。これ以上話すと実はテストの内容で、「デバッグ」ではありません

一.Debugger

Node にはブレーポイントデバッグ、つまり debugger 文が組み込まれています。以下の通り:

// console.js
debugger;

var value = 1;

var fn1 = function() {
debugger;
    value = '2';
    console.log('fn1');
};
var fn2 = function() {
debugger;
    value = 3;
    fn1();
    console.log('fn2');
};

console.log(1);

process.nextTick(function () {
debugger;
    value = 4;
    fn2();
    console.log(2);
});

console.log(3);

ここで debugger; はブレーポイントを設定することを表し、非同期 実行フローもブレーポイントで中断されます。もちろん、debugger はデバッグ環境でのみ有効で、コマンドラインから debug モードに入ります:

node debug ./console.js
// 既に実行中のサービスに対して、そのプロセスに SIGUSR1 シグナルを送信��てデバッグモードに入ることができます
// kill -s USR1 [pid]

その後、プロンプト情報と debug 対話プロンプトが表示されます:

< Debugger listening on port 5858
debug> . ok
break in E:\node\learn\debug\console.js:1
> 1 debugger;
  2
  3 var value = 1;
debug> 

実行フローが 1 行目の debugger; で停止し、カーソルが点滅して入力待ちになります。Node は V8 デバッグコマンドの完全サポートを提供しておらず、使用可能なコマンドは以下の通り:

###1.実行フローの制御

  • c/cont

    次のブレーポイントまで継続して実行

  • n/next

    次の文まで実行

  • s/step

    関数内部にステップイン

  • o/out

    関数内部からステップアウト

  • pause

    実行を一時停止

例えば c を入力すると 1 と 3 が出力され、その後 value = 4; の上一行で停止します。次に n を入力すると value = 4; で停止し、その後 n を入力してから s を入力すると fn2 の関数本体に入り、関数本体の 1 行目で停止します。。。

注意:デバッグコマンドはあまり友好的ではありません。プログラムが全部実行完毕后、さらに c を入力すると、プロセスを kill してデバッグを終了する必要があります

###2.ブレーポイントの設定/クリア

  • sb()/setBreakpoint()

    現在行にブレーポイントを設定

  • sb(line)/...

    line 行目にブレーポイントを設定

  • sb('fn()')/...

    関数本体の先頭にブレーポイントを設定

  • sb('script.js', 1)/...

    script.js ファイルの 1 行目にブレーポイントを設定

  • cb()/clearBeakpoint()

    ブレーポイントをクリア

注意:これらのコマンドは非常に使いにくいので、ソースコード内で debugger; 文を使用してブレーポイントを設定することをお勧めします

###3.状態情報の確認

  • bt/backtrace

    現在のスタック情報を出力

  • list(3)

    現在行の前後各 3 行のソースコードをリスト

  • watch('expr')

    expr を観察リストに追加

  • unwatch('expr')

    観察リストから expr を削除

  • watchers

    観察リスト内のすべての式と値をリスト

  • repl

    デバッグのコンテキストを開き、直接デバッグコードを入力

これらのコマンドは非常に便利です。watch で頻繁に変化する変数/式を監視するか、または repl でデバッグ環境中のデバッグ環境に入り、何を出力することもできます

二.デバッグツール

手動でコマンドを入力するのは面倒なので、デバッグツールがあります:node-inspector。npm でグローバルインストールし、その後直接実行:

E:\node\learn\debug>node-inspector
Node Inspector v0.12.7
Visit http://127.0.0.1:8080/?port=5858 to start debugging.
Cannot send response - there is no front-end connection.

ブラウザ(ブラウザにはBlink 開発者ツールが必要です。例えば Chrome と Opera。FF45 は不可)で http://127.0.0.1:8080/?port=5858 にアクセスしますが、何も表示されません。待って、最後の行にデバッグ対象が見つからないと書かれています。では、プログラムを実行して debug モードに入ります:

node debug ./console.js
// もちろん、プロセスに SIGUSR1 シグナルを送信することもできます
// kill -s USR1 [pid]

その後ブラウザをリフレッシュすると、ページにソースコードが表示され、馴染みのある Dev Tools が表示されます:

(function (exports, require, module, __filename, __dirname) { debugger;

var value = 1;

var fn1 = function() {
debugger;
    value = '2';
    console.log('fn1');
};
var fn2 = function() {
debugger;
    value = 3;
    fn1();
    console.log('fn2');
};

console.log(1);

process.nextTick(function () {
debugger;
    value = 4;
    fn2();
    console.log(2);
});

console.log(3);
});

コードがモジュールでラップされていることがわかります。したがって、デバッグの利点は node ソースコードを覗き見ることができることで、根源を追及したい場合、無限にステップインすれば実行フロー全体を引き出すことができます。同様に、サードパーティモジュール内部の具体的な実行フローも簡単に確認でき、ソースコード分析時に役立ちます

P.S.ここで先に node-inspector を実行したのは、順序は問題ないことを説明するためで、毎回厳密にデバッグ対象のプログラムを先に debug 実行する必要はありません。原理は node が TCP デバッグプロトコルを提供しており、プロトコルを通じてプロセス外部からデバッグでき、node-inspector は該プロトコルを通じてデバッグ対象のプロセスと通信し、debugger コマンドを実行し、Blink 開発者ツールインターフェースを通じて表示します

三.まとめ

実際、コマンドを使用してもツールを使用しても、どちらも比較的面倒だと感じます。そして、なぜデバッグが必要なのでしょうか?

理由としては、筆者は 2 つの状況しか考えられません:

  • コードがぐちゃぐちゃ(奇妙なエラーが発生し、単純な静的分析ではエラー原因が見つからない)

実行フローが分からなくなり、整理する必要がある

  • ソースコードを分析したい

弱タイプの js は定義にジャンスできないため、デバッグを通じてソースコードを分析するのは良い選択です

デバッグは実行中断を引き起こし、オフラインで実行する必要があります。開発中で 1 行ずつ盯着歩く状況は極めて少なく、ユニットテストを通じてコードの堅牢性を保証すべきで、問題が発生するたびにデバッグするべきではありません

サーバーサイドプログラムに対して、ユニットテスト(mocha, should, muk, rewire。内容は比較的多く、後でまた話します)のほか、ログ(pm2 は簡単なエラーログを自带)も非常に必要です。ログを分析してエラー原因を特定し、それに対応するユニットテストケースを見つけて、修復します

参考資料

  • 『深入浅出 NodeJS』

コメント

コメントはまだありません

コメントを書く