@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
JavaScript
"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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