かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

aws-lambda-powertools を試してみる(Logger 編)

概要

記事一覧はこちらです。

TwitterSimplifying serverless best practices with Lambda Powertools の記事を見かけました。Python で Lambda を作成する時に Logging、Tracing、Metrics の機能の実装を助けてくれるライブラリとのこと。

記事は SAM で実装されていたので Serverless Framework で実装して動作を確認してみます。Logger で1回(今回)、Tracer で2回の計3回に分けて書きます。Metrics は使い方(というか何が便利になるのか)が今ひとつ分からなかったので書きません。

参照したサイト・書籍

  1. Simplifying serverless best practices with Lambda Powertools
    https://aws.amazon.com/jp/blogs/opensource/simplifying-serverless-best-practices-with-lambda-powertools/

  2. AWS Lambda Powertools Python
    https://awslabs.github.io/aws-lambda-powertools-python/

  3. aws-samples / aws-serverless-shopping-cart
    https://github.com/aws-samples/aws-serverless-shopping-cart/tree/master/backend/shopping-cart-service

    • Python で書かれた Serverless のサンプル。今回の記事とは直接関係ありませんが、後で見たいので残しておきます。
  4. Serverless Framework v1.41 - X-Ray for API Gateway, Invoke Local with Docker Improvements & More
    https://www.serverless.com/blog/framework-release-v141/

  5. オブザーバビリティ(可観測性)がなぜ必要だと考えるのか
    https://ymotongpoo.hatenablog.com/entry/2019/03/25/084500

  6. CloudWatch Logs Insights を使用したログデータの分析
    https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/AnalyzingLogData.html

  7. 地味にイイネ!Amazon CloudWatch Logs Insightsで効率的に調査しよう!
    https://blog.ecbeing.tech/entry/2019/09/19/124352

  8. CloudWatch Logs Insights でApacheアクセスログを確認する
    https://dev.classmethod.jp/articles/cwinsights-apache/

目次

  1. lambda-powertools-project プロジェクトを作成する
  2. sample_service サブプロジェクトを作成する
  3. requirements.txt を作成する
  4. serverless.yml に POWERTOOLS 用の環境変数と X-Ray を有効にする設定を追加する
  5. Logging の機能を試してみる

手順

lambda-powertools-project プロジェクトを作成する

以下の手順で lambda-powertools-project プロジェクトを作成します。具体的な手順は IntelliJ IDEA+Node.js+npm+serverless framework+Python の組み合わせで開発環境を構築して AWS Lambda を作成してみる 参照。

  • lambda-powertools-project の Empty Project を作成する。
  • Python の仮想環境を作成する。
  • Serverless Framework をローカルインストールする。
  • .envrc を作成する。
  • aws-lambda-powertools は deploy 時にアップロードしないと使用できないので serverless-python-requirements をインストールします。
    • npm install --save-dev serverless-python-requirements
  • Tracing の機能を試すのに Lambda から別のサービスを呼び出すので boto3 をインストールします。aws-lambda-powertools もインストールします。
    • pip install boto3
    • pip install aws-lambda-powertools

sample_service サブプロジェクトを作成する

プロジェクトのルートディレクトリの下で npx sls create --template aws-python3 --path sample_service を実行して sample_service サブプロジェクトを作成します。

requirements.txt を作成する

deploy 時に aws-lambda-powertools もアップロードするために sample_service ディレクトリの下に requirements.txt を作成して以下の内容を記述します。

aws-lambda-powertools==1.0.0

serverless.yml に POWERTOOLS 用の環境変数X-Ray を有効にする設定を追加する

sample_service/serverless.yml を以下のように変更します。

service: sample-service

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true

provider:
  name: aws
  runtime: python3.8
  stage: dev
  region: ap-northeast-1
  environment:
    # aws-lambda-powertools 用環境変数
    LOG_LEVEL: INFO
    POWERTOOLS_LOGGER_LOG_EVENT: true
    POWERTOOLS_METRICS_NAMESPACE: lambda-powertools-project
    POWERTOOLS_SERVICE_NAME: sample-service
  tracing:
    apiGateway: true
    lambda: true

..........
  • グローバルな環境変数は provider.environment に記述すればよいので、ここに POWERTOOLS 用の環境変数のうち以下の4つを設定します。
    • LOG_LEVEL
    • POWERTOOLS_LOGGER_LOG_EVENT
    • POWERTOOLS_METRICS_NAMESPACE
    • POWERTOOLS_SERVICE_NAME
  • X-Ray の設定は provider.tracing に記述するので、apiGateway: truelambda: true を設定します。

Logging の機能を試してみる

