■ はじめに
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
を設定する必要があります。
-
put_log_events - CloudWatchLogs — Boto3 Docs 1.16.15 documentation
- 新しく作成されたログストリームでのアップロードには、シーケンストークンは不要。
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)。
- クォータの引き上げをリクエスト可。
- 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)。
- クォータの引き上げをリクエスト可。
- 1 秒、1 ログストリームあたり 5 リクエスト。
今回のやり方にしたところ遅延が解消されましたので、使い方にもよりますが、出力する頻度が多い場合は put_log_events
を使ったほうが良い様に思います。
逆に、今回のやり方でも遅延が発生が解消されない場合は、別のやり方を検討する必要があるかもしれません。
■ 出力先のログストリームの存在確認
上述した記事 ( Lambda (Python) から特定のログストリームにログを書こうとして苦戦した2つのポイント - Qiita ) では、describe_log_streams
で、sequenceToken
の取得だけではなく、ログストリームの存在確認も行っていましたが、クォータの制限により describe_log_streams
は使えませんので、別のやり方で確認する必要があります。
ただ、これも put_log_events
の Exceptions
で確認出来るみたいです。ResourceNotFoundException
に入ってきたらログストリームが存在しないということで、create_log_stream
を実行します。
■ ハマりポイント
-
上述しましたが…、最初は問題無かったのにリクエスト頻度が増えるに連れて Lambda の実行時間が伸びて非常に困りました。当然、コストにも跳ね返ってきますしね…。
-
とりあえず、AWS サポート さんに相談して良かったです。Boto3 documentation — Boto3 Docs 1.16.16 documentation に記載されているものの、相談しなかったら、見つけられなかった気がします…。どうもありがとうございました。🙇♂️🙇♂️🙇♂️
■ まとめ
参考になれば♪
👋👋👋