BBH
-Biz Branding Hub-
投稿日 : 
2019/09/14
更新日 : 
2019/09/14

LambdaでCloudWatchLogsからのペイロードを扱う(pythonサンプル)

CloudWatchLogsには、ログの内容をLambdaに飛ばして処理を行う、サブスクリプションフィルタという機能が存在します。

この機能を使う際、Lambda側でCloudWatchLogsの内容を受け取って処理する必要があるのですが、この方法がなかなかクセがあり最初は難しいです。
今回は、その方法について解説していきます。

CloudWatchLogsからLambdaに連携されるデータの3つの特徴

CloudWatchLogsからLambdaに飛ばされるログは以下の三つの特徴があります。
・ある程度のログのまとまりが連携される。
・base64エンコードされている。
・gzip圧縮されている。

LambdaでCloudWatchLogsからのデータを扱うには、この三つの特徴を理解した上で処理を行う必要があります。
以下、それぞれの特徴について解説していきます。

ある程度のログのまとまりが連携される

サブスクリプションフィルタで飛ばされるCloudWatchLogsは、ある程度の塊になっています。
ログの1行1行が飛ばされるわけではないということです。

1行ずつ飛ばしていると、通信コストがかさんでしまうので、ある程度まとまった量が出力されたら連携するという方式をとっているのです。
ですから、Lambdaで処理する際は、ループで1行ずつ処理していくのが定石になります。

base64エンコードされている

これはそのままです。
連携されるデータはbase64エンコードされているので、Lambda上で編集などを行う場合は、デコードしてやる必要があります。

gzip圧縮されている

こちらもそのままですね。
送られてくるデータはgzip圧縮されているので、処理する際はまず解凍してやる必要があります。

CloudWatchLogsを処理するサンプル

以下にCloudWatchLogsを処理するLambdaのサンプルを紹介します。
使用言語はPythonになります。

Lambda(Python)

import json
import base64
import gzip

def lambda_handler(event, context):
    print('event =' + str(event))
    
    # CloudWatchLogsから受け取ったデータはbase64エンコードされているため、デコード処理を行う
    decoded_data = base64.b64decode(event['awslogs']['data'])
    
    # ログ本体のデータ(awslogs.data)はバイナリに圧縮されているため、gzip解凍する
    json_data = json.loads(gzip.decompress(decoded_data))
    
    # ログデータを1件ずつループしてログ出力
    for log in json_data['logEvents']:
        print(str(log['message']))
    
    return 

具体的なデータの変化

サンプルソースだけだと、実際のデータがどのように変化していっているのかがわかりにくいかと思います。
参考までにデータがどのように変化していっているかも載せておきます。

CloudWatchLogsからの生データ

CloudWatchLogsから送られた直後の生データです。
awslogsの下にdataのみがついている状態です。

CloudWatchLogsからの生データ

{'awslogs': 
    {
        'data': 'pIowREIIzlS6fmCy4eLsQ0WhLeDQBkERRwTZ/N4325ZKsGFvyNaD75n9QvhYKL4CKtVD6Aqhz81Fh+N3xPtHktYNLToscfIfO4SHww25JqaiLBUKS06wlCxuqDhXUA6pIowREIIzlS6fmCy4eLsQ0WhLeDQBkERRwTZ/N4325ZKsGFvyNcC2MZJSZtKBOcU3PiQhirooU/G3+c3RTcOHy4LtjZo+0eFQvyaV573U+drb1byrEbaD75n9QvhYKL4CKtVD6AqhcC2UvgKq1UP6AHu6/6LZDuUQDAAA='
    }
}

base64デコード後

dataを取り出してデコードしたものです。
gzip圧縮されているのは、dataのみなので、以降は取り出して処理をしています。

base64デコード後

b"x08\x05\x1e7\x12s\x02T2\xe0D\t\xc2\x84`@\x00G\xb3\xe0\xe2\xedBD\xa3m\xcab\t\x80\xa4\x8cJ\xb2\xf9\xbbi\xac/\x17\xb3bl\xd3\xaf\x01\xdd7\xff\x83\xa6k\xa1\xf0\x02(\xac\x85\x92\x17@\xc9Z(}\x01\x94\xae\x85\xb2\x07\xf4p\xffe5eu\x90pj\x88\xc1:\xc5FP\x92\x1a\xd5\x10\xca\x19#\xe6\xc487V\xc6\n\x7f6\xfe8\xbb)\xb8q\xf8p]\xb0\xb3G\xdb=*\x16\xe4\xb3\xbc\xf6\xba\x9f:[{\xb7|\xc7n<7\x17\x1d\x8e\xdf\x11\xef\x1f&\xad\x1bZtXt\xf2\x1f;\x84G\xc3\r\xb9&Z\x11\xaa\xb8\xc4B(\nL\xa5\x84\x08\xca\xb0P\x8aI\xa9\x08\x05\x1e7\x12s\x02T2\xe0D\t\xc2\x84`@\x00G\xb3\xe0\xe2\xedBD\xa3m\xcab\t\x80\xa4\x8cJ\xb2\xf9\xbbi\xac/\x17\xb3bl\xd3\xaf\x01\xdd7\xff\x83\xa6k\xa1\xf0\x02(\xac\x85\x92\x17@\xc9Z(}\x01\x94\xae\x85\xb2\x07\xf4p\xff\x05\x8a\xb8\xd0\x8fD\x03\x00\x00"

gzip解凍後

解凍することによって、だいぶデータの意味が分かるようになってきました。
後は、好きな項目を取得して編集していくだけです。

gzip解凍後

{
  'messageType': 'DATA_MESSAGE', 
  'owner': '111111111111111', 
  'logGroup': '/aws/lambda/sample_lambda', 
  'logStream': '2019/09/09/[$LATEST]82fd3b0a10b7431b9d346553bf566be8', 
  'subscriptionFilters': ['LambdaStream_sample_simple_cloudwatchlogs_logging'], 
  'logEvents': [
                                  {
                                      'id': '34968077942591337450799588934260778063248526397357752320', 
                                      'timestamp': 1568022845483, 
                                      'message': 
                                      'SampleLog1\n'
                                  }, 
                                  {
                                      'id': '34968077942591337450799588934260778063248526397357752321', 
                                      'timestamp': 1568022845483, 
                                      'message': 'SampleLog2\n'
                                  }, 
                                  {
                                      'id': '34968077942591337450799588934260778063248526397357752322', 
                                      'timestamp': 1568022845483, 
                                      'message': 'SampleLog3\n'
                                  }, 
                                  {
                                      'id': '34968077942591337450799588934260778063248526397357752323', 
                                      'timestamp': 1568022845483, 
                                      'message': 'SampleLog4\n'
                                   }
                              ]
}

アラートメールを送る

LambdaでCloudWatchLogsのログを扱う方法は以上です。
後は、SESやSNSを使用することでそのログをアラートメールとして飛ばすことも可能です。
LambdaからSESに飛ばすサンプルは以下で紹介していますので、ご参照ください。

Profile

管理人プロフィール

都内でITエンジニアをやってます。
変遷:中規模SES→独立系SIer→Webサービス内製開発
使用技術はその時々でバラバラですが、C#、AWSが長いです。
どちらかと言うとバックエンドより開発が多かったです。
顧客との折衝や要件定義、マネジメント(10名弱程度)の経験あり。
最近はJava+SpringBootがメイン。

Recommend