Nodeには標準でデバッグ機能が搭載されています。
server.js
var http = require('http');
http.createServer(function(rq, rs) {
rs.writeHead(200, {'Content-Type': 'text/plain'});
rs.end('Hello Debugger!');
}).listen(3000, 'localhost');
console.log('サーバーが起動しました: http://localhost:3000/');
デバッグモードで起動するには、nodeコマンドにdebugオプションをつけます。
node debug filePath
$ node debug server.js
< debugger listening on port 5858
connecting... ok
break in server.js:1
1 var http = require('http');
2
3 http.createServer(function(rq, rs) {
debug>
debug> で入力待ちの状態になります。
break in server.js:1
は、止まっている位置を示しています。server.jsの1行目で処理が中断しています。
1 var http = require('http');
2
3 http.createServer(function(rq, rs) {
は、中断している位置周辺のコードが表示されます。
この状態のまま、ブラウザから http://localhost:3000/ にアクセスすると、接続できないはずです。
server.js の1行目で処理が中断しているので、6行目のlisten関数が実行されておらず、ウェブサーバが起動していないためです。
処理を再開するには、debug> で「c」と入力します。
debug> c
< サーバーが起動しました: http://localhost:3000/
debug>
「サーバーが起動しました」の出力があり、「break in server.js:N」の表示もありません。server.jsの最終行まで実行されています。ブラウザからアクセスすると、Hello Debugger! と表示されるはずです。
server.jsを修正し、クライアントからリクエストを受け取ったところで止めてみます。
var http = require('http');
http.createServer(function(rq, rs) {
debugger; // 追加。リクエストがきたら止める。
rs.writeHead(200, {'Content-Type': 'text/plain'});
rs.end('Hello Debugger!');
}).listen(3000, 'localhost');
console.log('サーバーが起動しました: http://localhost:3000/');
デバッグモードで実行してみます。
$ node debug server.js
< debugger listening on port 5858
connecting... ok
break in server.js:1
1 var http = require('http');
2
3 http.createServer(function(rq, rs) {
debug%gt; c
< サーバーが起動しました: http://localhost:3000/
debug<
「c」でサーバーが起動したら、ブラウザからアクセスしてみます。処理が完了しないはずです。
デバッガが起動しており、4行目で処理が中断しています。
(続き)
< サーバーが起動しました: http://localhost:3000/
break in server.js:4
2
3 http.createServer(function(rq, rs) {
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
debug>
インスタンス rq の中身を知るには、repl を使います。
(続き)
debug> repl
Press Ctrl + C to leave debug repl
>
replが起動します。REPL(Read-Eval-Print-Loop)は、読込→評価→表示を繰り返す対話型評価環境のこと。rubyやphythonなんかで使われています。
rqの中身を表示するには、rqと打ってReturnします。
> rq
{ httpVersion: '1.1',
method: 'GET',
headers:
{ 'cache-control': 'max-age=0',
'accept-encoding': 'gzip, deflate',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, lik... (length: 119)',
'accept-language': 'ja-jp',
accept: 'text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8',
connection: 'keep-alive',
host: 'localhost:3000' },
client:
(ズラーリ)
}
>
ポイントを絞ってHTTPヘッダだけ表示してみます。
> rq.headers
{ 'cache-control': 'max-age=0',
'accept-encoding': 'gzip, deflate',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.51.22 (KHTML, lik... (length: 119)',
'accept-language': 'ja-jp',
accept: 'text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8',
connection: 'keep-alive',
host: 'localhost:3000' }
>
いい具合です。
REPLを抜けるにはCtrl+Cです。
中断している行がわからない場合、bt, listコマンドを使います。
debug> list()
1 var http = require('http');
2
3 http.createServer(function(rq, rs) {
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
7 }).listen(3000, 'localhost');
8
9 console.log('サーバーが起動しました: http://localhost:3000/');
debug> bt
#0 server.js:4:5
debug>
listは、中断しているコードの前後を表示します。表示された行の真ん中が、現在の行です。(例では、1行目が近いので、実際どこかわかりません。)
btは、現在の行、スタックを表示します。(例では4行目で止まっていることがわかります。)
ウオッチリストを追加しています。
watchでウオッチ追加、unwatchでウオッチ削除、watchersでウオッチの一覧を表示します。
rs.finishedを監視に加え、nコマンドで一行進めます。
(続き)
debug> watch('rs.finished')
debug> n
break in server.js:5
Watchers:
0: rs.finished = false
3 http.createServer(function(rq, rs) {
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
7 }).listen(3000, 'localhost');
debug>
行が1行進んで5行目に、ウオッチリストと値が表示されます。
nを続けてみます。
(続き)
debug> n
break in server.js:6
Watchers:
0: rs.finished = false
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
7 }).listen(3000, 'localhost');
8
debug> n
break in server.js:7
Watchers:
0: rs.finished = true
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
7 }).listen(3000, 'localhost');
8
9 console.log('サーバーが起動しました: http://localhost:3000/');
debug>
7行目で、rs.finishedがtrueに変化しました。
ウオッチを削除してみます。
debug> watchers
0: rs.finished = true
debug> unwatch(0)
debug> watchers
debug>
現在の行にブレークポイントを追加してみます。sbコマンドを使います。
debug> sb()
2
3 http.createServer(function(rq, rs) {
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
* 7 }).listen(3000, 'localhost');
8
9 console.log('サーバーが起動しました: http://localhost:3000/');
10
11
12 });
debug>
「*」印がついて7行目にブレークポイントが設定されました。
「c」で継続して、再度ブラウザからアクセスしてみます。
debug> c
break in server.js:4
2
3 http.createServer(function(rq, rs) {
4 debugger;
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
debug> c
break in server.js:7
5 rs.writeHead(200, {'Content-Type': 'text/plain'});
6 rs.end('Hello Debugger!');
* 7 }).listen(3000, 'localhost');
8
9 console.log('サーバーが起動しました: http://localhost:3000/');
debug>
4行目のdebuggerで一度止まります。c で継続するとブレークポイントの7行目まで処理が飛びます。
こんな感じでデバッグできます。より詳しいデバッグコマンドは、公式リファレンスを参考に。