From 386b02aff53418916a2c2f791bde2b927ee69179 Mon Sep 17 00:00:00 2001 From: Donovan Hutchinson Date: Wed, 27 Nov 2019 15:32:12 +0000 Subject: [PATCH 1/2] Initial notes Updating notes WIP Moving things around Adding diag report Updating text --- child-processes/index.md | 2 +- diagnostics/basic-performance-analysis.md | 1 - diagnostics/count.js | 16 ++ diagnostics/debugging-node_js.md | 1 - diagnostics/index.md | 197 +++++++++++++++++++++- 5 files changed, 212 insertions(+), 5 deletions(-) delete mode 100644 diagnostics/basic-performance-analysis.md create mode 100644 diagnostics/count.js delete mode 100644 diagnostics/debugging-node_js.md diff --git a/child-processes/index.md b/child-processes/index.md index a833758..d76500c 100644 --- a/child-processes/index.md +++ b/child-processes/index.md @@ -5,7 +5,7 @@ url: child-processes author: ian --- -_Prerequisites: [events](../events), [streams](../buffers-and-streams)_ +_Prerequisites: [events]({{ "/events/" | url }}), [streams]({{ "/buffers-and-streams/" | url }})_ The typical operating system has different processes running in the background, and each process is being managed by a single-core of our CPU and will run a series of calculations each time it is being ticked. To take full advantage of our CPU using a single process, we would need a number of processes that is at least equal to the number of cores in our CPU. In addition, each process might be responsible for running a series of calculations of different logic, which will give the end user a better control over the CPU’s behavior. diff --git a/diagnostics/basic-performance-analysis.md b/diagnostics/basic-performance-analysis.md deleted file mode 100644 index b0d572b..0000000 --- a/diagnostics/basic-performance-analysis.md +++ /dev/null @@ -1 +0,0 @@ -# Basic Performance Analysis diff --git a/diagnostics/count.js b/diagnostics/count.js new file mode 100644 index 0000000..6fe677a --- /dev/null +++ b/diagnostics/count.js @@ -0,0 +1,16 @@ +function count() { + for (let i = 1; i < 4; i++) { + debugger; + if (i > 2) { + throw 'Wait, I counted too far!' + } + console.log(i + ' hahaha'); + } +} + +function startACount() { + console.log('I will now begin to count...') + count(); +} + +startACount(); diff --git a/diagnostics/debugging-node_js.md b/diagnostics/debugging-node_js.md deleted file mode 100644 index 71c11ad..0000000 --- a/diagnostics/debugging-node_js.md +++ /dev/null @@ -1 +0,0 @@ -# Debugging Node.js \ No newline at end of file diff --git a/diagnostics/index.md b/diagnostics/index.md index 4a57846..bafe1a7 100644 --- a/diagnostics/index.md +++ b/diagnostics/index.md @@ -1,8 +1,201 @@ --- layout: default title: Diagnostics +author: donovan +date: 1903-10-09 --- -Coming soon. +In this lesson we will take a look at ways we can diagnose issues in our code. To do this we'll use the built-in Node.js debugger, as well as the Chrome dev tools. -In the meantime, please see https://github.com/nodejs/diagnostics \ No newline at end of file +After this lesson you should be confident investigating errors in a methodical fashion, without relying on `console.log` so much. + +## Node.js Debugger + +Node pack a useful [built-in debugging](https://nodejs.org/api/debugger.html) tool. Let's try using it to debug a script and find out what is causing a thrown error using the command line approach first. + +To begin we create a JavaScript file locally called `count.js` containing the following: + +``` +function count() { + for (let i = 1; i < 4; i++) { + debugger; + if (i > 2) { + throw 'Wait, I counted too far!' + } + console.log(i + ' hahaha'); + } +} + +function startACount() { + console.log('I will now begin to count...') + count(); +} + +startACount(); +``` + +When we run this using `node count` (the `.js` is optional) in our command line tool it outputs an uncaught error: + +``` +I will now begin to count... +1 hahaha +2 hahaha + +/count.js:5 + throw 'Wait, I counted too far!' + ^ +Wait, I counted too far! +``` + +Something has gone wrong! Let's use the debugger tool to find out what. + +### The `debugger` command + +In the above code you might have noticed the `debugger;` code on line 3. During normal operation this is ignored, but we can make use of this by running `inspect`: + +``` +node inspect count +``` + +This will enter `debug` mode where we can use command to inspect what is going on. + +Firstly we can use `list()` to take a look at the place in the code we are currently exectuting. At first it'll be on line 16 `startACount()`. All good so far. We can then continue using `cont` to continue exectuting until we reach the break point. + +By entering the continue (`cont`) command we should now see: + +``` + 1 function count() { + 2 for (let i = 1; i < 4; i++) { +> 3 debugger; + 4 if (i > 2) { + 5 throw 'Wait, I counted too far!' +``` + +We have paused execution at this point. Now we can delve deeper and inspect some of our code to see what is going on. To begin, we jump into the Node REPL by using the command `repl`. + +This then lets us access the code directly. Type `i` to log the value for that variable: + +``` +debug> repl +Press Ctrl + C to leave debug repl +> i +1 +``` + +This shows that we have the value "1" stored in `i`. This is fine, so we then leave the REPL with `Cmd+C` and continue with `cont`. + +Repeating the above shows `i` is now "2". Continue one more time. The value of `i` should now be "3". + +The error hasn't thrown yet but we can carefully approach it by using `next`. This command steps through the lines one at a time. + +Using `next` we should see the `if` statement, then a second `next` takes us to the `throw` statement: + +``` +debug> next +break in count.js:5 + 3 debugger; + 4 if (i > 2) { +> 5 throw 'Wait, I counted too far!' + 6 } + 7 console.log(i + ' hahaha'); + ``` + +So we've managed to get to the moment when the script fails. Enter the `repl` command one last time and type `i`. We now see that it contains the value "3". Checking the `if` statement above, we can see why this now hits the `throw` statement. + +You can quit the debugger by typing `.exit` or by pressing `Cmd+C` twice. + +## Debugging using Node.js with Chrome DevTools + +We don't just need the command line to debug our code. We can also make use of Chrome's debugging tools to help navigate our code. + +``` +node --inspect index.js +``` + +The above runs the inspector, but in our case it throws an error, so we can have it pause on exectution to give us time to step through the code by using: + +``` +node --inspect-brk count.js +``` + +This will run the Chrome inspector and tell it to pause on any break points (`debugger;`). + +It now gives us a URL. We can ignore this and instead, open Chrome and put in the address: `about:inspect`. + +On this page we should see a link to our `count.js` process as it is currently running. Clicking the `inspect` link opens the `DevTools` window. We can then begin running the script within our DevTools window by pressing the blue _Resume_ button on the top right. + +This should cause the script to reach our `debugger;` line as follows: + +TODO: IMAGE: A screenshot of the DevTools showing the debugger line highlighted. + +Beside the blue _Resume_ button you'll find controls to step through the code, by stepping over the next function call, step into and out of functions and step forward line by line. + +We can also select the line numbers to toggle temporary breakpoints, to help drill down on specific areas of the code. These are listed under `Breakpoints` on the right panel. + +On the right panel you can also manage _Watchers_ and more. + +You can select `Console` in the tabs to see the output of the logs as we step through the code. + +### Debugging our error + +One approach will be to highlight line `4` in our code (click on the line number to highlight it with a blue background), then press the blue _Resume_ button until the execution pauses on the `if` statement. + +You can hover your mouse cursor over the `i` to see what value it contains (you can slso see this information on the right panel under `Scope`). + +Repeat pressing the _Resume_ button until `i` contains "3". Pressing _Resume_ again causes the code to disappear as it has encounted the error. We can see the error in our command line. + +### Worker threads + +Chrome DevTools doesn't support debugging [worker threads]({{ "/child-processes/" | url }}) yet. We can handle these using [ndb](https://github.com/GoogleChromeLabs/ndb). + +## Debugging with ndb + +You can install `ndb` globally by running: + +``` +npm install ndb -g +``` + +If you are using MacOS and encounter an error (`gyp: No Xcode or CLT version detected!`) you may need to install XCode or run: + +``` +sudo xcode-select -r +``` + +Then you can run `ndb` against the code with: + +``` +ndb count +``` + +This will download Chromium and present a similar view to before, albeit wrapped in a slightly smoother package. + +You can debug the code as above, adding breakpoints as needed, hovering over the variables to see their values, and much more. + +Find more information on [debugging using ndb](https://github.com/GoogleChromeLabs/ndb). + +## Generating diagnostic reports + +Sometimes we need more information to work out what is going on. To help with this, we can make use of Node's built-in [diagnostic report](https://nodejs.org/api/report.html) feature. + +To create the report, we can run the following command against out `count.js` file above: + +``` +node --report-uncaught-exception count.js +``` + +This generates a report in JSON that you can read to try to work out what has happened. + +It includes a lots of information on the JavaScript and native stack traces, heap statistics, platform information, resource usage and local environmental variables. + +Along with debugging the error messages from the script, this can be helpful in determining the state of the application when an uncaught exception occurred. + +With the report option enabled, diagnostic reports can be triggered on unhandled exceptions, fatal errors and user signals, in addition to triggering programmatically through API calls. Read more on the official [diagnostic report docs page](https://nodejs.org/api/report.html). + +### Homework + +Feel free to try moving the `debugger;` statement around in the above. You can also try using the `help` command in the `debug` mode to see other options. + +Try breaking the code and then using the `debug` mode to narrow down the issue. Inspecting variables using the REPL can be helpful to find logic errors or catch situations where variables contain unexpected values. + +Try out the same exercise using the Chrome devtools and see how it differs. By being familiar with each you will find it easier to know what tools to use to debug any issues in future. \ No newline at end of file From 30ebfe01ae7ab247563cb58794d3d8dc42e8da03 Mon Sep 17 00:00:00 2001 From: Donovan Hutchinson Date: Thu, 10 Jun 2021 16:14:50 +0100 Subject: [PATCH 2/2] Updating to use post type --- diagnostics/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/diagnostics/index.md b/diagnostics/index.md index bafe1a7..eefbd55 100644 --- a/diagnostics/index.md +++ b/diagnostics/index.md @@ -1,8 +1,8 @@ --- -layout: default +layout: post title: Diagnostics author: donovan -date: 1903-10-09 +date: 2021-06-10 --- In this lesson we will take a look at ways we can diagnose issues in our code. To do this we'll use the built-in Node.js debugger, as well as the Chrome dev tools.