From 6d4f2ad4581296a34c2fdb57dbdb64ac503751fe Mon Sep 17 00:00:00 2001 From: g-tejas Date: Wed, 26 Jun 2024 13:01:24 +0800 Subject: [PATCH] feat(errors): revamp business logic error codes --- src/app/modules/core/core.errors.ts | 30 +++++++++++++++++-- src/app/modules/form/form.errors.ts | 2 +- .../public-form/public-form.controller.ts | 9 ++++++ .../email-submission.controller.ts | 1 + 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/app/modules/core/core.errors.ts b/src/app/modules/core/core.errors.ts index 995fe73015..d7e72dec05 100644 --- a/src/app/modules/core/core.errors.ts +++ b/src/app/modules/core/core.errors.ts @@ -1,3 +1,11 @@ +import tracer from 'dd-trace' + +import { statsdClient } from 'src/app/config/datadog-statsd-client' + +export const errorStatsdClient = statsdClient.childClient({ + prefix: 'formsg.errors.', +}) + /** * A custom base error class that encapsulates the name, message, status code, * and logging meta string (if any) for the error. @@ -7,8 +15,15 @@ export class ApplicationError extends Error { * Meta object to be logged by the application logger, if any. */ meta?: unknown - - constructor(message?: string, meta?: unknown) { + code?: number + isError?: boolean + + constructor( + message?: string, + meta?: unknown, + errorCode?: number, + isError?: boolean, + ) { super() Error.captureStackTrace(this, this.constructor) @@ -18,6 +33,17 @@ export class ApplicationError extends Error { this.message = message || 'Something went wrong. Please try again.' this.meta = meta + this.code = errorCode + this.isError = isError + } +} + +export const setErrorCodes = (error: ApplicationError) => { + const span = tracer.scope().active() + if (span) { + span.setTag('error', error.isError || false) + span.setTag('error.code', error.code) + span.setTag('error.message', error.message) } } diff --git a/src/app/modules/form/form.errors.ts b/src/app/modules/form/form.errors.ts index 5ef8cdc8cc..e1ee130a03 100644 --- a/src/app/modules/form/form.errors.ts +++ b/src/app/modules/form/form.errors.ts @@ -29,7 +29,7 @@ export class PrivateFormError extends ApplicationError { message = 'If you think this is a mistake, please contact the agency that gave you the form link.', formTitle: string, ) { - super(message) + super(message, undefined, 1001, false) this.formTitle = formTitle } } diff --git a/src/app/modules/form/public-form/public-form.controller.ts b/src/app/modules/form/public-form/public-form.controller.ts index e30fec669b..a809c2a403 100644 --- a/src/app/modules/form/public-form/public-form.controller.ts +++ b/src/app/modules/form/public-form/public-form.controller.ts @@ -19,6 +19,7 @@ import { isMongoError } from '../../../utils/handle-mongo-error' import { createReqMeta, getRequestIp } from '../../../utils/request' import { getFormIfPublic } from '../../auth/auth.service' import * as BillingService from '../../billing/billing.service' +import { errorStatsdClient, setErrorCodes } from '../../core/core.errors' import { ControllerHandler } from '../../core/core.types' import { MYINFO_AUTH_CODE_COOKIE_NAME, @@ -96,6 +97,14 @@ export const handleGetPublicForm: ControllerHandler< } const { errorMessage, statusCode } = mapRouteError(error) + errorStatsdClient.increment('', 1, { + code: `${error?.code}`, + message: error.message, + }) + + // Add error code tags to the active span for datadog + setErrorCodes(error) + // Specialized error response for PrivateFormError. // This is to maintain backwards compatibility with the middleware implementation if (error instanceof PrivateFormError) { diff --git a/src/app/modules/submission/email-submission/email-submission.controller.ts b/src/app/modules/submission/email-submission/email-submission.controller.ts index 2cc6f73dde..432d15c38e 100644 --- a/src/app/modules/submission/email-submission/email-submission.controller.ts +++ b/src/app/modules/submission/email-submission/email-submission.controller.ts @@ -1,3 +1,4 @@ +import tracer from 'dd-trace' import { ok, okAsync, ResultAsync } from 'neverthrow' import {