diff --git a/runtime/fundamentals/debugging.md b/runtime/fundamentals/debugging.md index d0dcff5bb..1af8382ab 100644 --- a/runtime/fundamentals/debugging.md +++ b/runtime/fundamentals/debugging.md @@ -126,6 +126,143 @@ curl http://0.0.0.0:4507/ At this point we can introspect the contents of the request and go step-by-step to debug the code. +## Inspecting network traffic + +Starting with Deno 2.8, Chrome DevTools can inspect network traffic made by your +program in the same way it inspects traffic in a browser tab. Run your program +with `--inspect-wait` (or `--inspect` / `--inspect-brk`), open +`chrome://inspect` in a Chromium derived browser, click **Inspect** on the Deno +target, and switch to the **Network** tab. + +The following built-in APIs are wired into the Network tab: + +- `fetch()` — requests appear with `Type: fetch` +- `node:http` and `node:https` client requests (`http.request`, `http.get`, + `https.request`, `https.get`) — the **Type** column reflects the response + content-type (e.g. `json`, `document`), so any npm library that issues HTTP + requests through `node:http` shows up alongside `fetch()` traffic +- `WebSocket` — client connections appear alongside HTTP requests, with + handshake status and headers from the upgrade response, message frames, and a + close event when the socket is closed +- `Deno.upgradeWebSocket()` — server-side WebSocket upgrades are instrumented + too, so you can inspect both sides of a connection from a Deno-to-Deno + handshake + +For each request you can see the URL, method, status code, request and response +headers, request and response bodies, and timing information. + +Let's try it with a small program that uses `fetch()`: + +```ts title="net.ts" +const res = await fetch("https://api.github.com/repos/denoland/deno"); +console.log(res.status, (await res.json()).stargazers_count); +``` + +Run it with `--inspect-wait` so the program pauses until DevTools connects: + +```sh +$ deno run --inspect-wait --allow-net net.ts +Debugger listening on ws://127.0.0.1:9229/... +Visit chrome://inspect to connect to the debugger. +Deno is waiting for debugger to connect. +``` + +Open `chrome://inspect`, click **Inspect** on the Deno target, and switch to the +**Network** tab. The `fetch()` request shows up as a regular network entry, with +the request and response panes populated: + +![fetch() request in the Network tab](./images/debugger-network-fetch.png) + +Click a request to see its headers, payload, response body, and timing +breakdown: + +![Inspecting response headers and body](./images/debugger-network-response.png) + +The same applies to `node:http` and `node:https`, so npm libraries that issue +HTTP requests through Node's built-in client (rather than `fetch()`) also show +up in the Network tab. For example: + +```ts title="node-http.ts" +import https from "node:https"; + +const options = { + hostname: "api.github.com", + path: "/repos/denoland/deno", + headers: { "User-Agent": "deno-docs-example" }, +}; + +https.get(options, (res) => { + let body = ""; + res.on("data", (chunk) => body += chunk); + res.on( + "end", + () => console.log(res.statusCode, JSON.parse(body).stargazers_count), + ); +}); +``` + +```sh +$ deno run --inspect-wait --allow-net node-http.ts +``` + +The request appears in the Network tab with the same headers, body, and timing +information as a `fetch()` request — the **Type** column reflects the response +content-type (`json` for this example): + +![node:https request in the Network tab](./images/debugger-network-node-http.png) + +`WebSocket` connections appear in the same Network tab, with messages and the +close event surfaced as the connection progresses: + +![WebSocket connection in the Network tab](./images/debugger-network-websocket.png) + +Server-side WebSockets created with `Deno.upgradeWebSocket()` are also +instrumented, so you can inspect both sides of a connection — the outgoing +client `WebSocket` and the server upgrade that accepts it. For example, a small +echo server: + +```ts title="ws-server.ts" +Deno.serve({ port: 8000 }, (req) => { + if (req.headers.get("upgrade") !== "websocket") { + return new Response("send a WebSocket request", { status: 426 }); + } + const { socket, response } = Deno.upgradeWebSocket(req); + socket.onmessage = (e) => socket.send(`echo: ${e.data}`); + return response; +}); +``` + +```sh +$ deno run --inspect-wait --allow-net ws-server.ts +``` + +After connecting DevTools and resuming execution, connect to the server from +another terminal (for example with `deno eval`): + +```sh +deno eval 'const ws = new WebSocket("ws://localhost:8000"); + ws.onopen = () => ws.send("hello"); + ws.onmessage = (e) => { console.log(e.data); ws.close(); };' +``` + +The upgrade and the message frames show up in the Network tab of the server's +DevTools session: + +![Deno.upgradeWebSocket() in the Network tab](./images/debugger-network-upgrade-websocket.png) + +The same events are also exposed through `node:inspector` for programmatic +clients, so tooling that already speaks the Chrome DevTools Protocol against +Node can attach to Deno and observe the same network traffic without any +changes. + +:::note + +When no debugger is attached, the network instrumentation has effectively no +overhead — the events are only emitted while a session has opted in via +`Network.enable`. + +::: + ## VSCode Deno can be debugged using VSCode. This is best done with help from the official diff --git a/runtime/fundamentals/images/debugger-network-fetch.png b/runtime/fundamentals/images/debugger-network-fetch.png new file mode 100644 index 000000000..e4c32b790 Binary files /dev/null and b/runtime/fundamentals/images/debugger-network-fetch.png differ diff --git a/runtime/fundamentals/images/debugger-network-node-http.png b/runtime/fundamentals/images/debugger-network-node-http.png new file mode 100644 index 000000000..913e4aba5 Binary files /dev/null and b/runtime/fundamentals/images/debugger-network-node-http.png differ diff --git a/runtime/fundamentals/images/debugger-network-response.png b/runtime/fundamentals/images/debugger-network-response.png new file mode 100644 index 000000000..144c01433 Binary files /dev/null and b/runtime/fundamentals/images/debugger-network-response.png differ diff --git a/runtime/fundamentals/images/debugger-network-upgrade-websocket.png b/runtime/fundamentals/images/debugger-network-upgrade-websocket.png new file mode 100644 index 000000000..ae82ad230 Binary files /dev/null and b/runtime/fundamentals/images/debugger-network-upgrade-websocket.png differ diff --git a/runtime/fundamentals/images/debugger-network-websocket.png b/runtime/fundamentals/images/debugger-network-websocket.png new file mode 100644 index 000000000..b2deeb695 Binary files /dev/null and b/runtime/fundamentals/images/debugger-network-websocket.png differ