Skip to content

Instantly share code, notes, and snippets.

@julbrs
Created October 17, 2023 15:07
Show Gist options
  • Save julbrs/41d93dd234a5db69ad874101cb2853f1 to your computer and use it in GitHub Desktop.
Save julbrs/41d93dd234a5db69ad874101cb2853f1 to your computer and use it in GitHub Desktop.
Setup cloudwatch alarms on SST !
// name: FunctionsAlarm.ts
// can be used with:
// new FunctionsAlarm(stack, 'ApiAlarmMain', {
// api,
// alarmNamePrefix: `API Error`,
// });
//
// new FunctionsAlarm(stack, 'ApiAlarmMain', {
// functions: [cron.jobFunction],
// alarmNamePrefix: `Cron Job Error`,
// });
import { Api, ApiAuthorizer, Function } from 'sst/constructs';
import { Duration } from 'aws-cdk-lib';
import { Alarm } from 'aws-cdk-lib/aws-cloudwatch';
import { SnsAction } from 'aws-cdk-lib/aws-cloudwatch-actions';
import { Topic } from 'aws-cdk-lib/aws-sns';
import { EmailSubscription } from 'aws-cdk-lib/aws-sns-subscriptions';
import { Construct } from 'constructs';
export interface FunctionsAlarmProps {
/**
* Function to monitor
*/
readonly functions?: Function[];
/**
* The SST API to monitor
*/
readonly api?: Api<Record<string, ApiAuthorizer>>;
/**
* The name of the alarm
*/
readonly alarmNamePrefix: string;
}
/**
* This construct is responsible to create an alarm for all API Gateway endpoint.
*/
export default class FunctionsAlarm extends Construct {
constructor(scope: Construct, id: string, props: FunctionsAlarmProps) {
super(scope, id);
if (props.functions === undefined && props.api === undefined) {
throw new Error('You must provide at least one function or an API');
}
if (props.functions && props.api) {
throw new Error('You must provide either a function or an API, not both');
}
if (!process.env.ALERT_EMAIL) {
throw new Error('You must provide an ALERT_EMAIL environment variable');
}
const alarmTopic = new Topic(scope, `${id}-AlarmTopic`);
alarmTopic.addSubscription(new EmailSubscription(process.env.ALERT_EMAIL));
// work on Function array
if (props.functions) {
for (const func of props.functions) {
// create a new alarm based on the metric
createAlarm(scope, func, props.alarmNamePrefix, alarmTopic);
}
}
// work on API construct
if (props.api) {
for (const route of props.api.routes) {
const func = props.api.getFunction(route);
if (func) {
createAlarm(scope, func, props.alarmNamePrefix, alarmTopic, route);
}
}
}
}
}
const createAlarm = (
scope: Construct,
func: Function,
alarmNamePrefix: string,
alarmTopic: Topic,
route?: string
) => {
const alarm = new Alarm(scope, `FunctionAlarm-${func.id}`, {
metric: func.metricErrors({
period: Duration.minutes(15),
}),
alarmName: route ? `${alarmNamePrefix} ${route}` : `${alarmNamePrefix} ${func.id}`,
threshold: 5,
evaluationPeriods: 1,
});
alarm.addAlarmAction(new SnsAction(alarmTopic));
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment