cdk-serverless-agentic-api
Version:
CDK construct for serverless web applications with CloudFront, S3, Cognito, API Gateway, and Lambda
322 lines • 12.4 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createApiGatewayAlarms = createApiGatewayAlarms;
exports.createLambdaAlarms = createLambdaAlarms;
exports.createCloudFrontAlarms = createCloudFrontAlarms;
exports.createMonitoringResources = createMonitoringResources;
const cloudwatch = __importStar(require("aws-cdk-lib/aws-cloudwatch"));
const aws_cdk_lib_1 = require("aws-cdk-lib");
/**
* Creates CloudWatch alarms for API Gateway metrics
*
* @param scope The construct scope
* @param api The API Gateway REST API
* @param dashboard The CloudWatch dashboard to add widgets to
* @param constructId The ID of the parent construct
*/
function createApiGatewayAlarms(scope, api, dashboard, constructId) {
// Create alarm for API Gateway 4xx errors
new cloudwatch.Alarm(scope, 'ApiGateway4xxAlarm', {
alarmName: `${constructId}-api-4xx-errors`,
alarmDescription: 'API Gateway 4xx error rate is too high',
metric: new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: '4XXError',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Sum',
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 10,
evaluationPeriods: 2,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Create alarm for API Gateway 5xx errors
new cloudwatch.Alarm(scope, 'ApiGateway5xxAlarm', {
alarmName: `${constructId}-api-5xx-errors`,
alarmDescription: 'API Gateway 5xx error rate is too high',
metric: new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: '5XXError',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Sum',
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 5,
evaluationPeriods: 2,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Create alarm for API Gateway latency
new cloudwatch.Alarm(scope, 'ApiGatewayLatencyAlarm', {
alarmName: `${constructId}-api-latency`,
alarmDescription: 'API Gateway latency is too high',
metric: new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: 'Latency',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Average',
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 5000, // 5 seconds
evaluationPeriods: 3,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Add API Gateway metrics widget to dashboard
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: 'API Gateway Metrics',
left: [
new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: 'Count',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Sum',
}),
],
right: [
new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: 'Latency',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Average',
}),
],
}));
// Add error metrics widget
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: 'API Gateway Errors',
left: [
new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: '4XXError',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Sum',
}),
new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: '5XXError',
dimensionsMap: {
ApiName: api.restApiName,
Stage: 'api',
},
statistic: 'Sum',
}),
],
}));
}
/**
* Creates CloudWatch alarms for Lambda function metrics
*
* @param scope The construct scope
* @param lambdaFunctions Map of Lambda functions
* @param dashboard The CloudWatch dashboard to add widgets to
* @param constructId The ID of the parent construct
*/
function createLambdaAlarms(scope, lambdaFunctions, dashboard, constructId) {
// Create alarms for each Lambda function that has health alarms enabled
Object.entries(lambdaFunctions).forEach(([path, entry]) => {
// Only create alarms if enableHealthAlarms is true
if (!entry.config.enableHealthAlarms) {
return;
}
// Generate a safe alarm ID from the path
const safePath = path.replace(/[^a-zA-Z0-9]/g, '');
const alarmIdPrefix = `Lambda${safePath}`;
// Create alarm for Lambda errors
new cloudwatch.Alarm(scope, `${alarmIdPrefix}ErrorAlarm`, {
alarmName: `${constructId}-lambda${path}-errors`,
alarmDescription: `Lambda function for ${path} error rate is too high`,
metric: entry.function.metricErrors({
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 3,
evaluationPeriods: 2,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Create alarm for Lambda duration
new cloudwatch.Alarm(scope, `${alarmIdPrefix}DurationAlarm`, {
alarmName: `${constructId}-lambda${path}-duration`,
alarmDescription: `Lambda function for ${path} duration is too high`,
metric: entry.function.metricDuration({
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 25000, // 25 seconds (close to 30s timeout)
evaluationPeriods: 3,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Add Lambda metrics to dashboard
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: `Lambda ${path} Metrics`,
left: [
entry.function.metricInvocations(),
entry.function.metricErrors(),
],
right: [
entry.function.metricDuration(),
],
}));
});
}
/**
* Creates CloudWatch alarms for CloudFront metrics
*
* @param scope The construct scope
* @param distribution The CloudFront distribution
* @param dashboard The CloudWatch dashboard to add widgets to
* @param constructId The ID of the parent construct
*/
function createCloudFrontAlarms(scope, distribution, dashboard, constructId) {
// Create alarm for CloudFront 4xx errors
new cloudwatch.Alarm(scope, 'CloudFront4xxAlarm', {
alarmName: `${constructId}-cloudfront-4xx-errors`,
alarmDescription: 'CloudFront 4xx error rate is too high',
metric: new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: '4xxErrorRate',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Average',
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 5, // 5% error rate
evaluationPeriods: 3,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Create alarm for CloudFront 5xx errors
new cloudwatch.Alarm(scope, 'CloudFront5xxAlarm', {
alarmName: `${constructId}-cloudfront-5xx-errors`,
alarmDescription: 'CloudFront 5xx error rate is too high',
metric: new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: '5xxErrorRate',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Average',
period: aws_cdk_lib_1.Duration.minutes(5),
}),
threshold: 1, // 1% error rate
evaluationPeriods: 2,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});
// Add CloudFront metrics to dashboard
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: 'CloudFront Metrics',
left: [
new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: 'Requests',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Sum',
}),
],
right: [
new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: 'CacheHitRate',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Average',
}),
],
}));
// Add error rate metrics
dashboard.addWidgets(new cloudwatch.GraphWidget({
title: 'CloudFront Error Rates',
left: [
new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: '4xxErrorRate',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Average',
}),
new cloudwatch.Metric({
namespace: 'AWS/CloudFront',
metricName: '5xxErrorRate',
dimensionsMap: {
DistributionId: distribution.distributionId,
},
statistic: 'Average',
}),
],
}));
}
/**
* Creates monitoring resources including CloudWatch alarms and dashboards
*
* @param scope The construct scope
* @param api The API Gateway REST API
* @param lambdaFunctions Map of Lambda functions
* @param distribution The CloudFront distribution
* @param constructId The ID of the parent construct
* @returns The created CloudWatch dashboard
*/
function createMonitoringResources(scope, api, lambdaFunctions, distribution, constructId) {
// Create CloudWatch dashboard for monitoring
const dashboard = new cloudwatch.Dashboard(scope, 'MonitoringDashboard', {
dashboardName: `${constructId}-monitoring`,
});
// Add API Gateway metrics to dashboard
createApiGatewayAlarms(scope, api, dashboard, constructId);
// Add Lambda function metrics to dashboard
createLambdaAlarms(scope, lambdaFunctions, dashboard, constructId);
// Add CloudFront metrics to dashboard
createCloudFrontAlarms(scope, distribution, dashboard, constructId);
return dashboard;
}
//# sourceMappingURL=monitoring.js.map