Amazon Web Services ブログ

AWS Lambda の高度なログ制御機能のご紹介

この投稿は、 2023 年 11 月 16 日の シニアソリューションアーキテクトの Nati Goldberg 氏と AWS Lambda シニアプロダクトマネージャーの Shridhar Pandey 氏によるブログ記事を日本語化したものです。元の投稿はこちらをご覧ください。

AWS は本日、 AWS Lambda の高度なログ制御機能をリリースしました。これにより、開発者や運用者は関数のログのキャプチャ・処理・消費をより細かく制御できるようになりました。

今回3つの新機能がリリースされ、Lambda の標準的なログ体験が簡略化・強化されました。

まず、独自のロギングライブラリを用意せずとも、JSON 形式のログフォーマットで Lambda 関数のログをキャプチャできるようになりました。JSON 形式のログを利用すると、大量のログの検索・フィルタリング・分析がより簡単にできるようになります。

次に、Lambda 関数のログレベルの制御がコードの変更なしでもできるようになりました。これにより、デバッグやトラブルシューティングがより効率化されます。

最後に、Lambda 関数のログ転送先の Amazon CloudWatch ロググループをユーザ側で設定できるようになりました。これにより、大規模なログの集約と管理がより簡素化されます。

概要

重要な問題をトラブルシューティングし修正するためには、関連するログメッセージの特定やフィリタリングが必要不可欠です。開発者や運用者が障害を監視しトラブルシューティングできるように、Lambda サービスは自動的にログをキャプチャし、CloudWatch Logs に転送します。

これまで、Lambda 関数はプレーンテキスト形式、つまり非構造化ログ形式でログを出力していました。これにより、ログのクエリやフィルタリングが難しくなってしまう場合もありました。その一例としては、ユーザは START・END・REPORT といったよくある文字列識別子、または関数呼び出し時のリクエスト ID を使って手動でログの検索と関連付けを行う必要があったことが挙げられます。また、ネイティブでアプリケーションログをエンリッチする方法がなかったため、自動分析を行ったり分析ダッシュボードを構築したりするにはユーザ側でログからのデータ抽出に対応する必要がありました。

これまで、運用者は関数のログレベルを制御することができず、INFO・DEBUG・ERROR などの必要なログレベルに設定するには、アプリケーション開発チームにコードを変更してもらう必要がありました。

Lambda ベースのアプリケーションは多くの場合複数のマイクロサービスで構成され、それぞれのマイクロサービスが複数の単一目的の Lambda 関数で構成されます。このリリースより以前は、Lambda 関数のログは関数作成時に作成されるデフォルトの CloudWatch ロググループに送信され、ロググループの指定はできませんでした。今では、複数の関数のログを一箇所に集約できるようになったため、セキュリティやガバナンスおよび保持ポリシーを一括で適用できるようになりました。

JSON 形式のログフォーマットで Lambda のログをキャプチャする

この度のリリースで、Lambda は一連のキーバリューペアの形で構造化ログを JSON 形式でキャプチャすることをネイティブサポートするようになりました。これにより、ログの検索とフィルタリングがより簡単にできるようになりました。

JSON 形式の構造化ログを利用する場合、ログに独自のタグやコンテキスト情報を追加することもできるため、大量のログを自動的に分析できるようになり、これは関数のパフォーマンスを理解するのに役立ちます。Lambda の JSON 形式のログフォーマットは人気のオープンソースロギング標準である OpenTelemetry(OTel)の Logs Data Model に準拠するため、関数の監視にオープンソースのツールをご利用いただけます。

コンソールからログフォーマットを変更するには、設定タブを選択した上左側のパネルからモニタリング及び運用ツールを選択し、そしてログフォーマットのプロパティを変更をします。

3

Lambda はアプリケーションログ(関数コードが生成するログ)とシステムログ(Lambda サービスが生成するログ)を JSON 形式のログフォーマットでキャプチャすることをネイティブサポートするようになりました。

これは、Python、Node.js、Java の非推奨バージョンを除く各バージョンの Lambda ランタイムを利用した関数で、Lambda 推奨のロギング方法(例えば、Python では logging ライブラリ、Node.js ではコンソールオブジェクト、Java の場合では LambdaLogger または Log4j が推奨されています)を使って出力したログに適用されます。

