aws

AWS Lambdaのログ運用ガイド|CloudWatch Logsの見方・JSON構造化・S3出力とコスト削減

AWS Lambdaの関数は、コードを1行も書き足さなくても実行のたびにログを吐き出します。送信先はAmazon CloudWatch Logsで、ロググループ名は既定で /aws/lambda/関数名 になります。問題になるのはたいてい「どこを見るか」ではなく、その先です。ログが出てこない、JSONで検索できない、請求書のCloudWatch Logs欄が関数本体より高い、といった問題です。この記事では、ログの保存先と3行(START/END/REPORT)の読み方から、設定だけで切り替えられるJSON構造化ログとログレベル、2025年5月に選べるようになったS3・Amazon Data Firehoseへの出力、そして保持期間を含めたコストの下げ方までを整理します。メトリクス(Errors・Throttles・Duration)やアラームによる監視はAWS LambdaをCloudWatchで監視する方法|標準メトリクス・ログ・アラーム・Lambda Insightsで扱っているため、本記事が扱うのはログです。

まとめ

  • Lambdaのログは既定で /aws/lambda/関数名 のロググループに入る。出ない場合、原因のほとんどは実行ロールの logs:CreateLogGroup / logs:CreateLogStream / logs:PutLogEvents の欠落。
  • REPORT行の Billed DurationMax Memory UsedInit Duration はメモリ設定とコールドスタートの調整に直結する。追加ツールなしで読める最も費用対効果の高い指標。
  • ログ形式(JSON/Text)、アプリケーションログレベル、システムログレベル、送信先ロググループは、コードではなく関数の設定(LoggingConfig)で切り替える。ロギングライブラリの導入は不要。
  • 2025年5月1日にLambdaのログがCloudWatch LogsのVended Logs扱いになり、階層別料金とS3・Data Firehoseへの直接出力が使えるようになった。ただしS3・Firehose宛はDeliveryログクラスとなり、CloudWatch Logs Insightsでの検索ができない。
  • コスト削減は「保持期間の設定 → ログレベルの引き上げ → 出力先の変更」の順で着手する。出力先の変更は最も手間が大きく、検索性を失う代償が伴う。

Lambdaのログはどこに保存され、何が書かれているか

ロググループ名と実行ロールに必要な3つの権限

Lambdaは関数の実行ログをCloudWatch Logsへ送る仕組みです。AWS公式ドキュメントは「デフォルトで、これらのログは /aws/lambda/<function-name> という名前のロググループに保存されます」と明記しています。マネジメントコンソールの関数画面「モニタリング」タブから「CloudWatchログを表示」を押すと同じ場所へ移動できます。

ログが1行も出てこないときに疑うべきは関数のコードではなく実行ロールです。公式ドキュメントは、ログをアップロードするために実行ロールへ次の3つのアクセス許可が必要としています。

  • logs:CreateLogGroup
  • logs:CreateLogStream
  • logs:PutLogEvents

コンソールから関数を作ると付与される AWSLambdaBasicExecutionRole に含まれるのがこの3つです。一方、IaCで最小権限のロールを自作した場合や、後述するカスタムロググループへ送信先を変えた場合は、対象のロググループARNに対する許可が抜けて無言でログが消えます。関数自体はエラーにならないため、気づくのが遅れやすい点に注意してください。

START・END・REPORT行から読み取れる情報

ランタイムは呼び出しごとに STARTENDREPORT の3行を自動で記録します。実務で価値があるのはREPORT行で、公式ドキュメントが定義するフィールドは次のとおりです。

フィールド 意味 使いどころ
RequestId 呼び出しの一意のリクエストID ログ横断の突き合わせキー
Duration ハンドラーがイベント処理に要した時間 処理そのものの遅さの把握
Billed Duration 課金対象の時間 実行時間コストの試算
Memory Size 関数に割り当てられたメモリ量 設定値の確認
Max Memory Used 実際に使用されたメモリの最大値 メモリ設定の過剰・不足の判定
Init Duration ハンドラー外のロードとコード実行に要した時間 コールドスタートの実測
XRAY TraceId / SegmentId / Sampled トレース対象時のX-Ray情報 分散トレースとの接続

Max Memory UsedMemory Size の半分以下で張り付いているなら、メモリ設定を下げる余地があると判断できます。逆に上限に貼り付いていれば、メモリを増やしたほうが割り当てCPUも増えて Billed Duration が縮み、結果的に安くなるケースもあるためです。Init Duration が出るのは実行環境が新しく作られた呼び出しだけで、これがコールドスタートの発生回数と所要時間の一次情報になります。Max Memory Used は実行環境が使い回された場合、その環境で観測された最大値が報告される点にも注意が必要です。Javaなどで初期化が重い場合は、Lambda SnapStartの概要とその基本的な特徴とはで扱う起動高速化の対象になります。

ログ形式とログレベルを設定だけで切り替える

