Help us understand the problem. What is going on with this article?

CloudWatchのAlarmをlambdaから色付きでSlackに投稿

More than 3 years have passed since last update.

投稿すること自体は前々からやっていたんだけど,投稿フォーマット等がだいぶ固まってきて,最近はこれを使い回すことが多くなってきたので,個人的なメモとして残しておく.

単なるテキストだけだと,パッと見たときに,OKの通知なのかALARMの通知なのかわかりにくいというのがあって,ちょっと色分けしている.その辺がお気に入り.

スクリーンショット 2016-07-16 2.05.41.png

スクリーンショット 2016-07-16 2.05.48.png

Create a Lambda function

最近はblueprintというのが用意されているので,cloudwatch-alarm-to-slackを選ぶ.

スクリーンショット 2016-07-16 1.49.50.png

SNSとの関連付けは,後からでも変更可能なので,ここでやらなくても良い.

スクリーンショット 2016-07-16 1.50.41.png

こうやって作ると,雛形が用意されている.
そして雛形には,こんなコメントがついている.

/**
 * Follow these steps to configure the webhook in Slack:
 *
 *   1. Navigate to https://<your-team-domain>.slack.com/services/new
 *
 *   2. Search for and select "Incoming WebHooks".
 *
 *   3. Choose the default channel where messages will be sent and click "Add Incoming WebHooks Integration".
 *
 *   4. Copy the webhook URL from the setup instructions and use it in the next section.
 *
 *
 * Follow these steps to encrypt your Slack hook URL for use in this function:
 *
 *   1. Create a KMS key - http://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html.
 *
 *   2. Encrypt the event collector token using the AWS CLI.
 *      $ aws kms encrypt --key-id alias/<KMS key name> --plaintext "<SLACK_HOOK_URL>"
 *
 *      Note: You must exclude the protocol from the URL (e.g. "hooks.slack.com/services/abc123").
 *
 *   3. Copy the base-64 encoded, encrypted key (CiphertextBlob) to the ENCRYPTED_HOOK_URL variable.
 *
 *   4. Give your function's role permission for the kms:Decrypt action.
 *      Example:
 **/

blueprintが用意してくれる雛形では,slackのtokenを隠蔽しようとしていて(それはそれで良いことだけど),ちょっとめんどくさい暗号化&復号化処理を入れておく必要がある.

若干めんどくさいので,最近は暗号化せずにそのままtokenを記載することが多い.

Lambda function code

というわけで,tokenを暗号化せずにそのまま記載する形で,コードを載せておく.

var https = require('https');
var util = require('util');
var slackChannel = '#aws-alarm';  // Enter the Slack channel to send a message to
var slackPath = "/services/hogehoge/fugafuga";


var postMessage = function(message, callback) {
    var body = util.format("%j", message);
    var options = {
        hostname: "hooks.slack.com",
        port: 443,
        path: slackPath,
        method: 'POST'
    };

    options.headers = {
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(body),
    };

    var postReq = https.request(options, function(res) {
        var chunks = [];
        res.setEncoding('utf8');
        res.on('data', function(chunk) {
            return chunks.push(chunk);
        });
        res.on('end', function() {
            var body = chunks.join('');
            if (callback) {
                callback({
                    body: body,
                    statusCode: res.statusCode,
                    statusMessage: res.statusMessage
                });
            }
        });
        return res;
    });

    postReq.write(body);
    postReq.end();
};

var processEvent = function(event, context) {
    var message = JSON.parse(event.Records[0].Sns.Message);

    var alarmName = message.AlarmName;
    var oldState = message.OldStateValue;
    var newState = message.NewStateValue;
    var reason = message.NewStateReason;
    var description = message.AlarmDescription;

    var color = "danger";
    var icon = ":warning:";
    if (newState == "OK") {
        color = "good";
        icon = ":ok_hand:";
    }

    var slackMessage = {
        "cannel": slackChannel,
        "username": "AWS Notifier",
        "text": "*[" + newState + "] " + alarmName + "*",
        "icon_emoji": icon
    };

    var attachment_text = []
    attachment_text.push("Body : " + description);
    attachment_text.push("Reason : " + reason);
    attachment_text.push("OldState : " + oldState);

    slackMessage.attachments = [
        {
            "color": color,
            "text": attachment_text.join("\n")
        }
    ];


    postMessage(slackMessage, function(response) {
        if (response.statusCode < 400) {
            console.info('Message posted successfully');
            context.succeed();
        } else if (response.statusCode < 500) {
            console.error("Error posting message to Slack API: " + response.statusCode + " - " + response.statusMessage);
            context.succeed();  // Don't retry because the error is due to a problem with the request
        } else {
            // Let Lambda retry
            context.fail("Server error when processing message: " + response.statusCode + " - " + response.statusMessage);
        }
    });
};


exports.handler = function(event, context) {
    processEvent(event, context);
};

blueprintをそのまま使っている部分も結構ある.

これを使いまわしたくなるのは,メッセージの形式が気に入っているから.

attachmentsを指定していて,本文はほとんどattachmentsに書いている.そして色とアイコンの指定をしている.
この色とアイコンを,ALARMのときとOKのときで変化させている.

その結果,attachments側に書いたメッセージにいい感じに色がつく.

スクリーンショット 2016-07-16 2.05.41.png

スクリーンショット 2016-07-16 2.05.48.png

こんな感じで,アイコンと色が変わっているので,視覚的にわかりやすい.本当はOKのアイコンも,もっと青か緑色がいいんだけど,slackの標準アイコンにそこまでぴったりのが見つからなくて…….

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away