日: 2018年10月3日

  • CloudWatch Logsで任意の文字列を監視し、メールで通知する

    CloudWatch Logsで任意の文字列を監視し、メールで通知する

    はじめに

    CloudWatch Logsで集めたログの中で任意の文字列(例えば、Errorとか、Criticalとか)が記載されていた場合、メールなどで通知させたい事がある。

    Node.jsをLambdaで動かす事で文字列監視を実装した。

    通知先の作成

    まずはSNSでメールの宛先から作成しARNを控え、エンドポイントとなるメールアドレスを設定する。 

    node.js(lambda)

    関数コードを編集

     

    ERROR、CRITICALという文字列があったら監視するスクリプト

    var zlib = require('zlib');
    var aws = require('aws-sdk');
    var sns = new aws.SNS({ region: 'ap-northeast-1' });
    exports.handler = function(input, context, callback) {
      var data = new Buffer(input.awslogs.data, 'base64');
      zlib.gunzip(data, function(e, rst) {
        if (e) {
          callback(e);
        } else {
          rst = JSON.parse(rst.toString('utf-8'));
          var errL = rst['logEvents']
              .filter(function(evt) { return evt['message'].match(/ERROR/i) ;})
              .filter(function(evt) { return !evt['message'].match(/$^/) ;})
              .map(function(evt) { return evt['message'] });
          console.log('processing[Error]' + errL.length + '/' + rst['logEvents'].length + ' events.');
          var critL = rst['logEvents']
              .filter(function(evt) { return evt['message'].match(/CRITICAL/i) ;})
              .filter(function(evt) { return !evt['message'].match(/$^/) ;})
              .map(function(evt) { return evt['message'] });
          console.log('processing[Crit]' + critL.length + '/' + rst['logEvents'].length + ' events.');
          if (errL.length === 0 && critL.length === 0) { callback(); return; }
          var date = new Date();
          date.setTime(date.getTime() + 1000*60*60*9);
          var dateTime = date.getFullYear() + '/' + ("0" + (date.getMonth() + 1)).slice(-2) + '/' + ("0" + date.getDate()).slice(-2) +
               ' ' + ("0" + date.getHours()).slice(-2) + ':' + ("0" + date.getMinutes()).slice(-2) + ':' + ("0" + date.getSeconds()).slice(-2);
          if (0 < errL.length) {
            // has error log
            var sjct = '[Error] Notify From CloudWatch Logs';
            var pl = { default: '' };
            pl['default'] += 'NotifyAt: ' + dateTime.valueOf() + '\n';
            pl['default'] += 'Log: ' + rst['logGroup'] + ' - ' + rst['logStream'] + '\n';
            pl['default'] += 'Filter: ' + rst['subscriptionFilters'] + '\n';
            pl['default'] += 'Messages:\n';
            pl['default'] += errL.join('\n---\n');
            sns.publish({
              Subject: sjct,
              Message: JSON.stringify(pl),
              MessageStructure: 'json',
              TargetArn: 'arn:aws:sns:ap-northeast-1:1234567890(your no):(your arn)'
            }, function(err, data) {
              if (err) {
                callback(err);
              } else if (0 < critL.length) {
                // has waring too
                var sjct = '[Critical] Notify From CloudWatch Logs';
                var pl = { default: '' };
                pl['default'] += 'NotifyAt: ' + dateTime.valueOf() + '\n';
                pl['default'] += 'Log: ' + rst['logGroup'] + ' - ' + rst['logStream'] + '\n';
                pl['default'] += 'Filter: ' + rst['subscriptionFilters'] + '\n';
                pl['default'] += 'Messages:\n';
                pl['default'] += critL.join('\n---\n');
                sns.publish({
                  Subject: sjct,
                  Message: JSON.stringify(pl),
                  MessageStructure: 'json',
                  TargetArn: 'arn:aws:sns:ap-northeast-1:1234567890(your no):(your arn)'
                }, function(err, data) {
                  if (err) callback(err);
                  else callback(null, data);
                });
              } else {
                callback(null, data);
              }
            });
          } else {
            // has NOT error log == criticaling only
            var sjct = '[Critical] Notify From CloudWatch Logs';
            var pl = { default: '' };
            pl['default'] += 'NotifyAt: ' + dateTime.valueOf() + '\n';
            pl['default'] += 'Log: ' + rst['logGroup'] + ' - ' + rst['logStream'] + '\n';
            pl['default'] += 'Filter: ' + rst['subscriptionFilters'] + '\n';
            pl['default'] += 'Messages:\n';
            pl['default'] += critL.join('\n---\n');
            sns.publish({
              Subject: sjct,
              Message: JSON.stringify(pl),
              MessageStructure: 'json',
              TargetArn: 'arn:aws:sns:ap-northeast-1:1234567890(your no):(your arn)'
            }, function(err, data) {
              if (err) callback(err);
              else callback(null, data);
            });
          }
        }
      });
    };
    

     

    トリガーを設定

    今回はCloudWatch Logsがトリガーとなるので、CloudWatch Logsを選択し、その後対象のログを選択する。

     

    通知先の設定

    Amazon SNSのARNを選択する(予めSNSでトピックを作っておく必要がある)

    以上