LoggingConfigの4項目と指定できる値

かつてはJSON形式で構造化ログを出すために外部ライブラリを入れる必要があったが、現在はLambdaの関数設定(LoggingConfig)で完結します。APIリファレンスが定義する4項目は次のとおりです。

項目 指定できる値 既定・制約
LogFormat JSON | Text アプリケーションログとシステムログ両方の形式
ApplicationLogLevel TRACE | DEBUG | INFO | WARN | ERROR | FATAL 関数コードが出すログのフィルタ(TRACEが最も詳細)
SystemLogLevel DEBUG | INFO | WARN Lambdaが出すログのフィルタ
LogGroup 1〜512文字 / [.\-_/#A-Za-z0-9]+ 既定は /aws/lambda/<function name>

ログレベルのフィルタはJSON形式を選んだときにだけ有効です。アプリケーションログとシステムログのレベルを別々に決められるのが効く点で、「関数のDEBUGログは残したいがLambdaランタイム側の詳細は要らない」という調整がコード変更なしに行えます。

JSON構造化ログのフィールドとログの検索性

JSON形式にすると、各ログイベントに timestamplevelmessagerequestId が標準フィールドとして付く点が違いです。Pythonの logging ライブラリを使えば logger も加わり、例外時には stackTraceerrorTypeerrorMessagelocation も付与されます。

この違いはCloudWatch Logs Insightsのクエリで顕在化する点です。テキスト形式では文字列マッチに頼るしかない絞り込みが、JSON形式ならフィールド指定で書けます。

fields @timestamp, level, requestId, message
| filter level = "ERROR"
| sort @timestamp desc
| limit 20

なお、JSON形式では print() で出した文字列も message に包まれるが、ログレベルを持たないため level によるフィルタ対象になりません。構造化の恩恵を受けるなら、関数コード側は標準の logging(Node.jsなら console.info などレベル付きのメソッド)で出す必要があります。

AWS CLIでの設定とカスタムロググループの落とし穴

既存関数への適用はコンソールの「設定 > モニタリングおよび運用ツール」から、あるいはCLIで行います。

aws lambda update-function-configuration \
  --function-name my-function \
  --logging-config LogFormat=JSON,ApplicationLogLevel=INFO,SystemLogLevel=WARN

送信先ロググループを変えるなら LogGroup=/my-app/shared のように指定してください。複数関数のログを1つのロググループに集約するとLogs Insightsの横断検索が単純になる一方、実行ロールの許可をそのロググループへ向け直す必要があります。前述の AWSLambdaBasicExecutionRole は既定名のロググループを前提にしたスコープであるため、カスタムロググループを指定したまま権限を直さないとログだけが静かに消えます。設定変更後は必ず1回実行してログイベントが着地するかを確認したい。

出力先をCloudWatch Logs・S3・Data Firehoseから選ぶ

2025年5月のVended Logs化と階層別料金

2025年5月1日、LambdaのログはCloudWatch LogsのVended Logsとして扱われるようになり、同時に出力先としてAmazon S3とAmazon Data Firehoseを直接選べるようになりました。従来はCloudWatch Logs一択で、S3へ落とすにはサブスクリプションフィルタとFirehoseを自前で組む必要がありました。

料金面ではボリュームディスカウントが入った点も変更点です。DevelopersIOの検証記事によると、米国東部(バージニア北部)でCloudWatch Logs宛は0.50 USD/GBから、S3・Data Firehose宛は0.25 USD/GBから始まり、使用量に応じて0.05 USD/GBまで下がります。日本国内の環境で見積もるときは、東京リージョンの単価をAmazon CloudWatchの公式料金ページで確認したうえで、自社の月間取り込み量をティアに当てはめてください。単価は改定されることがあります。

Deliveryログクラスの制約と、S3出力を選ぶべきでない場面

S3・Data Firehoseを出力先にすると、ログはDeliveryログクラス扱いです。ここに実務上の分岐点があります。Deliveryログクラスは保持期間が2日に固定され、CloudWatch Logs Insightsをはじめとする多くの機能が使えません。つまり「安いほうへ寄せる」と、障害調査でいつも使っているクエリ検索を失います。

判断はこう置くのが妥当です。障害調査でLogs Insightsを日常的に使っているなら、S3・Firehose出力は選ぶべきではありません。単価差で浮く金額より、調査導線を作り直すコストのほうが大きくなります。S3出力が合うのは、監査ログや長期保管が目的で、検索はAthenaなど別基盤で行うと決まっている場合、あるいはSIEMやデータ基盤へ集約する前段としてFirehoseを使う場合に限られます。取り込み量が数十GB規模でなければ、単価差そのものが月数十ドル程度に収まる点も踏まえたい。

ログのコストを下げる3つのレバーと着手順

CloudWatch Logsの請求は、取り込み(ingestion)と保存(storage)の2つで発生します。効くレバーは3つあり、手間と副作用の小ささから次の順で着手するのが合理的です。

  • 1. 保持期間を設定する:CloudWatchのロググループは既定で無期限保持になる。作りっぱなしのロググループは保存料金を積み上げ続けるため、まず1日・3日・7日といった保持期間を全ロググループに設定する。副作用がほぼなく、既存ログにも即効性がある唯一のレバー。
  • 2. ログレベルを引き上げるApplicationLogLevel をDEBUGからINFOやWARNへ、SystemLogLevel をWARNへ寄せて取り込み量そのものを削る。コード変更が不要で、必要なときだけ一時的にDEBUGへ戻せる。
  • 3. 出力先を変える:ここまでやってなお取り込み量が大きい場合に、S3・Data Firehoseを検討する。前節のとおり検索性を失うため、最後に回す。

Lambda@Edgeを使っている場合、保持期間の設定は特に見落としやすくなります。ロググループは実行されたエッジロケーションに近いリージョンに作られるため、us-east-1だけを見て設定しても他リージョンに無期限保持のロググループが残り続ける点に注意してください。

出力したログを検索・分析する

ロググループを開いてログストリームを1つずつ追う運用は、関数が数個を超えた時点で破綻します。CloudWatch Logs Insightsを使えば複数ロググループを横断してクエリでき、JSON形式のログならフィールド単位で集計まで書けます。エラー率をリクエスト単位で数えたい場合は、REPORT行のRequestIdが軸です。クエリ構文と機能の詳細はCloudWatch Logs Insightsの概要と機能にまとめています。

デプロイ直後の切り分けなど、いま流れているログを見たい場面ではCloudWatch LogsのLive Tailを使ってください。クエリを実行し直さずにログイベントが流れてくるため、テスト実行しながらの確認に使えます。

ログだけでは因果が追えない場面もあります。API Gateway、Lambda、DynamoDBとリクエストが複数サービスをまたぐ場合、どこで時間を使っているかはREPORT行のDurationからは読めません。この層はトレースの担当で、AWS X-Rayとは|CloudWatchとの違いとOpenTelemetry移行後の使い方【2026年版】で扱う分散トレーシング、あるいはサービス単位のSLO監視を担うApplication Signalsとは何か?概要と基本機能をやさしく解説と組み合わせてください。

ログが出ない・多すぎるときのチェックリスト

問い合わせが多い症状と、確認すべき箇所を並べます。

症状 最初に見る箇所
ログが1件も出ない 実行ロールのlogs:CreateLogGroup / CreateLogStream / PutLogEvents
カスタムロググループに変えたら消えた 実行ロールの許可対象ロググループARN
DEBUGログだけ出ない ApplicationLogLevelの設定値(JSON形式でのみ有効)
print出力がフィルタできない ログレベルを持たないためlevelで絞れない。loggingへ移行
Lambda@Edgeのログが見つからない us-east-1以外のリージョン。ロググループ名は/aws/lambda/us-east-1.関数名
請求のCloudWatch Logsが高い ロググループの保持期間(既定は無期限)と取り込み量

よくある質問

AWS Lambdaのログはどこにありますか

CloudWatch Logsの /aws/lambda/関数名 ロググループです。Lambdaコンソールの関数画面「モニタリング」タブから「CloudWatchログを表示」で直接開けます。送信先は関数設定のLogGroupで変更が可能です。

Lambda@Edgeのログはどこに出力されますか

関数はus-east-1で作成しますが、ログは実行されたエッジロケーションに近いリージョンのCloudWatch Logsに保存されます。ロググループ名には作成リージョンの接頭辞が付き /aws/lambda/us-east-1.関数名 という形です。us-east-1だけを見て「ログが無い」と判断しないことが大事です。

ログがまったく出力されません。何を確認すればよいですか

実行ロールに logs:CreateLogGrouplogs:CreateLogStreamlogs:PutLogEvents があるかを最初に確認します。カスタムロググループを指定している場合は、許可の対象ARNがそのロググループを含んでいるかも見てください。権限不足でも関数の実行自体は成功するため、実行結果からは気づけません。

Lambdaログの保存期間はどう設定しますか

CloudWatch Logs側のロググループごとに保持期間を設定します。既定では無期限保持で、放置すると保存料金が増え続けます。関数を削除してもロググループは残るため、不要なロググループの棚卸しも合わせて行ってください。

ログをS3に出力するとコストはどれくらい下がりますか

米国東部(バージニア北部)の公表値では、CloudWatch Logs宛が0.50 USD/GBから、S3・Data Firehose宛が0.25 USD/GBからで、いずれも使用量に応じて0.05 USD/GBまで下がります。ただしS3・Firehose宛はDeliveryログクラスとなり保持期間は2日固定、CloudWatch Logs Insightsが使えません。調査に検索を使っているなら、単価差だけで判断しないでください。

関連記事

資料請求

RELATED POSTS 関連記事