AWS SAMでAPI GatewayのCloudWatchLogsへのロギングを有効にする記述

## 目的

AWS SAM[^1] でAPI Gatewayをデプロイする場面で、ロギングを有効化するための template.yaml 記述をメモします。
サンプルアプリケーションをベースに、変更点を示していきます。


[^1]:[AWS サーバーレスアプリケーションモデル](https://aws.amazon.com/jp/serverless/sam/)


## 準備

### sam-cli

sam-cliを利用できるようにします。[^2]
私の場合は Ubuntu22 with WSL2の環境で、Linux版をDocker無しでインストールしました。

[^2]:https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

### デプロイまで実施 (sam init & build & deploy)

詳細は省略しますが、大まかには下記の手順でサンプルアプリケーションをデプロイしました。

`sam init`を実行し、サンプルとして準備されているアプリケーションを設定します。
`AWS Quick Start Templates` → `Hello World Example` を選択しました。

続いて `sam build` を実行、さらに `sam deploy --guided` を実行し、AWS環境へデプロイします。

## API Gatewayのロギング設定を確認

ステージ→ログ/トレース→CloudWatch設定部分を確認します。
デフォルト設定では、 CloudWatchログ＝オフ、詳細 Cloudwatch メトリクスを有効化＝オフ、になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/79e7ceb8-ffd0-9137-630f-598d1df50fc2.png)

## template.yamlの変更

初期状態ではAPI Gatewayについての記述はありませんが、内部的には暗黙の定義名 `ServerlessRestApi`として、はAWS SAMのデフォルト設定でデプロイされるようです。

今回は個別に設定したいので、明示的に記述します。

1. `MyApi` というRestAPI定義を記述しています
    a. `MethodSettings` 部分 [^m1][^m2]が今回設定したいロギング部分に対応します
1. Function記述内の `Events` 部分で、 `GET /hello` は `MyApi` を使用することを明示します
1. Output記述部分も `MyApi` の値を利用するために書き換えます


[^m1]:https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-stage-methodsetting.html
[^m2]:https://docs.aws.amazon.com/ja_jp/apigateway/latest/api/API_MethodSetting.html


```diff_yaml:template.yaml
 Resources:
+  MyApi:
+    Type: AWS::Serverless::Api
+    Properties:
+      StageName: Prod
+      MethodSettings:
+        - ResourcePath: /*
+          HttpMethod: '*'
+          LoggingLevel: "OFF"
+          DataTraceEnabled: false
+          MetricsEnabled: false
   HelloWorldFunction:
     Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
     Properties:
       CodeUri: hello_world/
       Handler: app.lambda_handler
(snip)
       Events:
         HelloWorld:
           Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
           Properties:
             Path: /hello
             Method: get
+            RestApiId: !Ref MyApi

 Outputs:
   HelloWorldApi:
     Description: "API Gateway endpoint URL for Prod stage for Hello World function"
-    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
+    Value: !Sub "https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
```

## AWSコンソール設定と指定値の対応

AWSコンソール上の表現と指定値の関係です。

### 詳細 CloudWatch メトリクスを有効化

`MetricsEnabled` のbool値 (true/false) と対応します


### CloudWath ログ

AWSコンソール上ではプルダウン選択UIとなっています。選択肢と指定値は下記の関係になっていました。


|画面上の選択肢|LoggingLevel指定値|DataTraceEnabled指定値|
|---|---|---|
|オフ|OFF|false|
|エラーのみ|ERROR|false|
|エラーと情報ログ|INFO|false|
|リクエストとレスポンスの全ログ|INFO|true|


## ログ出力ロールの設定

本記事の目的から少しそれますが、API GatewayからCloudWatchLogsへ出力するためにはロールを作成、設定する必要があります。[^cwlog]

[^cwlog]:https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-logging.html

ロールもSAM templateへ記述し、デプロイすることで作成できます。
下記の記述を含め、Outputに出力されたロールARNをAWSコンソールから設定します。

```ログ出力のための追記.yaml
Resources:
  ApiGatewayRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - apigateway.amazonaws.com
          Action:
            - sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs
Outputs:
  ApiGatewayRole:
    Description: "CloudWatch Log Role for API Gateway log"
    Value: !GetAtt ApiGatewayRole.Arn
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/ed62ccce-b0a2-595e-29a0-915413b26bef.png)