PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

AWS Lambda のログの S3 出力が簡単になりました

杉嵜 諒吾です。戸籍の振り仮名は問題ありませんでした。

今年の5月よりLambdaのログ出力に仕様変更がありました。料金計算の際に Vended Logs として計上されるようになったほか、Vended Logs として S3 や Data Firehose へ出力できるようになりました。CloudWatch Logs 以外でのログ管理がしやすくなった他、S3 や Firehose へログ出力する際は料金面でも優遇されます。

ローンチ時のブログ記事では AWS コンソール上での設定方法を説明されていますが、Lambda 関数を AWS SAM で作っている身としては、できれば SAM テンプレートでまとめて設定しておきたいところです。今回ドキュメントを探したり、AWS Japan 様に問い合わせたりして作れるようにはなりましたが、自分の備忘も兼ねて記事にまとめることにしました。

今回変わったこと

今まで通りにLambda関数を作成した場合、ログはこれまで通りにCloudWatch Logsで取込・保存され、参照もCloudWatch Logsの機能で行うことになります。ログ運用を変える予定が無い場合は、今回のローンチ以降も変更すべきことはありません。

一方、CloudWatch Logsに取り込まれたログをS3へファイル出力したい場合、従来はAWSコンソールなどから手動でエクスポートするか、Data Firehose を使う必要がありました。これが今回のローンチ以降、Lambda から取り込むログを CloudWatch Logs で取り込んだ後、S3 バケットに直接出力することが可能になりました

また Lambda から取り込まれるログは Vended Logs に分類されるようになったため、 S3 や Data Firehose への出力に変更する場合は、CloudWatch Logs のログ取込料金が大幅に安くなります

CloudWatch Logs の料金

1GBあたりの料金(USD、2025年8月現在の東京リージョン)

通常のログ
(標準クラス)
Vended Logs Vended Logs
S3 出力
Vended Logs
Firehose 出力
取込 (~10TB/月) 0.760 0.760 0.380 0.380
取込 (10~30TB/月) 0.760 0.380 0.228 0.228
取込 (30~50TB/月) 0.760 0.152 0.114 0.114
取込 (50TB以降/月) 0.760 0.076 0.076 0.076
保存 (月あたり)*1 0.033 0.033 (S3 料金) -

料金 - Amazon CloudWatch | AWS

CloudWatch Logs の料金で支配的になりやすいのはログの取込料金ですが、Vended Logs に分類されるサービスのログ取込では、毎月 10TB 以降の取込料金にボリュームディスカウントがあります。加えて、Vended Logs で S3 や Firehose 出力にした場合、毎月 50TB までの取込料金が大幅に安くなります。50TB 以降は Logs 出力と S3 / Firehose 出力で取込料金が同じになりますが、東京リージョンの場合は 50TB までの累計で 7,600 USD の差が出ることになります。

なお従来より VPC フローログや Route 53 のクエリログ、AWS WAF のログなども Vended Logs に分類されており、ボリュームディスカウントはそれらのデータ量の合計を元に適用されます。そのため、AWS Lambda 単体で毎月 10 TB に満たない場合でもボリュームディスカウントが適用されることがあります。

取込料金の一例(クリックで展開)

単位 : USD / 月

通常のログ
(標準クラス)
Vended Logs Vended Logs
S3 / Firehose 出力
10 TB/月 7,600 7,600 3,800
30 TB/月 22,800 15,200 8,360
50 TB/月 38,000 18,240 10,640
100 TB/月 76,000 22,040 14,440

S3出力にする場合の構築

AWSのドキュメントでは、コマンドで作る方法が書かれています。

Sending Lambda function logs to Amazon S3 - AWS Lambda

Lambda のログが Vended Logs になった際、CloudWatch Logs ロググループのログクラスに "Delivery" が追加されました。これは現状、Lambda からログを取り込んで S3 や Data Firehose に出力する専用のログクラスです。今回の構築は、Lambdaからログを取り込むロググループをログクラス Delivery で作り、サブスクリプションフィルターで S3 への出力設定をすることになります。

Log classes - Amazon CloudWatch Logs

なおロググループのログクラスは後から変更できないため、既存の Lambda 関数のログをS3出力に変更する際は、ロググループを新たに作ることになります。

SAMテンプレート例

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  test of vended logs delivery from lambda functions

Globals:
  Function:
    Timeout: 3
    MemorySize: 128

Resources:
  VendedLogsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-vended-logs"
      VersioningConfiguration:
        Status: Enabled
      AccessControl: Private

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.13
      Architectures:
        - x86_64
      LoggingConfig:
        LogFormat: Text
        LogGroup: !Ref HelloWorldFunctionLogGroup

  # ログクラス DELIVERY でロググループを作る
  HelloWorldFunctionLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupClass: "DELIVERY"
      LogGroupName: !Sub "${AWS::StackName}-vended-logs"
  
  # DestinationArn に S3 バケットを指定
  SubscriptionFilter:
    Type: AWS::Logs::SubscriptionFilter
    Properties:
      FilterPattern: ""
      Distribution: "ByLogStream"
      LogGroupName: !Ref HelloWorldFunctionLogGroup
      ApplyOnTransformedLogs: false
      FilterName: "lambda-logs-delivery"
      DestinationArn: !GetAtt VendedLogsBucket.Arn
      RoleArn: !GetAtt SubscriptionFilterRole.Arn

  SubscriptionFilterRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: logs.amazonaws.com
            Condition:
              StringLike:
                aws:SourceArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
            Action: sts:AssumeRole
      Policies:
        - PolicyName: "AllowS3Write"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject
                Resource: !Sub "${VendedLogsBucket.Arn}/*"

ロググループの保持期間は明記せずとも2日に設定されるようです。あくまでロググループで管理してるログストリームなどが消えるもので、S3 バケットに出力したログが消えるわけではありません。バケット内の古いログを削除したい場合はライフサイクルルールを設定しましょう。

動作確認

設定後にLambda関数を実行するとログストリームが作成されますが、CloudWatch Logs でのログイベント参照はできません。

S3 へのログ出力はログストリームごとに Zstandard 形式で圧縮して保存されます。ロググループの名前やアカウントIDなどでフォルダが分かれるので、複数のロググループから同じ S3 バケットに出力することもできます。出力した後のログは、例えば Amazon Athena で日時やロググループ名を指定して参照できます。

終わりに

今回のローンチにより、AWS Lambda を中心に構築されたシステムでのログ管理の選択肢が増える形となりました。単に CloudWatch Logs の料金を抑えられるというのもありますが、1つの S3 バケットにログを集約して一元管理する、Data Firehose 経由で Redshift やサードパーティ製のデータウェアハウスに送るなどの大規模なログの分析・管理を、Lambda のログでやりやすくなったと言えるでしょう。

*1:取込後に圧縮されるため、料金計算に使われるデータ量は取込時より小さくなります。CloudWatch Logsの料金ページでは圧縮率 0.15 が目安として示されていますが、実際にはログの内容などに依存します。