Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CloudWatch to AWS Lambda to Slack Channel Alerts and Charts. Posts CloudWatch Alerts via SNS topic via Lambda function to Slack channel. And draws charts for CPUUtilization metrics(both for EC2 abd RDS).
////// Save as index.js and upload it to Lambda as zip archive with node_modules directory. After:
////// npm install aws-cloudwatch-chart
////// npm install request
////// no need to upload aws-sdk module
////// Don't forget to change API keys here.
////// License: MIT
////// Docs:
////// https://github.com/jeka-kiselyov/aws-cloudwatch-chart
////// http://docs.aws.amazon.com/sns/latest/dg/sns-lambda.html
////// http://docs.aws.amazon.com/lambda/latest/dg/walkthrough-s3-events-adminuser-create-test-function-create-function.html
//////
exports.handler = function(event, context) {
var request = require('request');
var fs = require('fs');
var AwsCloudWatchChart = require('aws-cloudwatch-chart');
var config = {};
config.slack = {
token: 'xoxp-4234234-234234-234234234-257abf',
channel: '#aws',
initialComment: "EC2 CPU Usage %from_time% to %to_time% UTC",
fileTitle: "EC2 CPU Usage %from_time% to %to_time% UTC"
};
config.aws = {
accessKeyId: "ASDASDSADSADASD",
secretAccessKey: "dsfsdfsdf/REWR/fdsdf/DFDSf34",
region: "us-east-1"
};
config.timeOffset = 1440;
config.timePeriod = 60;
config.graphSamples = 20;
config.width = 1000;
config.height = 250;
if (typeof(event.Records) === 'undefined' || typeof(event.Records[0]) === 'undefined' || typeof(event.Records[0].Sns) === 'undefined')
context.fail ('ERROR: requires SNS message');
if (typeof(event.Records[0].Sns.Message) !== 'undefined' && typeof(event.Records[0].Sns.Message.Trigger) === 'undefined')
event.Records[0].Sns.Message = JSON.parse(event.Records[0].Sns.Message);
config.slack.initialComment = event.Records[0].Sns.Subject + "\n" + event.Records[0].Sns.Message.AlarmDescription;
config.metrics = [];
console.log('event.Records[0].Sns.Message:');
console.log(event.Records[0].Sns.Message);
if (typeof(event.Records[0].Sns.Message.Trigger) !== 'undefined' && typeof(event.Records[0].Sns.Message.Trigger.Dimensions) !== 'undefined')
{
if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/EC2' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUUtilization')
{
config.metrics.push({
InstanceId: event.Records[0].Sns.Message.Trigger.Dimensions[0].value,
title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" EC2 Max CPU Usage",
Namespace: event.Records[0].Sns.Message.Trigger.Namespace,
MetricName: event.Records[0].Sns.Message.Trigger.MetricName,
StatisticValues: "Maximum",
Unit: "Percent",
color: "af9cf4",
thickness: 2,
dashed: false
});
} else if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/RDS' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUUtilization') {
config.metrics.push({
DBInstanceIdentifier: event.Records[0].Sns.Message.Trigger.Dimensions[0].value,
title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" DB Max CPU Usage",
Namespace: event.Records[0].Sns.Message.Trigger.Namespace,
MetricName: event.Records[0].Sns.Message.Trigger.MetricName,
StatisticValues: "Maximum",
Unit: "Percent",
color: "9caff4",
thickness: 2,
dashed: false
});
} else if (event.Records[0].Sns.Message.Trigger.Namespace == 'AWS/EC2' && event.Records[0].Sns.Message.Trigger.MetricName == 'CPUCreditBalance') {
config.metrics.push({
InstanceId: event.Records[0].Sns.Message.Trigger.Dimensions[0].value,
title: event.Records[0].Sns.Message.Trigger.Dimensions[0].value+" CPU Credit Balance",
Namespace: event.Records[0].Sns.Message.Trigger.Namespace,
MetricName: event.Records[0].Sns.Message.Trigger.MetricName,
StatisticValues: "Maximum",
Unit: "Count",
color: "9caff4",
thickness: 2,
dashed: false
});
}
}
var postSlackMessage = function(text, imageURL, callback)
{
var apiURL = "https://slack.com/api/chat.postMessage?token=" + encodeURIComponent(config.slack.token) +
"&text=" + encodeURIComponent("ALERT\n"+imageURL) +
"&username=" + encodeURIComponent('AWS') +
"&as_user=" + encodeURIComponent('false') +
"&icon_emoji=" + encodeURIComponent(':bell:') +
"&attachments=" + encodeURIComponent('[{"fallback": '+JSON.stringify(text)+',"text": '+JSON.stringify(text)+', "color": "danger"}]') +
"&channel=" + encodeURIComponent(config.slack.channel);
var req = request.post(apiURL, callback);
}
if (config.metrics.length < 1)
{
/// post
postSlackMessage(config.slack.initialComment, '', function() {
context.done(null, 'Not AWS/EC2 CPUUtilization metric');
});
} else {
var acs = new AwsCloudWatchChart(config);
console.log('Start');
acs.getChart().then(function(chart){
console.log('Got chart URL');
console.log(chart.getURL());
chart.get().then(function(image){
console.log('Got chart image');
var fileTitle = config.slack.fileTitle.
split('%from_time%').join(acs.getFromTimeString()).
split('%to_time%').join(acs.getToTimeString());
var initialComment = config.slack.initialComment.
split('%from_time%').join(acs.getFromTimeString()).
split('%to_time%').join(acs.getToTimeString());
var apiURL = "https://slack.com/api/files.upload?token=" + encodeURIComponent(config.slack.token) +
"&filename=" + encodeURIComponent("image.png") +
"&title=" + encodeURIComponent(fileTitle) +
"&initial_comment=" + encodeURIComponent(initialComment);
console.log('Sending file to Slack...');
var callback = function (err, response, body) {
var data = JSON.parse(body);
var text = config.slack.initialComment;
postSlackMessage(text, data.file.url, function() {
context.done(null, "Done");
});
}
var req = request.post(apiURL, callback);
var form = req.form();
form.append('file', new Buffer(image), {contentType: 'image/png', filename: 'x.png', name: 'x.png'});
});
});
}
};
@theist

This comment has been minimized.

Copy link

@theist theist commented Nov 29, 2015

Whould be possible use IAM roles instead of Keys/secrets?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.