DEV Community

Sam Clark
Sam Clark

Posted on

Horrible Howto - Attach A Stack To Debug

So, a few years ago in my infancy of learning how to use Javascript, I came upon a situation where I really wanted to learn how to attach the function name and file name to my functions. At the time, I do not think I really understood the concept of stack traces, and the value of an error.

The Circumstance

Assume if you will the following:

  1. You are early in the development cycle of a cloud function(e.g. lambda)
  2. Deploying your function takes some time, and so every time you do run it, you want as much valid feedback from it.
  3. Because you are deploying a cloud function your ability to inspect it via a debugger is severely limited. You need to be able to show some breakpoints, or at least WHERE your function is breaking.

Here it comes......the debug module....

The basis of the debug module is that we can turn on debugging with an environment variable, and then turn it off! That hits all the check boxes. We don't have to run it in production, and it's somewhat limited.

Starting Out

Let's start by declaring a few variables and debugs per the documentation:

blah.js:

const v = require('debug')('verbose');

v('test');

Now if we were to pass the environment variable DEBUG=verbose, we would end up with something like:

verbose test +0ms

We get a nice timer on the end of it to, with some colors if you're using it locally.

Building the Stack

Unfortunately Javascript does not actually carry a stack globally(much like glibc I have come to find out). The cheapest way to get the stack history is to actually drop the function into an error status. This shouldn't be a problem with our proposed use cases, because we are using this for debugging purposes.

const buildStack = () => {
  const depth = 3;
  if (!this.stackIs) {
    Object.defineProperty(this, 'stackIs', {
      get: function() {
        const orig = Error.prepareStackTrace;
        Error.prepareStackTrace = function(_, stack) {
          return stack;
        };
        const err = new Error();
        Error.captureStackTrace(err, arguments.callee);
        const stack = err.stack;
        Error.prepareStackTrace = orig;
        return stack;
      },
    });
  }

  if (!this.lineIs) {
    Object.defineProperty(this, 'lineIs', {
      get: function() {
        return this.stackIs[depth].getLineNumber();
      },
    });
  }

  if (!this.functionIs) {
    Object.defineProperty(this, 'functionIs', {
      get: function() {
        return this.stackIs[depth].getFunctionName();
      },
    });
  }

  return {
    function: this.functionIs,
    line: this.lineIs,
  };
};

We use the nice revealing pattern to print out an object with where our debug, and voila! We now have really awesome debugging!

of debugging

Total Snippet here

Sources: stack overflow

Latest comments (0)