DEV Community

Arijus Gilbrantas
Arijus Gilbrantas

Posted on

1

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. :)

Image of Docusign

Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

11 Tips That Make You a Better Typescript Programmer

typescript

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!