その他のランタイムの場合、現時点ではシステムログのみ JSON 形式のログフォーマットでのログキャプチャがネイティブサポートされています。とはいえ、手動でロギングライブラリを設定すれば、アプリケーションログをJSON 形式のログフォーマットでキャプチャすることが可能です。より詳しくは、Lambda の開発者向けガイドの Configuring advanced logging controls for your Lambda function のセクション(英語のみ)をご参照ください。また、 Powertools for AWS Lambda を使用した JSON 形式のログフォーマットでのログのキャプチャも可能です。

テレメトリーパイプラインでログをパースしている場合、ログフォーマットをテキストから JSON に変更することはシステムに深刻な影響を与えてしまう可能性があります。AWS では、ログフォーマットの変更後全てのテレメトリーパイプラインをテストすることを推奨しています。

Node.js の Lambda 関数で JSON 形式のログフォーマットを利用する

JSON 形式のログフォーマットとともに CloudWatch 埋め込みメトリクスフォーマット(CloudWatch Embedded Metric Format, EMF)を使用すれば、JSON 形式の構造化ログにカスタムメトリックスを埋め込むことができます。CloudWatch は自動的に埋め込まれたカスタムメトリックスを取得し、これをアラームの設定や可視化に活用できます。ただし、Node.js の Lambda 関数で JSON 形式のログフォーマットとともに EMF ライブラリーを使用するには、最新バージョンの Node.js 用 EMF クライアントライブラリ、 または最新バージョンの Powertools for AWS Lambda(TypeScript)ライブラリを使用する必要があります。

Lambda 関数のログレベルを設定する

コードの変更なしに ERROR・DEBUG・INFO などのログレベルによって Lambda のログをフィルタリングできるようになりました。簡素化されたログレベルフィルタリングにより、エラーをデバッグするために大量のログをふるい落とす必要がなくなり、必要なログの粒度が選択できるようになりました。

アプリケーションログ(関数コードが生成するログ)とシステムログ(START や REPORT ログメッセージのような Lambda サービスが生成するログ)でそれぞれのログレベルフィルタを設定することが可能です。ただし、ログフォーマットが JSON に設定されている場合のみ、ログレベルの設定が可能になります。

各ログイベントのログレベルは関数コード内で定義できます。次のコードでは関数のインプットである event を DEBUG ログとして出力しています。

console.debug(event);

関数のログレベルを設定すると、設定されたログレベルより低レベルのログイベントはその関数の CloudWatch ログストリームに送信されなくなります。例えばログレベルが INFO に設定された場合、DEBUG ログは転送されません。

この機能を活用することで関数が出力するログの量を適切に制御できるようになります。例えば、本番環境ではノイズ率をさげるためにログレベルを高めに設定しておき、テストやトラブルシューティング時はより細かいログイベントを収集できるようにログレベルを低く設定したりすることができます。

Lambda 関数の CloudWatch ロググループを設定する

これまでは、ユーザ側で関数の CloudWatch ロググループの設定ができなかったため、複数の関数からのログを一つの共通のロググループにストリーミングできませんでした。また、複数のロググループに任意の保持ポリシーを適用するには、各ロググループを /aws/lambda/<function> のような規定された名前で個別に作成する必要がありました。

今では、任意の CloudWatch ロググループを指定し、アプリケーションを構成する複数の関数からのログを自動的に一箇所に集約できるようになりました。関数レベルではなく、アプリケーションレベルでセキュリティ・ガバナンス・保持ポリシーを適用できるようになっています。

ログストリーム名には Lambda 関数の名前とバージョンが入っているため、これが共通のロググループに入っていても、ログの発行元の関数を見分けることができるようになっています。

複数の関数で共通のロググループを使用することによりログを集約することができます。Lambda が指定されたロググループにログを送信できるようにするためには、関数の IAM ポリシーに logs:CreateLogStreamlogs:PutLogEvents の権限を付与することが必要です。コンソールで関数のロググループを設定する場合は、Lambda サービスが自動的に必要な権限を付与します。

コンソールでロググループ名を入力すれば、関数のログの送信先を任意のロググループに設定できます。入力したロググループが存在しない場合、Lambda が自動でロググループを作成します。

Lambda の高度なログ制御機能は Lambda APIAWS マネジメントコンソールAWS コマンドラインインターフェイス(CLI)、または AWS サーバレスアプリケーションモデル(AWS SAM)AWS CloudFormation などの infrastructure as code(IaC)ツールからご利用いただけます。

Lambda の高度なログ制御機能を使用したサンプルアプリケーション

このセクションでは、AWS SAM から新しくリリースされた Lambda の高度なログ制御機能を利用し、AWS 上でリソースをビルドおよびデプロイする方法を示します。

