8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ELBのAccess Logを解析して特定の条件でLambda経由でSNS通知

Last updated at Posted at 2015-06-04

前書き

Amazon Loadbalancer(ELB)を使っていると、『ELBのAccess logを解析して特定の条件(例えばStatus code != 200)が存在すればAlarmを飛ばす』と言う事をやりたい事が多いと思います。

Status CodeであればCloudWatchのHTTPCode_Backend_5XX等のMetricsを使えば簡単に出来ます(ELBのCloud Watch Metricはここ参照)。このMetricsの条件に当てはまった時に、email等のAlarmを飛ばす様にAWS SNSを設定すれば良いです。が、これでAlarm通知は受け取れるんですが、Requestの詳細(URLとかRequest元のIPとか)を確認しようと思ったときに、S3に書き出されているELBの生Access logをみるしか有りません。これ、手作業でやろうとすると結構苦痛です。何故かLog fileがタブ区切りでもカンマ区切りでも無く、半角スペース区切りですし、、、。

ELBがS3にLogを書き出したタイミングで、AWS Lambdaを起動させて、Lambdaのnode.js内でAccess logを解析して、必要な情報を切り出してEmailの本文に含めれば楽ジャン、と思い、その設定手順やLambdaのscriptをチラ裏しておきます。

設定でのハマり箇所

  • ELBのLogがS3に吐きだされるAWS Regionと同じRegionに、Lambda, SNS Topicを作成してください
  • LambdaのFunctionを作成すると、Lambda functionを動かす為のIAM Roleを新規で作る様に進められます(既存の物を使い廻す事も可能)。このIAM roleに対して、AmazonSNSFullAccessをAttach Policyするのを忘れずに。これによりLambda FunctionからSNS通知がさらに発火出来る様になります
  • Lambda functionを作成後、Add event sourceで、監視するS3 bucketを設定して下さい
  • SNSのTopicSubscriptionsLambdaと同じAWS regionに作成し、Topicを発火させるとemail通知が行くように事前設定しておいて下さい。また TopicのARNをメモしておいてください

Debugでのハマり箇所

  • まず、Lambdaの編集画面で、左ペインのSample EventS3 Putを指定して、Invokeをクリックすると、Error getting object HappyFace.jpg from bucket sourcebucket...というエラーがでます。"key": "HappyFace.jpg""name": "sourcebucket"を先ほどAdd event sourceで設定したS3 bucket名とそのbucketに実際にあるlog fileに書き換えて、再度Invokeをクリックすると、このlog fileがS3 bucketに追加されたという想定でScriptが動作してくれます
  • Lambdaの編集画面でInvokeさせて動かない場合は、CloudWatch -> LogsにFullのDebug logが吐き出されます

Lambdaのcode

  • TopicArnは自分の物に置き換えてください
  • 処理の流れは以下の通りです
  • S3 Bucketに変更があったら、1行づつ取り出して、checkStringに掛ける
  • checkStringELB Access Logの仕様を元に、半角スペース区切りで9番目の値がbackend_status_code、区切りの2番目がURL、、、と必要な要素を取り出す
  • Status Codeが200以外の場合は、その行をsnsParams.Messageに追記していき、最後にsns.publishで結果をSNS発火させる
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var sns = new aws.SNS({apiVersion: '2010-03-31'});
var snsParams = {
  Message: '',
  Subject: 'ELB log check alarm',
  TopicArn: 'arn:aws:sns:us-east-1:xxxxxxxx:yyyyyyyyyy'
};

exports.handler = function(event, context) {
  var bucket = event.Records[0].s3.bucket.name;
  var key = event.Records[0].s3.object.key;
  s3.getObject({Bucket: bucket, Key: key}, function(err, data) {
    if (err) {
      console.log("Error getting object " + key + " from bucket " + bucket +
        ". Make sure they exist and your bucket is in the same region as this function.");
      context.fail('Error', "Error getting file: " + err);
    }

    var contentBody = data.Body.toString(data.ContentEncoding);
    snsParams.Message += 'Upload filename:' + key.substr(key.lastIndexOf('/') + 1) + '\n';
    snsParams.Message += 'Data\tStatusCode\tSource IP\tURL\tUserAgent\n';

    contentBody.split('\n').forEach(function (line) {
      checkString(line);
    });

    sns.publish(snsParams, function() {
      context.succeed("success");
    });
  });
};

function checkString(line) {
  if (line !== '') {
    var status_code = line.split(' ')[8];
    var source_ip = line.split(' ')[2].split(':')[0];
    if (Number(status_code) != 200) {
      snsParams.Message += line.split(' ')[0].split('.')[0] + '\t' + status_code + '\t' + source_ip+ '\t' 
       + line.split('"')[1] + '\t' + line.split('"')[3] + '\n' ;
    }
  }
}

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?