|
| 1 | +import {Fn} from "aws-cdk-lib" |
| 2 | +import {Unit} from "aws-cdk-lib/aws-cloudwatch" |
| 3 | +import { |
| 4 | + MetricFilter, |
| 5 | + FilterPattern, |
| 6 | + IFilterPattern, |
| 7 | + ILogGroup |
| 8 | +} from "aws-cdk-lib/aws-logs" |
| 9 | +import {Topic} from "aws-cdk-lib/aws-sns" |
| 10 | +import {TypescriptLambdaFunction} from "@nhsdigital/eps-cdk-constructs" |
| 11 | +import {Construct} from "constructs" |
| 12 | +import {MetricAlarm} from "../constructs/MetricAlarm" |
| 13 | + |
| 14 | +export interface AlarmsProps { |
| 15 | + readonly stackName: string |
| 16 | + readonly enableAlerts: boolean |
| 17 | + readonly functions: {[key: string]: TypescriptLambdaFunction} |
| 18 | +} |
| 19 | + |
| 20 | +export class Alarms extends Construct { |
| 21 | + public constructor(scope: Construct, id: string, props: AlarmsProps) { |
| 22 | + super(scope, id) |
| 23 | + |
| 24 | + const createMetricFilter = ( |
| 25 | + metricFilterId: string, |
| 26 | + metricFilterProps: { |
| 27 | + filterName: string |
| 28 | + filterPattern: IFilterPattern |
| 29 | + logGroup: ILogGroup |
| 30 | + metricNamespace: string |
| 31 | + metricName?: string |
| 32 | + metricValue?: string |
| 33 | + unit?: Unit |
| 34 | + dimensions?: {[key: string]: string} |
| 35 | + } |
| 36 | + ) => new MetricFilter(this, metricFilterId, { |
| 37 | + ...metricFilterProps, |
| 38 | + metricName: metricFilterProps.metricName ?? "ErrorCount", |
| 39 | + metricValue: metricFilterProps.metricValue ?? "1", |
| 40 | + unit: metricFilterProps.unit ?? Unit.COUNT |
| 41 | + }) |
| 42 | + |
| 43 | + const slackAlertTopic = Topic.fromTopicArn( |
| 44 | + this, |
| 45 | + "SlackAlertsTopic", |
| 46 | + Fn.importValue("lambda-resources:SlackAlertsSnsTopicArn") |
| 47 | + ) |
| 48 | + |
| 49 | + const getMyPrescriptionsFunction = props.functions.getMyPrescriptions.function |
| 50 | + const enrichPrescriptionsFunction = props.functions.enrichPrescriptions.function |
| 51 | + |
| 52 | + createMetricFilter("ServiceSearchErrorsLogsMetricFilter", { |
| 53 | + filterName: "ServiceSearchErrors", |
| 54 | + filterPattern: FilterPattern.literal( |
| 55 | + `{ ($.level = "ERROR") && ($.function_name = "${getMyPrescriptionsFunction.functionName}") ` + |
| 56 | + "&& $.message = %error in request to serviceSearch% }" |
| 57 | + ), |
| 58 | + logGroup: getMyPrescriptionsFunction.logGroup, |
| 59 | + metricNamespace: "LambdaLogFilterMetrics", |
| 60 | + metricName: "ServiceSearchErrorCount", |
| 61 | + dimensions: { |
| 62 | + FunctionName: "$.function_name" |
| 63 | + } |
| 64 | + }) |
| 65 | + |
| 66 | + new MetricAlarm(this, "ServiceSearchErrors", { |
| 67 | + stackName: props.stackName, |
| 68 | + enableAlerts: props.enableAlerts, |
| 69 | + namespace: "LambdaLogFilterMetrics", |
| 70 | + alarmDefinition: { |
| 71 | + name: "ServiceSearch_Errors", |
| 72 | + metric: "ServiceSearchErrorCount", |
| 73 | + description: "Count of Service Search errors", |
| 74 | + dimensions: { |
| 75 | + FunctionName: getMyPrescriptionsFunction.functionName |
| 76 | + } |
| 77 | + }, |
| 78 | + slackAlertTopic |
| 79 | + }) |
| 80 | + |
| 81 | + new MetricAlarm(this, "ServiceSearchUnhandledErrors", { |
| 82 | + stackName: props.stackName, |
| 83 | + enableAlerts: props.enableAlerts, |
| 84 | + namespace: "Lambda", |
| 85 | + alarmDefinition: { |
| 86 | + name: "ServiceSearch_UnhandledErrors", |
| 87 | + metric: "Errors", |
| 88 | + description: "Count of Service Search unhandled errors", |
| 89 | + dimensions: { |
| 90 | + FunctionName: getMyPrescriptionsFunction.functionName |
| 91 | + } |
| 92 | + }, |
| 93 | + slackAlertTopic |
| 94 | + }) |
| 95 | + |
| 96 | + createMetricFilter("GetMyPrescriptionsErrorsLogsMetricFilter", { |
| 97 | + filterName: `${props.stackName}_GetMyPrescriptionsErrors`, |
| 98 | + filterPattern: FilterPattern.literal( |
| 99 | + `{ ($.level = "ERROR") && ($.function_name = "${getMyPrescriptionsFunction.functionName}") ` + |
| 100 | + "&& ($.message != %error in request to serviceSearch%) }" |
| 101 | + ), |
| 102 | + logGroup: getMyPrescriptionsFunction.logGroup, |
| 103 | + metricNamespace: "LambdaLogFilterMetrics", |
| 104 | + dimensions: { |
| 105 | + FunctionName: "$.function_name" |
| 106 | + } |
| 107 | + }) |
| 108 | + |
| 109 | + new MetricAlarm(this, "GetMyPrescriptionsErrors", { |
| 110 | + stackName: props.stackName, |
| 111 | + enableAlerts: props.enableAlerts, |
| 112 | + namespace: "LambdaLogFilterMetrics", |
| 113 | + alarmDefinition: { |
| 114 | + name: "GetMyPrescriptions_Errors", |
| 115 | + metric: "ErrorCount", |
| 116 | + description: "Count of GetMyPrescriptions errors", |
| 117 | + dimensions: { |
| 118 | + FunctionName: getMyPrescriptionsFunction.functionName |
| 119 | + } |
| 120 | + }, |
| 121 | + slackAlertTopic |
| 122 | + }) |
| 123 | + |
| 124 | + createMetricFilter("EnrichPrescriptionsErrorsLogsMetricFilter", { |
| 125 | + filterName: `${props.stackName}_EnrichPrescriptionsErrors`, |
| 126 | + filterPattern: FilterPattern.literal("ERROR"), |
| 127 | + logGroup: enrichPrescriptionsFunction.logGroup, |
| 128 | + metricNamespace: "LambdaLogFilterMetrics", |
| 129 | + metricName: `${props.stackName}EnrichPrescriptionsErrorCount` |
| 130 | + }) |
| 131 | + |
| 132 | + new MetricAlarm(this, "EnrichPrescriptionsErrors", { |
| 133 | + stackName: props.stackName, |
| 134 | + enableAlerts: props.enableAlerts, |
| 135 | + namespace: "LambdaLogFilterMetrics", |
| 136 | + alarmDefinition: { |
| 137 | + name: "EnrichPrescriptions_Errors", |
| 138 | + metric: `${props.stackName}EnrichPrescriptionsErrorCount`, |
| 139 | + description: "Count of EnrichPrescriptions errors" |
| 140 | + }, |
| 141 | + slackAlertTopic |
| 142 | + }) |
| 143 | + } |
| 144 | +} |
0 commit comments