概要

次のアーキテクチャ図では、Amazon S3 のバケットに新しいオブジェクトが作成された後、二つの Lambda 関数がそれぞれオブジェクトを処理し、ログを共通の CloudWatch ロググループに送信することを表しています。

具体的な処理の流れは以下となります:

  1. S3 バケットに新しいオブジェクトが作成されます。
  2. S3 が S3 イベント通知機能によって Amazon EventBridge にイベントを発行します。
  3. EventBridge が非同期的に二つの Lambda 関数を発火させます。
  4. 関数がそれぞれ Amazon RekognitionAmazon Textract を利用し、オブジェクトからラベル検出とテキスト抽出を行います。
  5. 各関数が共通の CloudWatch ロググループにそれぞれのログを送信します。

ここでは AWS SAM を使用して Lambda 関数を定義し、必要なログ制御を設定しています。IAM ポリシーでは、関数が指定のロググループにおいてログストリームの作成とログの送信ができるよう権限設定されています。

DetectLabelsFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: detect-labels/
      Handler: app.lambdaHandler
      Runtime: nodejs18.x
      Policies:
        ...
        - Version: 2012-10-17
          Statement:
            - Sid: CloudWatchLogGroup
              Action: 
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: !GetAtt CloudWatchLogGroup.Arn
              Effect: Allow
    LoggingConfig:
        LogFormat: JSON
        ApplicationLogLevel: DEBUG
        SystemLogLevel: INFO
        LogGroup: !Ref CloudWatchLogGroup

サンプルをデプロイする

サンプルをデプロイする手順は下記となります:

  1. GitHub リポジトリをクローンし、アプリケーションを確認します。
git clone https://github.com/aws-samples/advanced-logging-controls-lambda/

cd advanced-logging-controls-lambda
  1.  AWS SAM を使ってリソースをビルドし、AWS 上にデプロイします。下記のコマンドでは、npm によってアプリケーションがビルドされ、リソースをデプロイするのに必要なテンプレートが作成されます。
sam build
  1. AWS SAM CLI によるインタラクティブなデプロイガイドを利用しソリューションをデプロイします。
sam deploy --guided
  1. 下記の値を入力してください。
    • Stack Name:advanced-logging-controls-lambda
    • Region:デプロイ先のリージョン(例えば us-east-1 など)を入力してください。
    • Parameter UploadsBucketName:一意的なバケット名を入力してください。
    • ほかは全てデフォルトのままにしてください。
  2. アプリケーションをテストするため、下記の AWS CLI コマンドを使って先ほど作成した S3 バケットにサンプル画像をコピーしましょう。
aws s3 cp samples/skateboard.jpg s3://<先ほど作成したバケットの名前>

CloudWatch に作成された AggregatedLabelsLogGroup という名前のロググループに出力されたログを確認します。

ログストリームには、DetectLables という Lambda 関数が JSONフォーマットで出力した DEBUG ログイベントがある一方、ExtractText 関数からの同レベルのログイベントは省略されています。これは、それぞれの関数ではアプリケーションログのログレベルの設定の違い(DetectLables では DEBUG、ExtractText では INFO)に由来します。

下記のサンプルクエリのように、CloudWatch Logs Insights を使用した JSON フォーマットのログの検索・フィルタリング・分析も可能です。

以下のようなクエリ結果が得られます。

まとめ

Lambda の高度なログ制御機能によって、ログをより細かく設定できるようになりました。Lambda 関数のログレベルやログフォーマットが設定できるようになったため、ユーザはより簡単にログを検索・クエリ・フィルタリングできるようになり、効果的にトラブルシューティングを行うことができるようになりました。

Lambda のログの送信先の CloudWatch ロググループもユーザ側で指定できるようになりました。これにより、複数の関数のログを一つのロググループに集約し、保持・セキュリティ・ガバナンスポリシーを共通化することで、大規模なログ管理を効率化できるようになりました。

新規・既存の Lambda 関数のロギング設定を必要に応じて設定することで、これらの新機能が利用できます。

Lambda の高度なログ制御機能は、Lambda が利用可能な全ての AWS リージョンで追加費用なしでご利用いただけます。より詳しくは、こちらのドキュメント(英文のみ)をご参照ください。

Serverless Land では、他にもサーバレスの学習リソースをご用意しております。
日本語のサーバレス学習リソースについては、 サーバーレスパターンサーバーレス自己学習ガイドもご覧ください。