新たに追加されたAWS LambdaのログコントロールをAWS SAM CLIで試してみる

2023.11.17

初めに

昨日AWS Lambdaにログ形式やログレベルのコントロールといった指定が可能なアップデートが行われました。

機能については既に別の方が記事を書かれているため大枠としてはこちらをご参照ください。

本日リリースされたAWS SAM CLIv1.103.0が既にこちらの機能に対応していたのでせっかくなのでSAMでも試してみます。

SAMテンプレート作成

今回新たにAWS::Serverless::Functionに追加されたLoggingConfigで設定可能です。

また今回のアップデートでsam init--structured-loggingオプションが追加されておりこちらを指定することでログフォーマットデフォルトでJSON形式としたテンプレートが生成されるようになっております。

sam init実行時にこのオプションを付与したsam-app-structedプロジェクトと、このオプションを未指定(--no-structured-logging指定と同等)を比較すると以下の差分が確認できます。
(そのほかにも名前とダブルクォートの有無はありますが実質的な差はありません)

$ diff -ubBr sam-app-no-structed sam-app-structed
...
+    # You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
+    LoggingConfig:
+      LogFormat: JSON
...

ちなみにsam init --structured-loggingで生成した場合この設定はGlobalsセクションに書き込まれるようです。

template.yml

...
Globals:
  Function:
    Timeout: 3

    # You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
    LoggingConfig:
      LogFormat: JSON
...

もう少し色々書き加えていい感じにログを調整できるようにしてみます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
  AppLogLevel:
    Type: string
    Default: WARN
    AllowedValues:
      - FATAL
      - ERROR
      - WARN
      - INFO
      - DEBUG
      - TRACE
Globals:
  Function:
    Timeout: 10
    LoggingConfig:
      LogFormat: JSON
      ApplicationLogLevel: !Ref AppLogLevel
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs20.x
      Architectures:
        - x86_64
      LoggingConfig:
        LogGroup: /aws/lambda/blog/structed-log-sample

3種類のログレベルでの出力を用意しておきます。

app.mjs

export const lambdaHandler = async (event, context) => {
    console.debug("Im DEBUGGING log")
    console.warn("Im WARNING log")
    console.error("Im ERROR log")
    const response = {
      statusCode: 200,
      body: JSON.stringify({
        message: 'hello world',
      })
    };

    return response;
  };

実行

SAMテンプレートとデプロイ側のみの対応かなと思っていたのですが既にlocal invokeの方も対応しているようです。
(ただ追加された処理がほとんど引数の追加とテンプレートの変換くらいなのでコンテナ側で何かやってる気がします)

レベルを変えて出力を試してみます。

% sam local invoke
...
START RequestId: e48c8dcd-f6df-4ef2-9c1e-93224eed7900 Version: $LATEST
{"timestamp":"2023-11-17T11:17:12.419Z","level":"WARN","requestId":"e48c8dcd-f6df-4ef2-9c1e-93224eed7900","message":"Im WARNING log"}
{"timestamp":"2023-11-17T11:17:12.434Z","level":"ERROR","requestId":"e48c8dcd-f6df-4ef2-9c1e-93224eed7900","message":"Im ERROR log"}

% sam local invoke --parameter-overrides AppLogLevel=ERROR
...
START RequestId: 8b1ed350-cc79-4fe7-bee9-f56abe6b748d Version: $LATEST
{"timestamp":"2023-11-17T11:15:15.482Z","level":"ERROR","requestId":"8b1ed350-cc79-4fe7-bee9-f56abe6b748d","message":"Im ERROR log"}
END RequestId: 8b1ed350-cc79-4fe7-bee9-f56abe6b748d


sam local invoke --parameter-overrides AppLogLevel=DEBUG
...
START RequestId: d21dc300-2c59-43c1-b4a4-beaeb1a41fd3 Version: $LATEST
{"timestamp":"2023-11-17T11:15:48.530Z","level":"DEBUG","requestId":"d21dc300-2c59-43c1-b4a4-beaeb1a41fd3","message":"Im DEBUGGING log"}
{"timestamp":"2023-11-17T11:15:48.545Z","level":"WARN","requestId":"d21dc300-2c59-43c1-b4a4-beaeb1a41fd3","message":"Im WARNING log"}
{"timestamp":"2023-11-17T11:15:48.546Z","level":"ERROR","requestId":"d21dc300-2c59-43c1-b4a4-beaeb1a41fd3","message":"Im ERROR log"}

debugオプションをつけて流したりしてみましたがLogGroupの設定を変えてもlocal invokeでは何か起きるみたいのはなさそうです。

終わりに

欲しいログレベルというのは環境によって違うものかと思いますので今回のようにログレベルが調整できるようになったのは非常に嬉しいアップデートです。
またJSON形式となったことでよりCloudWatch Logs Insightとの親和性もより良くなったのではないでしょうか。

特にSAMを利用している環境であればGlobalsセクションをうまく活用することでリソースごとに設定を記載せずともログレベルを一箇所の設定値でまとめて管理し、必要に応じて部分的に上書きということが可能ですのでうまく活用して冗長な書き方を減らしていきましょう。