今回は以下の JSON Schema のメッセージを送信します(sample_service ディレクトリの下に msg_schema.json というファイルを作成しその中に記述します)。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "definitions": {
    "orderedItem": {
      "type": "object",
      "properties": {
        "orderItemNumber": {
          "type": "string",
          "pattern": "^[0-9]+$"
        },
        "orderQuantity": {
          "type": "integer",
          "minimum": 0,
          "maximum": 999
        },
        "productID": {
          "type": "string",
          "pattern": "^[0-9]+$"
        },
        "category": {
          "type": "string",
          "enum": [
            "book",
            "camera",
            "computer"
          ]
        },
        "price": {
          "type": "integer",
          "minimum": 1
        }
      },
      "required": [
        "orderItemNumber",
        "orderQuantity",
        "productID",
        "category",
        "price"
      ]
    }
  },
  "title": "Order",
  "type": "object",
  "properties": {
    "orderNumber": {
      "type": "string",
      "pattern": "^[0-9]+$"
    },
    "orderDate": {
      "type": "string",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
    },
    "isGift": {
      "type": "boolean"
    },
    "orderedItem": {
      "type": "array",
      "minItems": 1,
      "maxItems": 3,
      "uniqueItems": true,
      "items": {
        "$ref": "#/definitions/orderedItem"
      }
    }
  },
  "required": [
    "orderNumber",
    "orderDate",
    "orderedItem"
  ]
}

メッセージのサンプルです。

{
  "orderNumber": "1",
  "orderDate": "2020-06-28",
  "isGift": false,
  "orderedItem": [
    {
      "orderItemNumber": "1",
      "orderQuantity": 3,
      "productID": "1001",
      "category": "book",
      "price": 3800
    },
    {
      "orderItemNumber": "2",
      "orderQuantity": 1,
      "productID": "3052",
      "category": "camera",
      "price": 150000
    }
  ]
}

sample_service の下の handler.py を apigw_handler.py にリネームし、以下の内容を記述します。

import json

from aws_lambda_powertools import Logger

logger = Logger()


# @logger.inject_lambda_context を付けておくとログ出力時に context にセットされている
# function_name 等の情報がセットされる
# Capturing context Lambda info
# https://awslabs.github.io/aws-lambda-powertools-python/core/logger/#capturing-context-lambda-info
@logger.inject_lambda_context
def recv_msg(event, context):
    logger.debug(event['body'])
    request_body = json.loads(event['body'])
    logger.info({
        "orderNumber": request_body['orderNumber'],
        "orderDate": request_body['orderDate']
    })

    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response

sample_service/serverless.yml の functions の記述を以下の内容に変更します。

functions:
  recvMsg:
    handler: apigw_handler.recv_msg
    events:
      - http:
          path: recv-msg
          method: post
          cors: true
          request:
            schema:
              application/json: ${file(msg_schema.json)}

deploy します。

f:id:ksby:20200630004725p:plain f:id:ksby:20200630004839p:plain

Postman からサンプルメッセージを送信すると 200 OK が返ってきました。

f:id:ksby:20200630005120p:plain

試した結果としては、

まずログのメッセージフォーマットが JSON になり、logger のメソッドに渡した文字列は message に出力されます。JSON フォーマットになることで CloudWatch Logs Insights で検索しやすくなります。

Lambda に @logger.inject_lambda_context を付与しておくと、出力されるログに引数 context にセットされている function_name 等の情報が追加されます。

f:id:ksby:20200630005957p:plain

@logger.inject_lambda_context が付与されていて、かつ環境変数 POWERTOOLS_LOGGER_LOG_EVENT が true に設定されていると、Lambda が呼び出された時に decorate のログ(API Gateway から呼び出された Lambda だとアクセス時の HTTPヘッダ等)が出力されます。環境変数 POWERTOOLS_LOGGER_LOG_EVENT のデフォルト値が false なので DEBUG 用?

f:id:ksby:20200630010156p:plain f:id:ksby:20200630010340p:plain

環境変数 LOG_LEVEL で出力するログのレベルを調整可能です。今は LOG_LEVEL: INFO の設定なので INFO のログだけ出ていますが(環境変数 POWERTOOLS_LOGGER_LOG_EVENT は false にしています)、

f:id:ksby:20200630235835p:plain

sample_service/serverless.yml で functions.recvMsg.environment に LOG_LEVEL: DEBUG を設定した後、deploy し直してからメッセージを送信すると、

provider:
  name: aws
  runtime: python3.8
  stage: dev
  region: ap-northeast-1
  environment:
    # aws-lambda-powertools 用環境変数
    LOG_LEVEL: INFO
    POWERTOOLS_LOGGER_LOG_EVENT: false
    POWERTOOLS_METRICS_NAMESPACE: lambda-powertools-project
    POWERTOOLS_SERVICE_NAME: sample-service
  tracing:
    apiGateway: true
    lambda: true

functions:
  recvMsg:
    handler: apigw_handler.recv_msg
    events:
      - http:
          path: recv-msg
          method: post
          cors: true
          request:
            schema:
              application/json: ${file(msg_schema.json)}
    environment:
      LOG_LEVEL: DEBUG

DEBUG のログも出力されます。

f:id:ksby:20200701000010p:plain

履歴

2020/07/05
初版発行。