DEV Community

Arijus Gilbrantas
Arijus Gilbrantas

Posted on

Make useful JS/TS errors in AWS Lambda

I have been playing with custom errors and how it can help with monitoring AWS lambda based APIs.

The native Error of JavaScript is kinda meh. You can only set a message, which, I find, is not enough to determine an issue in production, i.e. ‘http request failed’. What I would love to know is some context, at least: url, headers, payload, response.

I have tried to stringify error context and attach to an error message, but it was difficult to read the logs and therefore didn't spark joy.

Ultimately, I would prefer not to look at the logs at all, the monitoring tool should tell me what's wrong and maybe even give a solution. Got better things to do, than debugging logs :)))

Error does not like serialisation.

try {
  throw new Error("Something bad happened");
} catch (err) {
  const serialised = JSON.stringify(err);
  console.log(serialised);
}
Enter fullscreen mode Exit fullscreen mode

outputs:

{}
Enter fullscreen mode Exit fullscreen mode

Let's serialise the Error

So what we could do is to create an BaseError, which has a property reason.

export class BaseError extends Error {
    public readonly reason: string;

    constructor(reason: string) {
        super(reason);
        this.name = BaseError.name;
        Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain

        this.reason = reason;
    }
}
Enter fullscreen mode Exit fullscreen mode

now when we run this:

try {
  throw new BaseError("Something bad happened");
} catch (err) {
  let serialised = JSON.stringify(err);
  console.log(serialised);
}
Enter fullscreen mode Exit fullscreen mode

we get

{"name":"BaseError","reason":"Something bad happened"}
Enter fullscreen mode Exit fullscreen mode

Let's make a custom Error

So once we have a BaseError, we can create an purpose built error like that:

export class SuperHeroError extends BaseError {
  public readonly superHeroName: string;

  constructor(superHeroName: string) {
    super(`superhero ${superHeroName} malfunctioned`);
    this.name = SuperHeroError.name;
    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain

    this.superHeroName = superHeroName;
  }
}
Enter fullscreen mode Exit fullscreen mode

and when we run it:

try {
  throw new SuperHeroError("Batman");
} catch (err) {
  let serialised = JSON.stringify(err);
  console.log(serialised);
}
Enter fullscreen mode Exit fullscreen mode

we get this:

{"name":"SuperHeroError","reason":"superhero Batman malfunctioned","superHeroName":"Batman"}
Enter fullscreen mode Exit fullscreen mode

AWS CloudWatch LogInsights report

Once we have some failure logs, we can write a query like this:

fields @timestamp as timestamp, name, reason
| sort @timestamp desc
| limit 100
Enter fullscreen mode Exit fullscreen mode

and the result will be:

timestamp name reason
2020-07-23 12:59:30.716 SuperHeroError superhero Batman malfunctioned

This is very basic error logging, in the real world you will need much more data in the logs, like sessionId, requestId etc. :)

Top comments (0)