locals { lambda_alarm_matrix = { errors = { metric_name = "Errors" statistic = "Sum" threshold = 0 comparison = "GreaterThanThreshold" period = 300 } throttles = { metric_name = "Throttles" statistic = "Sum" threshold = 0 comparison = "GreaterThanThreshold" period = 300 } } lambda_alarms = { for pair in flatten([ for fn_key, fn in local.functions : [ for metric_key, metric in local.lambda_alarm_matrix : { key = "${fn_key}-${metric_key}" function = fn.function_name metric_key = metric_key metric_name = metric.metric_name statistic = metric.statistic threshold = metric.threshold comparison = metric.comparison period = metric.period alarm_name = "${fn.function_name}-${metric_key}" description = "${fn.function_name} ${metric_key}" } ] ]) : pair.key => pair } } resource "aws_cloudwatch_metric_alarm" "lambda_errors_throttles" { for_each = local.lambda_alarms alarm_name = each.value.alarm_name alarm_description = each.value.description namespace = "AWS/Lambda" metric_name = each.value.metric_name dimensions = { FunctionName = each.value.function } statistic = each.value.statistic period = each.value.period evaluation_periods = 1 threshold = each.value.threshold comparison_operator = each.value.comparison treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "lambda_duration" { for_each = local.functions alarm_name = "${each.value.function_name}-duration" alarm_description = "${each.value.function_name} approaching timeout (~80% of ${each.value.timeout}s)" namespace = "AWS/Lambda" metric_name = "Duration" dimensions = { FunctionName = each.value.function_name } statistic = "Maximum" period = 300 evaluation_periods = 1 threshold = each.value.duration_ms comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "ddb_read_throttle" { alarm_name = "payments-dashboard-table-read-throttle" alarm_description = "PaymentsDashboard table read requests throttled" namespace = "AWS/DynamoDB" metric_name = "ReadThrottleEvents" dimensions = { TableName = aws_dynamodb_table.dashboard.name } statistic = "Sum" period = 300 evaluation_periods = 1 threshold = 0 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "ddb_write_throttle" { alarm_name = "payments-dashboard-table-write-throttle" alarm_description = "PaymentsDashboard table write requests throttled" namespace = "AWS/DynamoDB" metric_name = "WriteThrottleEvents" dimensions = { TableName = aws_dynamodb_table.dashboard.name } statistic = "Sum" period = 300 evaluation_periods = 1 threshold = 0 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "api_5xx" { alarm_name = "payments-dashboard-api-5xx" alarm_description = "payments-dashboard HTTP API returned 5xx responses" namespace = "AWS/ApiGateway" metric_name = "5xx" dimensions = { ApiId = aws_apigatewayv2_api.http.id } statistic = "Sum" period = 300 evaluation_periods = 1 threshold = 0 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "api_4xx" { alarm_name = "payments-dashboard-api-4xx" alarm_description = "payments-dashboard HTTP API elevated 4xx responses" namespace = "AWS/ApiGateway" metric_name = "4xx" dimensions = { ApiId = aws_apigatewayv2_api.http.id } statistic = "Sum" period = 300 evaluation_periods = 1 threshold = 10 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "api_latency" { alarm_name = "payments-dashboard-api-latency-p99" alarm_description = "payments-dashboard HTTP API p99 latency elevated (>3s)" namespace = "AWS/ApiGateway" metric_name = "Latency" dimensions = { ApiId = aws_apigatewayv2_api.http.id } extended_statistic = "p99" period = 300 evaluation_periods = 1 threshold = 3000 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] } resource "aws_cloudwatch_metric_alarm" "process_csv_dlq" { alarm_name = "payments-processPaymentCsv-async-dlq-messages" alarm_description = "Failed processPaymentCsv async invocations landed in the DLQ" namespace = "AWS/SQS" metric_name = "ApproximateNumberOfMessagesVisible" dimensions = { QueueName = aws_sqs_queue.process_csv_dlq.name } statistic = "Maximum" period = 300 evaluation_periods = 1 threshold = 0 comparison_operator = "GreaterThanThreshold" treat_missing_data = "notBreaching" alarm_actions = [local.site_alerts_arn] }