本連載では、AWS Lambdaを使ったサーバレス処理でのエラーハンドリング方法を解説しています。前回は、下図の赤字の矢印のスコープにおいて、同期的なLambdaの呼び出しでシステムエラーが発生するケースを想定し、CloudWatch Logsに出力されたログをイベント契機として実行される、Spring Cloud Functionを使ったLambdaファンクションを実装について解説しました。

構成図

今回は、実際にCloudWatch Logsに出力されたログをサブスクリプションして、Mattermostへメッセージ通知する環境を構築します。

CloudFormationを使用したLambda環境の構築/CloudWatchサブスリプションの設定

第8回で解説した手順で構築したLambdaテンプレートに、前回実装したLambdaファンクションを追加して、スタックを作成し直します。

AWSTemplateFormatVersion: '2010-09-09'

#omit

Resources:
  LambdaForSyncExecuteSystemErrorFuntion:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::ImportValue: debugroom-mynavi-sample-lambda-errorhandling-deploy-s3-bucket
        S3Key: spring-cloud-3-1-lambda-function-0.0.1-SNAPSHOT-aws.jar
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
      FunctionName: mynavi-sample-aws-lambda-errorhandling-sync-system-error
      Environment:
        Variables:
          SPRING_CLOUD_FUNCTION_DEFINITION: syncExecuteSystemErrorFunction
      MemorySize: 1024
      Runtime: java11
      Timeout: 120
      Role: !GetAtt LambdaRole.Arn


  #omit

  LambdaForNotifySystemErrorFuntion:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::ImportValue: debugroom-mynavi-sample-lambda-errorhandling-deploy-s3-bucket
        S3Key: spring-cloud-3-1-lambda-function-0.0.1-SNAPSHOT-aws.jar
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
      FunctionName: mynavi-sample-aws-lambda-errorhandling-notify-system-error
      Environment:
        Variables:
          SPRING_CLOUD_FUNCTION_DEFINITION: notifySystemErrorFunction
      MemorySize: 1024
      Runtime: java11
      Timeout: 120
      Role: !GetAtt LambdaRole.Arn

  #omit

Outputs:
  #omit

  LambdaForSyncExecuteSystemErrorFuntion:
    Description: Sync execute Lambda function for occuring system error function.
    Value: !Ref LambdaForSyncExecuteSystemErrorFuntion
    Export:
      Name: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name

  LambdaForSyncExecuteSystemErrorFuntionArn:
    Description: Sync execute Lambda function for occuring system error function.
    Value: !GetAtt LambdaForSyncExecuteSystemErrorFuntion.Arn
    Export:
      Name: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-arn

  #omit

  LambdaForNotifySystemErrorFuntion:
    Description: Lambda function for notifying system error function.
    Value: !Ref LambdaForNotifySystemErrorFuntion
    Export:
      Name: mynavi-sample-lambda-errorhandling-notify-system-error-function-name

  LambdaForNotifiySystemErrorFuntionArn:
    Description: Lambda function for notifying system error function.
    Value: !GetAtt LambdaForNotifySystemErrorFuntion.Arn
    Export:
      Name: mynavi-sample-lambda-errorhandling-notify-system-error-function-arn

同様に、API Gatewayのテンプレートも、システムエラーが発生するファンクション向けにメソッドやリソースを定義して構築し直します。

#omit

ApiGatewaySystemExceptionResource:
  Type: "AWS::ApiGateway::Resource"
  Properties:
    RestApiId:
      Ref: ApiGatewayRestApi
    ParentId:
      Fn::GetAtt:
        - ApiGatewayRestApi
        - RootResourceId
    PathPart: "system-exception-sample-resource"

#omit

ApiGatewaySystemExceptionMethod:
  Type: "AWS::ApiGateway::Method"
  DependsOn: ApiGatewayModel
  Properties:
    RestApiId:
      Ref: ApiGatewayRestApi
    ResourceId:
      Ref: ApiGatewaySystemExceptionResource
    HttpMethod: "GET"
    AuthorizationType: "NONE"
    Integration:
      Type: "AWS_PROXY"
      Uri:
        Fn::Join:
          - ""
          - - "arn:aws:apigateway"
            - ":"
            - Ref: AWS::Region
            - ":"
            - "lambda:path/2015-03-31/functions/"
            - Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-arn
            - "/invocations"
      IntegrationHttpMethod: "POST"
      PassthroughBehavior: WHEN_NO_MATCH
    MethodResponses:
      - StatusCode: 200
        ResponseModels:
          application/json: SampleSchema
      - StatusCode: 400
        ResponseModels:
          application/json: Error

