2&>1

AWSとかGCPとかGolangとかとか

CloudWatchでの(疑似)外形監視とslack or chatwarkへの通知

今回は外形監視みたいなことしてCloudwatchで監視設定します。

簡単にいえばアクセスログで400エラーなんやらが発生したらslack へ通知を出します。

メール通知はアドレス入れるだけで簡単ですけど最近流行らないですからね、

構成

ざっくりこうです。(よくある)

f:id:piyojir0:20190509150144p:plain

設定順番は以下

1.SNSへトピック追加

2.CloudWatchのアラート設定

3.slackのwebhookURL確認

4.Lambdaの設定

5.SNSとLambdaの設定

SNSへトピック追加

とりあえずはSNSでトピックだけ作成 適当な名前を決めるだけ。サブスクリプションは最後に設定。

f:id:piyojir0:20190509161646j:plain

CloudWatchのアラート設定

httpdアクセスログから400番台エラーを検知するようにします。

一発CLIだとこう

aws logs put-metric-filter \
  --log-group-name /HttpdAccessLog \
  --filter-name HTTP4xxErrors \
  --filter-pattern '[ip, id, user, timestamp, request, status_code=4*, size]' \
  --metric-transformations \
  metricName=HTTP4xxErrors,metricNamespace=MyNamespace,metricValue=1,defaultValue=0

(--log-group-name だけは各々の環境に修正すること)

コンパネからするやり方だと

「ログ」を選択しアラームを作成するロググループをチェック

f:id:piyojir0:20190509161349j:plain

「メトリクスフィルタを作成する」を選択

[ip, id, user, timestamp, request, status_code=4*, size]

フィルタパターンに上記を入力して「メトリクスの割り当て」

f:id:piyojir0:20190509161150j:plain

2枚上画像のログ一覧から右側のメトリクスフィルタから作成したメトリクスを選択(数字を押す)

そしてアラームの作成 f:id:piyojir0:20190509161435j:plain

画像のように設定して通知先を先程作成したSNSトピックにする f:id:piyojir0:20190509161512j:plain

slackのwebhookURL確認

slackの設定から確認

こんな感じ

qiita.com

Lambdaの設定

「関数の作成」から以下を

ランタイムは「node.js 8.10」

4行目のwebhookUrlを環境に合わせる

var url = require('url');
var https = require('https');
 
var hookUrl = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
 
var processEvent = function(event, context) {
    var message = JSON.parse(event.Records[0].Sns.Message);
 
    // Format Slack posting message
    var text = "<!channel> *" + message.AlarmDescription + "* state is now `" + message.NewStateValue + "`\n" +
               "```" + 
               "reason: " + message.NewStateReason + "\n" +
               "alarm: " + message.AlarmName + "\n" + 
               "time: " + message.StateChangeTime +
               "```"
               ;
 
    var slackMessage = {
        text: text
    };
 
    postMessage(slackMessage, function(response) {
        if (response.statusCode < 400) {
            console.info('Message posted!');
            context.succeed();
        } else if (response.statusCode < 500) {
            console.error("4xx error occured when processing message: " + response.statusCode + " - " + response.statusMessage);
            context.succeed(); // Don't retry when got 4xx cuz its request error
        } else {
            // Retry Lambda func when got 5xx errors
            context.fail("Server error when processing message: " + response.statusCode + " - " + response.statusMessage);
        }
    });
};
 
var postMessage = function(message, callback) {
    var body = JSON.stringify(message);
    var options = url.parse(hookUrl);
    options.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();
};
 
exports.handler = function(event, context) {
    if (hookUrl) {
        processEvent(event, context);
    } else {
        context.fail('Missing Slack Hook URL.');
    }
};

トリガーにSNSを設定

先程作ったトピックネームを選択

SNSとLambdaの設定

SNSサブスクリプションを作成する

プロトコルは「Lambda」

エンドポイントは先程作成したLambda関数を選択

f:id:piyojir0:20190509161724j:plain

確認

400エラーを発生させてみる

きた

f:id:piyojir0:20190509161621j:plain

まとめ

あくまでログから判断する擬似的な外形監視なので500エラーは検知できない。 それをやるならほんとうに外側からやる必要がある。

いざやってみると複数のサービスで作成順番があるのでちょっと混乱した。

SNSないからCloudWatchの通知ないやんけとか)

一度つくって理解しとくと作業自体は簡単