LoginSignup
6
5

More than 3 years have passed since last update.

Python (Boto3) @ Lambda で CloudWatch Logs の特定のログストリームにログを出力する

Last updated at Posted at 2020-11-12

■ はじめに

Python (Boto3) @ Lambda から CloudWatch Logs の特定のログストリームにログを出力したかったので、やってみました。

■ コード

コードは、以下。

def put_logs(client, group_name, stream_name_prefix, message):
    try:
        exist_log_stream = True
        log_event = {
            'timestamp': int(time.time()) * 1000,
            'message': message
        }
        sequence_token = None
        for i in range(2):
            try:
                if exist_log_stream == False:
                    create_log_stream_response = client.create_log_stream(
                        logGroupName = group_name,
                        logStreamName = stream_name_prefix)
                    exist_log_stream = True
                if sequence_token is None:
                    put_log_events_response = client.put_log_events(
                        logGroupName = group_name,
                        logStreamName = stream_name_prefix,
                        logEvents = [log_event])
                else:
                    put_log_events_response = client.put_log_events(
                        logGroupName = group_name,
                        logStreamName = stream_name_prefix,
                        logEvents = [log_event],
                        sequenceToken = sequence_token)
            except client.exceptions.ResourceNotFoundException as e:
                exist_log_stream = False
            except client.exceptions.DataAlreadyAcceptedException as e:
                sequence_token = e.response.get('expectedSequenceToken')
            except client.exceptions.InvalidSequenceTokenException as e:
                sequence_token = e.response.get('expectedSequenceToken')
            except Exception as e:
                print(e)
                break
    except Exception as e:
        print(e)

sequenceToken の取得の仕方

こちらの記事 ( Lambda (Python) から特定のログストリームにログを書こうとして苦戦した2つのポイント - Qiita ) にもありますが、put_log_events でログを PUT する際、例外はありますが、基本的には sequenceToken を設定する必要があります。

describe_log_streams による sequenceToken の取得

記事の中では describe_log_streams によって、ログストリームの存在判定と sequenceToken の取得を行っており、describe_log_streams のレスポンスから nextToken として取得しています。

ですが、実は CloudWatch Logs のクォータ - Amazon CloudWatch Logs にも書かれていますが、describe_log_streams にはクォータによる制限があります。

  • DescribeLogStreams
    • 1 リージョン、1 アカウントあたり 5 件のトランザクション/秒 (TPS)。
      • クォータの引き上げをリクエスト可。

その為、使い方にもよりますが、出力頻度が高い場合は、クォータの制限に引っ掛かり遅延が発生することがあり、実際、Lambda から結構な頻度でログを出力したところ、describe_log_streams での遅延が発生してしまいました。

put_log_events による sequenceToken の取得

そこで、AWS サポート に相談したところ、put_log_events による sequenceToken の取得を提案されました。

put_log_events - CloudWatchLogs — Boto3 Docs 1.16.15 documentation にも記載されていますが、InvalidSequenceTokenException からexpectedSequenceToken として取得出来るみたいです。

もちろん put_log_events にもクォータの制限はありますが、describe_log_streams より緩めです。

  • PutLogEvents
    • 1 秒、1 ログストリームあたり 5 リクエスト。
      • 追加のリクエストは調整され、クォータは変更不可。
    • 1 リージョン、1 アカウントあたり 800 件のトランザクション/秒 (TPS)。
      • クォータの引き上げをリクエスト可。

今回のやり方にしたところ遅延が解消されましたので、使い方にもよりますが、出力する頻度が多い場合は put_log_events を使ったほうが良い様に思います。

逆に、今回のやり方でも遅延が発生が解消されない場合は、別のやり方を検討する必要があるかもしれません。

■ 出力先のログストリームの存在確認

上述した記事 ( Lambda (Python) から特定のログストリームにログを書こうとして苦戦した2つのポイント - Qiita ) では、describe_log_streams で、sequenceToken の取得だけではなく、ログストリームの存在確認も行っていましたが、クォータの制限により describe_log_streams は使えませんので、別のやり方で確認する必要があります。

ただ、これも put_log_eventsExceptions で確認出来るみたいです。ResourceNotFoundException に入ってきたらログストリームが存在しないということで、create_log_stream を実行します。

■ ハマりポイント

  • 上述しましたが…、最初は問題無かったのにリクエスト頻度が増えるに連れて Lambda の実行時間が伸びて非常に困りました。当然、コストにも跳ね返ってきますしね…。

  • とりあえず、AWS サポート さんに相談して良かったです。Boto3 documentation — Boto3 Docs 1.16.16 documentation に記載されているものの、相談しなかったら、見つけられなかった気がします…。どうもありがとうございました。🙇‍♂️🙇‍♂️🙇‍♂️

■ まとめ

参考になれば♪

👋👋👋

6
5
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
6
5