diff --git a/lib/entities/aws-metrics-logger.ts b/lib/entities/aws-metrics-logger.ts index 7f40caa7..9528ec9b 100644 --- a/lib/entities/aws-metrics-logger.ts +++ b/lib/entities/aws-metrics-logger.ts @@ -37,6 +37,10 @@ export class AWSMetricsLogger implements IMetric { } } +export enum MetricDimension { + METHOD = 'method', +} + export enum Metric { QUOTE_200 = 'QUOTE_200', QUOTE_400 = 'QUOTE_400', @@ -46,6 +50,7 @@ export enum Metric { QUOTE_REQUESTED = 'QUOTE_REQUESTED', QUOTE_LATENCY = 'QUOTE_LATENCY', QUOTE_RESPONSE_COUNT = 'QUOTE_RESPONSE_COUNT', + HANDLER_DURATION = 'HANDLER_DURATION', QUOTE_POST_ERROR = 'QUOTE_POST_ERROR', QUOTE_POST_ATTEMPT = 'QUOTE_POST_ATTEMPT', diff --git a/lib/handlers/base/api-handler.ts b/lib/handlers/base/api-handler.ts index e778d6c1..70fa499c 100644 --- a/lib/handlers/base/api-handler.ts +++ b/lib/handlers/base/api-handler.ts @@ -9,7 +9,7 @@ import { import { default as bunyan, default as Logger } from 'bunyan'; import Joi from 'joi'; -import { Metric } from '../../entities'; +import { Metric, MetricDimension } from '../../entities'; import { CustomError, ErrorCode } from '../../util/errors'; import { BaseHandleRequestParams, BaseInjector, BaseLambdaHandler, BaseRInj } from './base'; @@ -88,22 +88,30 @@ export abstract class APIGLambdaHandler< } get handler(): APIGatewayProxyHandler { - return async (event: APIGatewayProxyEvent, context: Context): Promise => { - const handler = this.buildHandler(); + return metricScope( + (metric: MetricsLogger) => + async (event: APIGatewayProxyEvent, context: Context): Promise => { + const requestStart = new Date().getTime(); + const handler = this.buildHandler(); + const response = await handler(event, context); + const requestEnd = new Date().getTime(); - const response = await handler(event, context); + // Track handler duration + metric.putDimensions({ [MetricDimension.METHOD]: this.handlerName }); + metric.putMetric(Metric.HANDLER_DURATION, requestEnd - requestStart, MetricLoggerUnit.Milliseconds); - return { - ...response, - headers: { - ...response.headers, - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', - 'Access-Control-Allow-Credentials': true, - 'Content-Type': 'application/json', - }, - }; - }; + return { + ...response, + headers: { + ...response.headers, + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', + 'Access-Control-Allow-Credentials': true, + 'Content-Type': 'application/json', + }, + }; + } + ); } protected buildHandler(): APIGatewayProxyHandler { @@ -187,10 +195,12 @@ export abstract class APIGLambdaHandler< ({ body, statusCode } = handleRequestResult); } } catch (err) { - log.error({ err }, 'Unexpected error in handler'); if (err instanceof CustomError) { - return err.toJSON(id); + const errorJson = err.toJSON(id); + log.error({ errorJson }, 'Unexpected error in handler'); + return errorJson; } + log.error({ err }, 'Unexpected error in handler'); metric.putMetric(Metric.QUOTE_500, 1, MetricLoggerUnit.Count); return INTERNAL_ERROR(id); } @@ -236,10 +246,10 @@ export abstract class APIGLambdaHandler< log: Logger ): Promise< | { - state: 'valid'; - requestBody: ReqBody; - requestQueryParams: ReqQueryParams; - } + state: 'valid'; + requestBody: ReqBody; + requestQueryParams: ReqQueryParams; + } | { state: 'invalid'; errorResponse: APIGatewayProxyResult } > { /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ diff --git a/package.json b/package.json index ac7d4173..0ca3d6a5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "typescript": "^4.8.4" }, "dependencies": { - "@aws-cdk/aws-redshift-alpha": "^2.54.0-alpha.0", + "@aws-cdk/aws-redshift-alpha": "^2.85.0-alpha.0", "@aws-sdk/client-dynamodb": "^3.386.0", "@aws-sdk/client-firehose": "^3.490.0", "@aws-sdk/client-redshift-data": "^3.382.0", diff --git a/yarn.lock b/yarn.lock index b26ef8d5..4c19f172 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,10 +30,10 @@ resolved "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.166.tgz#467507db141cd829ff8aa9d6ea5519310a4276b8" integrity sha512-j0xnccpUQHXJKPgCwQcGGNu4lRiC1PptYfdxBIH1L4dRK91iBxtSQHESRQX+yB47oGLaF/WfNN/aF3WXwlhikg== -"@aws-cdk/aws-redshift-alpha@^2.54.0-alpha.0": - version "2.54.0-alpha.0" - resolved "https://registry.yarnpkg.com/@aws-cdk/aws-redshift-alpha/-/aws-redshift-alpha-2.54.0-alpha.0.tgz#eac9251cdb6939b2848191b42cc33f326a29917d" - integrity sha512-7/bxH6KMLArBfgJxiylNaz8NLV1EHcxa/kLctUK9xRBsn40DobZ/mIZxXc0keCK/siTKwv9i5qiGQ7l0YvJHOA== +"@aws-cdk/aws-redshift-alpha@^2.85.0-alpha.0": + version "2.85.0-alpha.0" + resolved "https://registry.yarnpkg.com/@aws-cdk/aws-redshift-alpha/-/aws-redshift-alpha-2.85.0-alpha.0.tgz#1231c32eb288516c5e5901e81009f5fe1d185839" + integrity sha512-oBXABcEWtVn8yPYR4wOoufdZe8J+nyvy3j0u2l8Gr5GXGQsRgSKWicqFjDid8vwfsX3xh5m26QclXsPWXsm6mw== "@aws-crypto/crc32@3.0.0": version "3.0.0"