UNPKG

@renovosolutions/cdk-library-cloudwatch-alarms

Version:

AWS CDK Construct Library to automatically create CloudWatch Alarms for resources in a CDK app based on resource type.

674 lines 115 kB
"use strict"; var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApiGatewayRecommendedAlarmsAspect = exports.RestApi = exports.ApiGatewayRestApiRecommendedAlarms = exports.ApiGatewayRestApiIntegrationLatencyAnomalyAlarm = exports.ApiGatewayRestApiCountAnomalyAlarm = exports.ApiGatewayRestApiLatencyAnomalyAlarm = exports.ApiGatewayRestApiDetailedLatencyAlarm = exports.ApiGatewayRestApiLatencyAlarm = exports.ApiGatewayRestApi5XXErrorAlarm = exports.ApiGatewayRestApi4XXErrorAlarm = exports.ApiGatewayRecommendedAlarmsMetrics = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const constructs_1 = require("constructs"); const common_1 = require("./common"); /** * The recommended metrics for ApiGateway alarms. */ var ApiGatewayRecommendedAlarmsMetrics; (function (ApiGatewayRecommendedAlarmsMetrics) { /** * The number of client-side errors captured in a given period. */ ApiGatewayRecommendedAlarmsMetrics["ERROR_4XX"] = "4XXError"; /** * The number of server-side errors captured in a given period. */ ApiGatewayRecommendedAlarmsMetrics["ERROR_5XX"] = "5XXError"; /** * The time (milliseconds) between when API Gateway receives a request from a client and * when it returns a response to the client. The latency includes the integration latency * and other API Gateway overhead. */ ApiGatewayRecommendedAlarmsMetrics["LATENCY"] = "Latency"; /** * Anomaly detection on the Latency metric. Detects drift in total request latency * (API Gateway overhead + backend integration) without requiring a static threshold. */ ApiGatewayRecommendedAlarmsMetrics["LATENCY_ANOMALY"] = "LatencyAnomaly"; /** * Anomaly detection on the Count metric. Detects unexpected drops (or spikes) in * traffic volume for low-traffic APIs where a static `LESS_THAN_THRESHOLD` value * is hard to pick. */ ApiGatewayRecommendedAlarmsMetrics["COUNT_ANOMALY"] = "CountAnomaly"; /** * Anomaly detection on the IntegrationLatency metric. Detects drift in backend * latency independently of overall request latency. No static counterpart exists * in this library. */ ApiGatewayRecommendedAlarmsMetrics["INTEGRATION_LATENCY_ANOMALY"] = "IntegrationLatencyAnomaly"; })(ApiGatewayRecommendedAlarmsMetrics || (exports.ApiGatewayRecommendedAlarmsMetrics = ApiGatewayRecommendedAlarmsMetrics = {})); /** * This alarm detects a high number of client-side errors. * * This can indicate an issue in the authorization or client request parameters. It could also mean that a resource was * removed or a client is requesting one that doesn't exist. Consider enabling CloudWatch Logs and checking for any errors * that may be causing the 4XX errors. Moreover, consider enabling detailed CloudWatch metrics to view this metric per * resource and method and narrow down the source of the errors. Errors could also be caused by exceeding the configured * throttling limit. * * The alarm is triggered when number of client-errors exceeds the threshold. */ class ApiGatewayRestApi4XXErrorAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.ERROR_4XX}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm can detect high rates of client-side errors for the' + ' API Gateway requests.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricClientError({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'Average', period, }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApi4XXErrorAlarm = ApiGatewayRestApi4XXErrorAlarm; _a = JSII_RTTI_SYMBOL_1; ApiGatewayRestApi4XXErrorAlarm[_a] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApi4XXErrorAlarm", version: "0.0.17" }; ; /** * This alarm detects a high number of server-side errors. * * This can indicate that there is something wrong on the API backend, the network, * or the integration between the API gateway and the backend API. * * The alarm is triggered when number of server-errors exceeds the threshold. */ class ApiGatewayRestApi5XXErrorAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.ERROR_5XX}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 3; const datapointsToAlarm = props.datapointsToAlarm ?? 3; const threshold = props.threshold; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm can detect high rates of server-side errors for the' + ' API Gateway requests.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricServerError({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'Average', period, }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApi5XXErrorAlarm = ApiGatewayRestApi5XXErrorAlarm; _b = JSII_RTTI_SYMBOL_1; ApiGatewayRestApi5XXErrorAlarm[_b] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApi5XXErrorAlarm", version: "0.0.17" }; ; /** * This alarm can detect when the API Gateway requests in a stage have high latency. * * If you have detailed CloudWatch metrics enabled and you have different latency performance * requirements for each method and resource, we recommend that you create alternative alarms to * have more fine-grained monitoring of the latency for each resource and method. * * The alarm is triggered when time in milliseconds exceeds or equals the threshold. */ class ApiGatewayRestApiLatencyAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.LATENCY}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold ?? 2500; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm can detect when the API Gateway requests in a' + ' stage have high latency.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricLatency({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'p90', period, }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApiLatencyAlarm = ApiGatewayRestApiLatencyAlarm; _c = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiLatencyAlarm[_c] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiLatencyAlarm", version: "0.0.17" }; ; /** * This alarm detects high latency for a resource and method in a stage. * * Find the IntegrationLatency metric value to check the API backend latency. If the two * metrics are mostly aligned, the API backend is the source of higher latency and you should * investigate there for performance issues. Consider also enabling CloudWatch Logs and checking * for any errors that might be causing the high latency. * * The alarm is triggered when time in milliseconds exceeds or equals the threshold. */ class ApiGatewayRestApiDetailedLatencyAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName}-${props.alias} - ${ApiGatewayRecommendedAlarmsMetrics.LATENCY}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold ?? 2500; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm can detect when the API Gateway requests for a' + ' resource and method in a stage have high latency.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricLatency({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, Resource: props.resource, Method: props.method, }, statistic: 'p90', period, }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApiDetailedLatencyAlarm = ApiGatewayRestApiDetailedLatencyAlarm; _d = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiDetailedLatencyAlarm[_d] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiDetailedLatencyAlarm", version: "0.0.17" }; ; /** * An anomaly detection alarm on the API Gateway `Latency` metric. * * Catches drift in total request latency without requiring a static threshold. * The static `Latency` alarm uses the AWS-recommended `p90` statistic and a * fixed threshold; this anomaly variant uses `Average` (required by anomaly * detection) and a CloudWatch-fitted band. It is intended to coexist with the * static alarm, not replace it. */ class ApiGatewayRestApiLatencyAnomalyAlarm extends aws_cdk_lib_1.aws_cloudwatch.AnomalyDetectionAlarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.LATENCY_ANOMALY}`; // Anomaly bands use a fixed 5-minute metric period; a finer period produces noisier, less reliable bands. const period = aws_cdk_lib_1.Duration.minutes(5); const evaluationPeriods = props.evaluationPeriods ?? 3; const datapointsToAlarm = props.datapointsToAlarm ?? 2; const stdDevs = props.stdDevs ?? 8; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const comparisonOperator = props.comparisonOperator ?? aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_UPPER_THRESHOLD; const alarmDescription = props.alarmDescription ?? 'This anomaly detection alarm detects unusual drift in the API' + ' Gateway request latency compared to the expected baseline.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricLatency({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'Average', period, }), stdDevs, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApiLatencyAnomalyAlarm = ApiGatewayRestApiLatencyAnomalyAlarm; _e = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiLatencyAnomalyAlarm[_e] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiLatencyAnomalyAlarm", version: "0.0.17" }; ; /** * An anomaly detection alarm on the API Gateway `Count` metric. * * AWS recommends a static `Count` alarm with `LESS_THAN_THRESHOLD` to detect * unexpected traffic drops, but says the threshold "Depends on your situation". * This anomaly variant lets the band track historical traffic so the alarm * fires on actual deviations without picking a number that goes stale. By default * it flags both unexpected drops and unusual spikes (e.g. abuse or retry storms). * * Because anomaly detection requires the `Average` statistic, this alarm tracks the * average request rate per period, not total request volume. * * Note: on the drop side it detects partial drops below the expected band, not a * complete outage. API Gateway does not publish `Count` when there are zero requests, * so a full outage produces missing data (treated as not breaching) rather than a low * value. To alarm on zero traffic, pair this with a static `Count` alarm or a canary. */ class ApiGatewayRestApiCountAnomalyAlarm extends aws_cdk_lib_1.aws_cloudwatch.AnomalyDetectionAlarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.COUNT_ANOMALY}`; // Anomaly bands use a fixed 5-minute metric period; a finer period produces noisier, less reliable bands. const period = aws_cdk_lib_1.Duration.minutes(5); const evaluationPeriods = props.evaluationPeriods ?? 4; const datapointsToAlarm = props.datapointsToAlarm ?? 3; const stdDevs = props.stdDevs ?? 8; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const comparisonOperator = props.comparisonOperator ?? aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.LESS_THAN_LOWER_OR_GREATER_THAN_UPPER_THRESHOLD; const alarmDescription = props.alarmDescription ?? 'This anomaly detection alarm detects unexpected drops or spikes in' + ' request volume for the API Gateway stage, which can indicate clients calling the wrong endpoints, an outage' + ' upstream, or abusive traffic.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricCount({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'Average', period, }), stdDevs, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApiCountAnomalyAlarm = ApiGatewayRestApiCountAnomalyAlarm; _f = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiCountAnomalyAlarm[_f] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiCountAnomalyAlarm", version: "0.0.17" }; ; /** * An anomaly detection alarm on the API Gateway `IntegrationLatency` metric. * * Catches drift in backend latency separately from total request latency, so * a slow backend integration shows up even when overall request latency is * within normal range (e.g. because backend latency was always part of the * baseline). This library has no static counterpart for this metric. */ class ApiGatewayRestApiIntegrationLatencyAnomalyAlarm extends aws_cdk_lib_1.aws_cloudwatch.AnomalyDetectionAlarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.api.restApiName} - ${ApiGatewayRecommendedAlarmsMetrics.INTEGRATION_LATENCY_ANOMALY}`; // Anomaly bands use a fixed 5-minute metric period; a finer period produces noisier, less reliable bands. const period = aws_cdk_lib_1.Duration.minutes(5); const evaluationPeriods = props.evaluationPeriods ?? 3; const datapointsToAlarm = props.datapointsToAlarm ?? 2; const stdDevs = props.stdDevs ?? 8; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const comparisonOperator = props.comparisonOperator ?? aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_UPPER_THRESHOLD; const alarmDescription = props.alarmDescription ?? 'This anomaly detection alarm detects unusual drift in the API' + ' Gateway backend integration latency, which can indicate backend performance issues independent of API Gateway' + ' overhead.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.api.metricIntegrationLatency({ dimensionsMap: { ApiName: props.api.restApiName, Stage: props.api.deploymentStage.stageName, }, statistic: 'Average', period, }), stdDevs, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.ApiGatewayRestApiIntegrationLatencyAnomalyAlarm = ApiGatewayRestApiIntegrationLatencyAnomalyAlarm; _g = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiIntegrationLatencyAnomalyAlarm[_g] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiIntegrationLatencyAnomalyAlarm", version: "0.0.17" }; ; /** * A construct that creates the recommended alarms for an ApiGateway api. * * The recommended alarms created by default for the ApiName and Stage are: * - 4XXError alarm * - 5XXError alarm * - Latency alarm * - Latency anomaly detection alarm (additional to the static Latency alarm) * - Count anomaly detection alarm (drop detection for low-traffic APIs) * - IntegrationLatency anomaly detection alarm (no static counterpart) * * In order to create the Latency alarms for the Resource and Method dimensions the * configDetailedLatencyAlarmList must be specified. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#ApiGateway */ class ApiGatewayRestApiRecommendedAlarms extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.ERROR_4XX)) { this.alarm4XXError = new ApiGatewayRestApi4XXErrorAlarm(this, `${props.api.node.id}_4XXError`, { api: props.api, treatMissingData: props.treatMissingData, ...props.config4XXErrorAlarm, }); if (props.defaultAlarmAction && !props.config4XXErrorAlarm?.alarmAction) { this.alarm4XXError.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.config4XXErrorAlarm?.okAction) { this.alarm4XXError.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.config4XXErrorAlarm?.insufficientDataAction) { this.alarm4XXError.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.ERROR_5XX)) { this.alarm5XXError = new ApiGatewayRestApi5XXErrorAlarm(this, `${props.api.node.id}_5XXError`, { api: props.api, treatMissingData: props.treatMissingData, ...props.config5XXErrorAlarm, }); if (props.defaultAlarmAction && !props.config5XXErrorAlarm?.alarmAction) { this.alarm5XXError.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.config5XXErrorAlarm?.okAction) { this.alarm5XXError.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.config5XXErrorAlarm?.insufficientDataAction) { this.alarm5XXError.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.LATENCY)) { this.alarmLatency = new ApiGatewayRestApiLatencyAlarm(this, `${props.api.node.id}_Latency`, { api: props.api, treatMissingData: props.treatMissingData, ...props.configLatencyAlarm, }); if (props.defaultAlarmAction && !props.configLatencyAlarm?.alarmAction) { this.alarmLatency.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configLatencyAlarm?.okAction) { this.alarmLatency.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configLatencyAlarm?.insufficientDataAction) { this.alarmLatency.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.LATENCY) && props.configDetailedLatencyAlarmList) { props.configDetailedLatencyAlarmList.forEach((config, index) => { let alarmConfig = { api: props.api, treatMissingData: props.treatMissingData, ...config, }; if (props.defaultAlarmAction && !config.alarmAction) { alarmConfig = { ...alarmConfig, alarmAction: props.defaultAlarmAction }; } if (props.defaultOkAction && !config.okAction) { alarmConfig = { ...alarmConfig, okAction: props.defaultOkAction }; } if (props.defaultInsufficientDataAction && !config.insufficientDataAction) { alarmConfig = { ...alarmConfig, insufficientDataAction: props.defaultInsufficientDataAction }; } new ApiGatewayRestApiDetailedLatencyAlarm(this, `${props.api.node.id}_DetailedLatency${index}`, alarmConfig); }); } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.LATENCY_ANOMALY)) { this.alarmLatencyAnomaly = new ApiGatewayRestApiLatencyAnomalyAlarm(this, `${props.api.node.id}_LatencyAnomaly`, { api: props.api, treatMissingData: props.treatMissingData, ...props.configLatencyAnomalyAlarm, }); if (props.defaultAlarmAction && !props.configLatencyAnomalyAlarm?.alarmAction) { this.alarmLatencyAnomaly.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configLatencyAnomalyAlarm?.okAction) { this.alarmLatencyAnomaly.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configLatencyAnomalyAlarm?.insufficientDataAction) { this.alarmLatencyAnomaly.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.COUNT_ANOMALY)) { this.alarmCountAnomaly = new ApiGatewayRestApiCountAnomalyAlarm(this, `${props.api.node.id}_CountAnomaly`, { api: props.api, treatMissingData: props.treatMissingData, ...props.configCountAnomalyAlarm, }); if (props.defaultAlarmAction && !props.configCountAnomalyAlarm?.alarmAction) { this.alarmCountAnomaly.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configCountAnomalyAlarm?.okAction) { this.alarmCountAnomaly.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configCountAnomalyAlarm?.insufficientDataAction) { this.alarmCountAnomaly.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(ApiGatewayRecommendedAlarmsMetrics.INTEGRATION_LATENCY_ANOMALY)) { this.alarmIntegrationLatencyAnomaly = new ApiGatewayRestApiIntegrationLatencyAnomalyAlarm(this, `${props.api.node.id}_IntegrationLatencyAnomaly`, { api: props.api, treatMissingData: props.treatMissingData, ...props.configIntegrationLatencyAnomalyAlarm, }); if (props.defaultAlarmAction && !props.configIntegrationLatencyAnomalyAlarm?.alarmAction) { this.alarmIntegrationLatencyAnomaly.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configIntegrationLatencyAnomalyAlarm?.okAction) { this.alarmIntegrationLatencyAnomaly.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configIntegrationLatencyAnomalyAlarm?.insufficientDataAction) { this.alarmIntegrationLatencyAnomaly.addInsufficientDataAction(props.defaultInsufficientDataAction); } } } } exports.ApiGatewayRestApiRecommendedAlarms = ApiGatewayRestApiRecommendedAlarms; _h = JSII_RTTI_SYMBOL_1; ApiGatewayRestApiRecommendedAlarms[_h] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRestApiRecommendedAlarms", version: "0.0.17" }; /** * An extension for the RestApi construct that provides methods * to create recommended alarms. */ class RestApi extends aws_cdk_lib_1.aws_apigateway.RestApi { constructor(scope, id, props) { super(scope, id, props); } /** * Creates an alarm that monitors the number of client-side errors captured in a given period. */ alarm4XXError(props) { return new ApiGatewayRestApi4XXErrorAlarm(this, '4XXErrorAlarm', { api: this, ...props, }); } /** * Creates an alarm that monitors the number of server-side errors captured in a given period. */ alarm5XXError(props) { return new ApiGatewayRestApi5XXErrorAlarm(this, '5XXErrorAlarm', { api: this, ...props, }); } /** * Creates an alarm that monitors the time between when API Gateway receives a request * from a client and when it returns a response to the client. */ alarmLatency(props) { return new ApiGatewayRestApiLatencyAlarm(this, 'LatencyAlarm', { api: this, ...props, }); } /** * Creates a list of alarms the time between when API Gateway receives a request * from a client and when it returns a response to the client for the methods and * resources specified. */ alarmDetailedLatency(props) { let alarmList = []; props.forEach((config, index) => { const alarm = new ApiGatewayRestApiDetailedLatencyAlarm(this, `DetailedLatency${index}`, { api: this, ...config, }); alarmList.push(alarm); }); return alarmList; } /** * Creates an anomaly detection alarm on the Latency metric. Detects drift in * total request latency without requiring a static threshold; intended to * coexist with the static `Latency` alarm. */ alarmLatencyAnomaly(props) { return new ApiGatewayRestApiLatencyAnomalyAlarm(this, 'LatencyAnomalyAlarm', { api: this, ...props, }); } /** * Creates an anomaly detection alarm on the Count metric. By default detects both * unexpected traffic drops and spikes for low-traffic APIs where a static count * threshold is hard to pick. */ alarmCountAnomaly(props) { return new ApiGatewayRestApiCountAnomalyAlarm(this, 'CountAnomalyAlarm', { api: this, ...props, }); } /** * Creates an anomaly detection alarm on the IntegrationLatency metric. * Catches backend integration latency drift independently of API Gateway * overhead. */ alarmIntegrationLatencyAnomaly(props) { return new ApiGatewayRestApiIntegrationLatencyAnomalyAlarm(this, 'IntegrationLatencyAnomalyAlarm', { api: this, ...props, }); } /** * Creates the recommended alarms for the ApiGateway api. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#ApiGateway */ applyRecommendedAlarms(props) { return new ApiGatewayRestApiRecommendedAlarms(this, 'ApiGatewayRestApiRecommendedAlarms', { api: this, ...props, }); } } exports.RestApi = RestApi; _j = JSII_RTTI_SYMBOL_1; RestApi[_j] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.RestApi", version: "0.0.17" }; /** * Configures the recommended alarms for an ApiGateway api. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#ApiGateway */ class ApiGatewayRecommendedAlarmsAspect { constructor(props) { this.props = props; } visit(node) { if (node instanceof aws_cdk_lib_1.aws_apigateway.RestApi) { if (this.props.excludeResources && this.props.excludeResources.includes(node.node.id)) { return; } else { const api = node; new ApiGatewayRestApiRecommendedAlarms(api, 'ApiGatewayRestApiRecommendedAlarmsFromAspect', { api, ...this.props, }); } } } } exports.ApiGatewayRecommendedAlarmsAspect = ApiGatewayRecommendedAlarmsAspect; _k = JSII_RTTI_SYMBOL_1; ApiGatewayRecommendedAlarmsAspect[_k] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.ApiGatewayRecommendedAlarmsAspect", version: "0.0.17" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpZ2F0ZXdheS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hcGlnYXRld2F5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkNBS3FCO0FBQ3JCLDJDQUFtRDtBQUNuRCxxQ0FBb0U7QUFFcEU7O0dBRUc7QUFDSCxJQUFZLGtDQWdDWDtBQWhDRCxXQUFZLGtDQUFrQztJQUM1Qzs7T0FFRztJQUNILDREQUFzQixDQUFBO0lBQ3RCOztPQUVHO0lBQ0gsNERBQXNCLENBQUE7SUFDdEI7Ozs7T0FJRztJQUNILHlEQUFtQixDQUFBO0lBQ25COzs7T0FHRztJQUNILHdFQUFrQyxDQUFBO0lBQ2xDOzs7O09BSUc7SUFDSCxvRUFBOEIsQ0FBQTtJQUM5Qjs7OztPQUlHO0lBQ0gsK0ZBQXlELENBQUE7QUFDM0QsQ0FBQyxFQWhDVyxrQ0FBa0Msa0RBQWxDLGtDQUFrQyxRQWdDN0M7QUFtR0Q7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQWEsOEJBQStCLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQ2xFLFlBQVksS0FBaUIsRUFBRSxFQUFVLEVBQUUsS0FBMEM7UUFDbkYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsV0FBVyxNQUFNLGtDQUFrQyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2xILE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkQsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1FBQ3ZELE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLENBQUMsQ0FBQztRQUN2RCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO1FBQ2xDLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixJQUFJLDRC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