Last active
December 14, 2020 15:43
-
-
Save nicolaracco/ef8febc5ad465ef870071df32e695df2 to your computer and use it in GitHub Desktop.
Lambda error reporting via CDK
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
import 'source-map-support/register' | |
import * as cdk from '@aws-cdk/core' | |
import { MyLambdaStack } from '../lib/my-lambda-stack' | |
import { ErrorReportingStack } from '../lib/error-reporting-stack' | |
const app = new cdk.App() | |
const errorReportingStack = new ErrorReportingStack(app, 'ErrorReportingStack', { | |
appName: 'my-app', | |
}) | |
new MyLambdaStack(app, 'MyLambdaStack', { | |
errorReporter: errorReportingStack.errorReporter, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as zlib from 'zlib' | |
import { promisify } from 'util' | |
import * as Bluebird from 'bluebird' | |
import * as _AWS from 'aws-sdk' | |
import * as AWSXRay from 'aws-xray-sdk' | |
import { CloudWatchLogsHandler } from 'aws-lambda' | |
interface LogEventPayload { | |
id: string | |
timestamp: number | |
message: string | |
} | |
interface LogTriggerPayload { | |
messageType: string | |
owner: string | |
logGroup: string | |
logStream: string | |
subscriptionFilter: string[] | |
logEvents: LogEventPayload[] | |
} | |
const AWS = AWSXRay.captureAWS(_AWS) | |
const gunzip = promisify(zlib.gunzip) | |
const sns = new AWS.SNS() | |
const SNS_TOPIC = process.env.SNS_TOPIC! | |
const APP_NAME = process.env.APP_NAME! | |
export const sendSnsNotification = (lambdaName: string, event: LogEventPayload, payload: LogTriggerPayload): Promise<any> => { | |
const message = ` | |
Lambda error summary | |
########################################################## | |
# Account ID: ${payload.owner} | |
# LogGroup Name: ${payload.logGroup} | |
# LogStream: ${payload.logStream} | |
# Log Message: ${event.message.split('\n').join('\n# ')} | |
########################################################## | |
` | |
return sns.publish({ | |
TargetArn: SNS_TOPIC, | |
Subject: `[${APP_NAME}] FATAL ${lambdaName}`, | |
Message: message, | |
}).promise() | |
} | |
export const handler: CloudWatchLogsHandler = async (event) => { | |
const data = JSON.parse((await gunzip(Buffer.from(event.awslogs.data, 'base64')) as Buffer).toString()) as LogTriggerPayload | |
const lambdaName = data.logGroup.split('/').slice(-1)[0] | |
await Bluebird.each(data.logEvents, (logEvent) => sendSnsNotification(lambdaName, logEvent, data)) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from '@aws-cdk/core' | |
import * as iam from '@aws-cdk/aws-iam' | |
import * as lambda from '@aws-cdk/aws-lambda' | |
import * as lambdaNode from '@aws-cdk/aws-lambda-nodejs' | |
import * as sns from '@aws-cdk/aws-sns' | |
import * as snsSubscriptions from '@aws-cdk/aws-sns-subscriptions' | |
export interface ErrorReportingStackProps extends cdk.StackProps { | |
appName: string | |
} | |
export class ErrorReportingStack extends cdk.Stack { | |
readonly errorReporter: lambda.IFunction | |
constructor(scope: cdk.Construct, id: string, props: ErrorReportingStackProps) { | |
super(scope, id, props) | |
const snsTopic = new sns.Topic(this, 'ErrorTopic') | |
snsTopic.addSubscription(new snsSubscriptions.EmailSubscription('[email protected]')) | |
const errorReporter = new lambdaNode.NodejsFunction(this, 'ErrorReporter', { | |
environment: { | |
SNS_TOPIC: snsTopic.topicArn, | |
APP_NAME: props.appName, | |
} | |
}) | |
errorReporter.addToRolePolicy(new iam.PolicyStatement({ | |
actions: ['sns:Publish'], | |
resources: [snsTopic.topicArn], | |
})) | |
this.errorReporter = errorReporter | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from '@aws-cdk/core' | |
import * as lambda from '@aws-cdk/aws-lambda' | |
import * as lambdaNode from '@aws-cdk/aws-lambda-nodejs' | |
import * as logs from '@aws-cdk/aws-logs' | |
import * as logsDestinations from '@aws-cdk/aws-logs-destinations' | |
export interface MyLambdaStackProps extends cdk.StackProps { | |
errorReporter?: lambda.IFunction | |
} | |
export class MyLambdaStack extends cdk.Stack { | |
constructor(scope: cdk.Construct, id: string, props: MyLambdaStackProps) { | |
super(scope, id, props) | |
const lambda = new lambdaNode.NodejsFunction(this, 'handler'); | |
const logGroup = lambda.logGroup; | |
logGroup.addSubscriptionFilter('ErrorSubscription', { | |
filterPattern: logs.FilterPattern.literal('ERROR'), | |
destination: new logsDestinations.LambdaDestination(props.errorReporter), | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment