Kalan's Blog

Software Engineer / Taiwanese / Life in Fukuoka

Current Theme light

Better-express-error

When developing with express, if an error occurs, it is usually directly printed on the error page or redirected to a 404 or 500 page in production.

Although this may not be worth mentioning, honestly, do you feel happy when you see these kinds of pages?

default error

Engineers familiar with Ruby on Rails development should have used better_errors or the built-in error trace page in Rails itself for debugging.

However, in express, I haven't seen a package similar to better_errors that provides such functionality. Often, we can only see these ugly error messages and feel frustrated.

So, I created a simple middleware to handle this. Essentially, it's an express implementation of better_errors.

Analyzing error messages

TypeError: range out of bound. Please check http://kjj6198.github.io for more information.
at app.get (/Users/kalan/code/express-error/server/app.js:17:9)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/kalan/code/express-error/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/kalan/code/express-error/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)
at /Users/kalan/code/express-error/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/kalan/code/express-error/node_modules/express/lib/router/index.js:335:12)
at next (/Users/kalan/code/express-error/node_modules/express/lib/router/index.js:275:10)
at jsonParser (/Users/kalan/code/express-error/node_modules/body-parser/lib/types/json.js:109:7)
at Layer.handle [as handle_request] (/Users/kalan/code/express-error/node_modules/express/lib/router/layer.js:95:5)

After careful observation, it can be noticed that the format of the error message is quite consistent. First, the first line contains the error name and message, which is usually the most important information. The following lines are the stack trace. "at ..." denotes a function call, and the parentheses contain the filename, line number, and row information.

After analyzing the error message, we can convert the plain text into more useful information. By using split('\n') and simple regular expression matching based on strings, we can extract the filename and line number information.

Displaying the Error

For the first line of the error message, which is usually the most important information since it indicates where the code went wrong, we highlight it and place it in the most prominent position.

better error(1)

For the subsequent lines of the error message, we use colors and font sizes to indicate the filename, line number, and the invoked function.

better error(2)

Compared to the previous block of plain text, this simple organization already allows developers to quickly understand what went wrong.

Displaying File Contents

However, in addition to displaying the error message, it would be helpful to also show the corresponding file contents and the surrounding context. Therefore, on the right side, we can use the filename and line number provided in the error message to display the corresponding file contents.

For Node.js, it is sufficient to use fs.readFileSync.

function(filename, line, row) {
  const content = fs.readFileSync(filename);
  content.toString()
  	.split('\n')
  	.slice(line - 5, line + 5)
  	.map(content => `<span>${content}</span>`)
  	.join('\n');
}

Here, we simply print the five lines before and after the error line. A smarter approach would be to only print the content of the corresponding function using techniques like AST. However, for now, printing the surrounding code is sufficient.

After some adjustments and modifications, it would look something like this:

better error(3)

By highlighting the code, developers can immediately identify where the error occurred.

REPL

In addition to displaying the error, we also want this page to allow input of simple code so that we can confirm the problematic areas and make actual code modifications.

In Node.js, there is a VM module that allows you to execute given code using V8's Virtual Machine contexts. With this module, we can achieve functionality similar to a REPL!

const debugContext = vm.createContext({
  request: req,
  response: res,
  util: require("util"),
  Buffer: require("buffer").Buffer,
  stream: require("stream"),
  console: {
    log: util.format,
  },
  clear: "",
})

By passing the variables we want to expose into the context and then reading the frontend code through a POST request, we can easily achieve the debugging effect.

better error(4)

(Some adjustments are still needed)

All Integrated!

better error(5)

After integrating everything, the page would look something like this.

Compared to the original plain text, although it took some effort to adjust the page style and implement the REPL functionality, it makes the debugging process much smoother.

Conclusion

express-error

The detailed implementation can be found in this repository. If I have some free time in the near future, I will refactor the implementation into a middleware form for easier usage. I will also gradually optimize the overall layout and code highlighting, making the entire process and interface smoother. However, I can't say how long it will take XD

If you have any suggestions, feel free to open an issue.

Prev

React16 Highlights

Next

Carnival Double 11 — Happy Birthday to Me

If you found this article helpful, please consider buy me a drink ☕️ It'll make my ordinary day shine✨

Buy me a coffee

作者

Kalan 頭像照片,在淡水拍攝,淺藍背景

愷開 | Kalan

Hi, I'm Kai. I'm Taiwanese and moved to Japan in 2019 for work. Currently settled in Fukuoka. In addition to being familiar with frontend development, I also have experience in IoT, app development, backend, and electronics. Recently, I started playing electric guitar! Feel free to contact me via email for consultations or collaborations or music! I hope to connect with more people through this blog.