SystemErrorLambdaPermission:
  Type: "AWS::Lambda::Permission"
  Properties:
    FunctionName:
      Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name
    Action: "lambda:InvokeFunction"
    Principal: "apigateway.amazonaws.com"

続いて、CloudWatchにサブスクリプションフィルタおよびロググループ、実行権限に関するテンプレートを実装します。

AWSTemplateFormatVersion: '2010-09-09'

#omit

Resources:
  CloudWatchLogsSyncExecuteSystemErrorSubscription:  #(1)
    Type: AWS::Logs::SubscriptionFilter
    Properties:
      LogGroupName: !Ref LogsGroupSyncExecuteSystemError
      FilterPattern: "Exception"                     #(2)
      DestinationArn:
        Fn::ImportValue: mynavi-sample-lambda-errorhandling-notify-system-error-function-arn #(3)

  LogsGroupSyncExecuteSystemError:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName:
        Fn::Join:
          - ""
          - - "/aws/lambda/"
            - Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name #(4)

  NotifyErrorLambdaPermission: #(5)
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName:
        Fn::ImportValue: mynavi-sample-lambda-errorhandling-notify-system-error-function-name
      Action: lambda:InvokeFunction
      Principal: !Join [ ".", [ "logs", !Ref "AWS::Region", "amazonaws.com" ] ]
      SourceAccount: !Ref AWS::AccountId

上記のコードのポイントは以下の通りです。

項番 説明
1 CloudWatch Logsで特定のログをサブスクリプションする設定を行います。各プロパティの詳細は「AWS::Logs::SubscriptionFilter」を参照してください
2 ログでピックアップ対象とする文字列パターンを指定します。前節の実際の実装ではSystemExceptionをスローしていますが、実際はさまざまな想定外のExceptionクラスがスローされることになるので、「Exception」をパターン文字列として設定します
3 実行するLambdaファンクションのARNをクロススタックリファレンスで参照します
4 監視対象とするロググループを指定します。前節で作成したシステム例外を発生するLambdaファンクションのログが出力されるロググループを指定しています
5 ロググループにLambdaの実行権限を付与します

これらのテンプレートを実行し、環境を構築します。また、本連載では説明は省略しますが、Mattermost環境の構築やWebhookの設定を行い、URLを「SystemsManager ParameterStore」に設定しておきます。なお、SystemsManager ParameterStoreの設定に関しては、連載「AWSで実践! 基盤構築・デプロイ自動化」の第29回などを適宜参考にしてください。

必要な環境を構築/設定後、第8回と同じ要領でAPI Gatewayからシステムエラーが発生するファンクションを実行すると、以下のようにAPI Gatewayからインターナルサーバエラーが返却されます。

※ Mattermost環境の構築やWebhookの設定については、公式サイトの「Installing Mattermost」や「Mattermost Integration Guide」を参照してください。

インターナルサーバエラー

CloudWatch Logsには発生したエラーのスタックトレースが記録されます。

スタックトレース

CloudWatch Logsのサブスクリプションが別途Lambdaファンクションを呼び出し、Mattermost側へエラー内容を通知します。システム管理者や運用担当者は、エラーの内容を確認して、AWSの外で優先度を設定し、対応することができます。

エラー内容を通知

* * *

今回は、API GatewayとLambdaを使用した同期呼び出しでシステムエラーが発生した際に、CloudWatchに出力されたエラーログを契機として、システム管理者へ通知を行うLambdaファンクション実装について解説しました。

次回は、S3などのマネージドサービスから非同期に実行されるLambdaファンクション内で発生したエラーのハンドリングについて解説を進めていきます。

著者紹介


川畑 光平(KAWABATA Kohei) - NTTデータ
エグゼクティブ ITスペシャリスト ソフトウェアアーキテクト・デジタルテクノロジーストラテジスト(クラウド)

金融機関システム業務アプリケーション開発・システム基盤担当、ソフトウェア開発自動化関連の研究開発を経て、デジタル技術関連の研究開発・推進に従事。

Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなど様々な開発プロジェクト支援にも携わる。AWS Top Engineers & Ambassadors選出。

本連載の内容に対するご意見・ご質問は Facebook まで。