Skip to content

Instantly share code, notes, and snippets.

@tyrchen
Forked from jeka-kiselyov/index.js
Created October 26, 2015 14:43
Show Gist options
  • Save tyrchen/9a001ae7fcc213fabecf to your computer and use it in GitHub Desktop.
Save tyrchen/9a001ae7fcc213fabecf to your computer and use it in GitHub Desktop.
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'});
});
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment