michimani.net

Telemetry API を使う Lambda Extension を作ってみた

2022-12-12

AWS Lambda の Runtime API について調べていたら Extension API、 Telemetry API というものの存在を知り、 ひとつ前の記事 ではそれを使って簡単な Lambda Extension を自作してみました。今回は、 Telemetry API を使う Lambda Extension を作ってみて、 Telemetry API でどのような情報が取得できるのかを確認してみます。

はじめに

この記事は 弁護士ドットコム Advent Calendar 2022 (と AWS LambdaとServerless Advent Calendar 2022 (その2) ) の 12 日目の記事です。

昨日は @talog による 「textlint のルールを作って仕組みを理解した💪 」 でした。このブログにも linter を導入したい…

今回の記事ではタイトルの通り Telemetry API を使った Lambda Extension について書きますが、下記の記事で Lambda Extension そのものについて書いているので合わせて読んでいただくとよいかもしれません。

AWS Lambda の Extension API を使いたいがために Go で Lambda Extension を自作してみた - michimani.net

Telemetry API とは

2022年 11月にリリースされた機能で、 Lambda の実行環境、拡張機能、関数で起こっていることをイベントとして受け取ることができるような API のことです。

AWS Lambda において、新しい AWS Lambda Telemetry API がリリースされました。これにより、関数の実行に関する強化されたモニタリングデータおよびオブザーバビリティデータを、Lambda 拡張機能で収集できるようになりました。 Telemetry API は、ログ、プラットフォームのトレース、関数呼び出しレベルのメトリクスを Lambda から直接受け取るための、拡張機能用のシンプルなインターフェイスを提供します。

引用元: AWS Lambda が Telemetry API を導入したことで Lambda 拡張機能のモニタリングとオブザーバビリティがさらに向上

Telemetry API のリリース以前には Logs API というものが提供されており、この API では関数でログが出力されたイベントを受け取ることができていました。 Telemetry API は Logs API の上位互換のような存在で、今後は Logs API の代わりとして Telemetry API を使用することが推奨されています。

The Lambda Telemetry API supersedes the Lambda Logs API. While the Logs API remains fully functional, we recommend using only the Telemetry API going forward.

引用元: Lambda Telemetry API - AWS Lambda

Telemetry API を使う Lambda Extension の概要

Lambda Extension で Telemetry API を使う場合、 Extension の実装としては下記のようになります。

  1. HTTP または TCP でリクエストを受け取るサーバを所定のアドレス (ポートは任意) で起動する
  2. 1 で起動したサーバのアドレスを Telemetry API の Subscribe API (PUT /telemetry) を使って登録する
  3. 何かしらのイベントが発生した際に Telemetry API から 1 のサーバに対してリクエストが送信されるので、ハンドリングを行う

シーケンス図で描くと下記のようなイメージです。

sequenceDiagram participant ls as Lambda Service participant eapi as Extension API participant tapi as Telemetry API participant main as Extension (main) participant sub as Extension (subscriber) alt Init ls ->> main: start (init extensions in /ops/extensions) main ->> eapi: POST /extension/register eapi ->> main: OK + ExtensionIdentifier main ->> sub: Start HTTP (or TCP) server sub ->> main: OK + listenAddress main ->> tapi: PUT /telemetry with ExtensionIdentifier + listenAddress tapi ->> main: OK end loop Repeat main ->> eapi: GET /extension/event/next eapi ->> main: INVOKE/SHUTDOWN event tapi ->> sub: platform/extension/function event sub ->> sub: handle event end

上記の通り、Extension からコールする Telemetry API としては PUT /telemetry の Subscribe API のみです。

Telemetry API の詳細

ここでは Telemetry API の詳細として、下記の 2 点について整理します。

  1. Subscribe API - PUT /telemetry について
  2. Subscriber に対して送信されるイベントについて

1. Subscribe API - PUT /telemetry について

Subscribe API は、 Extension からコールする Telemetry API として唯一公開されている API で、各イベントを受け取るための Subscriber の登録を行う API です。

仕様については下記公式ドキュメントに記載されていますが、一部載っていない項目もあったのであらためてここで整理します。

Lambda Telemetry API reference - AWS Lambda

Subscribe API をコールする際に注意したいのは、まず destination.URI の値としてはドメインが sandbox.localdomain である必要があります。それ以外のドメインで指定した場合、下記のようなエラーになります。

statusCode:403
errType:Telemetry.AccessDenied
errMessage:Only ‘sandbox.localdomain’ hostname is supported.

また、上記の公式ドキュメントでは Lambda-Extension-Identifier に関する記述がありませんが、設定しない もしくは値が不正な場合は下記のようなエラーになります。

statusCode:403
errType:Extension.InvalidExtensionIdentifier
errMessage:Invalid Lambda-Extension-Identifier

2. Subscriber に対して送信されるイベントについて

Telemetry API から送信されるイベントは、大きく分けて Platform event, Function logs, Extension logs の 3 つのカテゴリに分けられ、各カテゴリ内で更にいつかの Event type に分類されています。

各 Event type ごとに schema が定義されていますが、 Event 全体の schema としては下記のようになっています。

{
  "time": "イベントの発生日時",
  "type": "Event type",
  "record": "各 Event type の schema"
}

例えば、 Extension が登録されて起動状態になったことを示すイベント platform.extension は下記のようなオブジェクトになります。

{
  "time": "2022-10-12T00:02:15.000Z",
  "type": "platform.extension",
  "record": {
    "events": [ "INVOKE", "SHUTDOWN" ],
    "name": "my-telemetry-extension",
    "state": "Ready"
  }
}

その他、各 Event type の schema の詳細については下記の公式ドキュメントを参照してください。

Lambda Telemetry API Event schema reference - AWS Lambda

Telemetry API を使う Extension を作ってみる

では実際に Telemetry API を使う Extension を作ってみます。前回と同様に Go で実装します。

今回作る Extension でやることは下記のとおりです。

  1. platformfunction のイベントを Subscribe する
  2. 受け取ったイベントの内容をログに出力する

以上です。

Extension のメイン処理については前回と大きく変わらないので、 Telemetry API に関連するところだけ掻い摘んで説明します。
実装の詳細については下記の GitHub リポジトリを参照してください。

aws-lambda-api-go/_examples/extension-using-telemetry-api at main · michimani/aws-lambda-api-go

Telemetry API の Subscriber を起動

まずは、 Telemetry API からのイベントを受信してハンドリングするための Subscriber を起動します。

aws-lambda-api-go/subscriber.go at v0.2.0 · michimani/aws-lambda-api-go

const defaultSubscriberPort = "1210"
const address = "sandbox.localdomain:" + defaultSubscriberPort

type TelemetryAPISubscriber struct {
	httpServer *http.Server
	logger     *logger.Logger
}

func NewTelemetryAPISubscriber(l *logger.Logger) *TelemetryAPISubscriber {
	return &TelemetryAPISubscriber{
		httpServer: nil,
		logger:     l,
	}
}

func (s *TelemetryAPISubscriber) Start() (string, error) {
	s.logger.Info("Starting on address:%s", address)
	s.httpServer = &http.Server{Addr: address}
	http.HandleFunc("/", s.telemetryEventHandler)

	go func() {
		err := s.httpServer.ListenAndServe()
		if err != http.ErrServerClosed {
			s.logger.Error("Unexpected stop on Http Server. err:%v", err)
			s.Shutdown()
		} else {
			s.logger.Info("Http Server closed. err:%v", err)
		}
	}()

	return fmt.Sprintf("http://%s/", address), nil
}

TelemetryAPISubscriber を返す NewTelemetryAPISubscriber と、 TelemetryAPISubscriber のメソッドとして Start を実装しています。

TelemetryAPISubscriber.Start で、 sandbox.localdomain:1210 のアドレスで HTTP サーバを起動しています。HTTP サーバでは / に対するリクエストを受けて、リクエスト (Telemetry API から送信されるイベント) をハンドリングする TelemetryAPISubscriber.telemetryEventHandler を実行するようにしています。

サーバのアドレスはこのあとの Subscribe API をコールする際に必要になるので呼び出し元 (= Extension のメイン処理) に返します。

Subscribe API をコールして Subscriber を登録

続いて、起動した Subscriber の情報と受信したいイベントを Subscribe API を使って登録します。

aws-lambda-api-go/client.go at v0.2.0 · michimani/aws-lambda-api-go

func (c *Client) Subscribe(ctx context.Context, exId string, httpURI string) error {
	var bufTimeoutMs uint64 = 100

	out, err := telemetry.Subscribe(ctx, c.alagoClient, &telemetry.SubscribeInput{
		LambdaExtensionIdentifier: exId,
		DestinationProtocol:       telemetry.DestinationProtocolHTTP,
		DestinationURI:            httpURI,
		TelemetryTypes: []telemetry.TelemetryType{
			telemetry.TelemetryTypeFunction,
			telemetry.TelemetryTypePlatform,
		},
		BufferTimeoutMs: &bufTimeoutMs,
	})

	if err != nil {
		c.logger.Error("An error occurred at telemetrySubscribe. err:%v", err)
		return err
	}

	if out.StatusCode != http.StatusOK {
		return fmt.Errorf("An error occurred at extension registration. statusCode:%d errType:%s errMessage:%s",
			out.StatusCode, out.Error.ErrorType, out.Error.ErrorMessage)
	}

	return nil
}

今回も、クライントライブラリとして aws-lambda-api-go を使っています。

受信するイベントは、 platformfunction にしています。 (extension はイベントの数が多すぎたので除外しました)
エラーがあれば呼び出し元に返す、ただそれだけの処理になっています。

イベントのハンドリング

最後に、Telemetry API から送信されたイベントのハンドリング処理です。

aws-lambda-api-go/subscriber.go at v0.2.0 · michimani/aws-lambda-api-go

type telemetryAPIEvent struct {
	Record any       `json:"record"`
	Type   string    `json:"type"`
	Time   time.Time `json:"time"`
}

func (s *TelemetryAPISubscriber) telemetryEventHandler(w http.ResponseWriter, r *http.Request) {
	body, err := io.ReadAll(r.Body)
	if err != nil {
		s.logger.Error("Failed to reading body. err:%v", err)
		return
	}

	var events []telemetryAPIEvent
	_ = json.Unmarshal(body, &events)

	s.logger.Info("Received %d events.", len(events))
	for i, e := range events {
		s.logger.Info("%d: Time:%s Type:%s Record:%v", i, e.Time.Format(time.RFC3339Nano), e.Type, e.Record)
	}

	events = nil
}

今回はイベントの大枠となる schema に対応する構造体 telemetryAPIEvent だけ用意して、各イベントごとの schema に対応する構造体の定義については省略しています。

また、ハンドリングと言っても今回はログに出力するだけなので、特に難しいことはしていません。

Lambda 関数で使ってみる

前回と同様に RIE を使ってローカルで試そうと思ったんですが、どうやら Telemetry API はまだ RIE (が含まれたコンテナイメージ) では対応していないようだった1ので実際の環境にデプロイして試してみました。

準備

実際に Lambda で実行して確認するまでの準備として、 Extension と関数をビルドします。

Extension については Lambda Layer として作成するので、下記コマンドで build -> zip 化します。

GOOS=linux GOARCH=amd64 go build -o ../bin/extensions/telemetry-api-extension main.go
chmod +x bin/extensions/telemetry-api-extension
cd bin && zip -r extension.zip extensions/

Lambda 関数についてはただログを出力する処理だけあればよさそうなので、下記のような内容で Python で実装しました。

import json
import logging


def lambda_handler(event, context):
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)

    logger.info('[%s] Hello Telemetry API!', context.aws_request_id)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

こちらも zip 化しておきます。

zip function.zip main.py

また、 Lambda 関数の作成時にアタッチする IAM Role が必要になるので、下記コマンドで作成しておきます。

# IAM Role の作成
aws iam create-role \
--role-name telemetry-api-function-role \
--assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' \
--query 'Role.Arn' \
--output text

# IAM Policy をアタッチ
aws iam attach-role-policy \
--role-name telemetry-api-function-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Extension と それを使う関数を作成

準備ができたので、 Extension (Lambda Layer) と Lambda 関数のリソースを作成します。

Extension は Lambda Layer として作成するので、下記コマンドでデプロイします。

aws lambda publish-layer-version \
--layer-name 'telemetry-api-extension' \
--zip-file 'fileb://bin/extension.zip' \
--region ap-northeast-1

Lambda 関数については、下記コマンドで作成します。中で AWS CLI コマンドを叩いていてややこしく見えますが、各 ARN 記述する必要がなく、アカウント ID に依存しない形になっています。

aws lambda create-function \
--function-name 'function-with-telemetry-api-extension' \
--runtime 'python3.9' \
--handler 'main.lambda_handler' \
--role $(
  aws iam get-role \
  --role-name 'telemetry-api-function-role' \
  --query 'Role.Arn' \
  --output text) \
--zip-file fileb://function.zip \
--layers $(
  aws lambda list-layer-versions \
  --layer-name 'telemetry-api-extension' \
  --query 'LayerVersions[0].LayerVersionArn' \
  --output text) \
--region ap-northeast-1

実行してログを確認

Extension を設定した Lambda 関数が作成できたので、下記コマンドで実行してみます。

aws lambda invoke \
--function-name 'function-with-telemetry-api-extension' \
--invocation-type 'RequestResponse' \
--cli-binary-format 'raw-in-base64-out' \
--region 'ap-northeast-1' \
--log-type 'Tail' \
/dev/stdout \
| jq -sr '.[1] | .LogResult' \
| base64 -d

上記コマンドを実行すると、 Lambda 関数実行時のログが手元で確認できます。

 1[Telemetry API Extension Client] INFO: Succeeded to register extension.
 2[Telemetry API Subscriber] INFO: Starting on address:sandbox.localdomain:1210
 3TELEMETRY       Name: telemetry-api-extension   State: Subscribed       Types: [function,platform]
 4[Telemetry API Subscriber] INFO: Received 1 events.
 5[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:21:53.222Z Type:platform.initStart Record:map[initializationType:on-demand phase:init]
 6[Telemetry API Extension Client] INFO: Waiting for next event...
 7[Telemetry API Subscriber] INFO: Received 1 events.
 8[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:21:53.277Z Type:platform.telemetrySubscription Record:map[name:telemetry-api-extension state:Subscribed types:[function platform]]
 9EXTENSION       Name: telemetry-api-extension   State: Ready    Events: [SHUTDOWN,INVOKE]
10START RequestId: eded6372-e614-4305-8516-f2697c3acfbc Version: $LATEST
11[Telemetry API Extension Client] INFO: Received invoke event. awsRequestId:eded6372-e614-4305-8516-f2697c3acfbc invokedAt:2022-12-11 10:21:53.381772081 +0000 UTC
12[Telemetry API Extension Client] INFO: Waiting for next event...
13[INFO]  2022-12-11T10:21:53.382Z        eded6372-e614-4305-8516-f2697c3acfbc    [eded6372-e614-4305-8516-f2697c3acfbc] Hello Telemetry API!
14END RequestId: eded6372-e614-4305-8516-f2697c3acfbc
15REPORT RequestId: eded6372-e614-4305-8516-f2697c3acfbc  Duration: 17.38 ms      Billed Duration: 18 ms  Memory Size: 128 MB       Max Memory Used: 45 MB  Init Duration: 157.98 ms

なんとなく冒頭に書いたような順番で処理がされてそうなことがわかると思います。

例えば、 1 行目の

[Telemetry API Extension Client] INFO: Succeeded to register extension.

では、メッセージが示すとおり Extension の登録が完了したことがわかります。

また、 4-5 行目の

[Telemetry API Subscriber] INFO: Received 1 events. [Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:21:53.222Z Type:platform.initStart Record:map

では、 Telemetry API から Platform に関するイベントを受け取っていることがわかります。

とは言え、一度関数を実行しただけでは雰囲気が掴みづらいと思うので、何度か invoke-function コマンドを実行した後に、下記のコマンドで CloudWatch Logs に出力されたログを確認してみます。

aws logs get-log-events \
--log-group-name /aws/lambda/function-with-telemetry-api-extension \
--log-stream-name "$(
  aws logs describe-log-streams \
  --log-group-name /aws/lambda/function-with-telemetry-api-extension \
  --query 'max_by(logStreams[], &lastEventTimestamp).logStreamName' \
  --output text)" \
--limit 100 \
--query 'events[].message' \
--output text

得られる出力は下記のようになります。

 1[Telemetry API Extension Client] INFO: Succeeded to register extension.
 2[Telemetry API Subscriber] INFO: Starting on address:sandbox.localdomain:1210
 3TELEMETRY	Name: telemetry-api-extension	State: Subscribed	Types: [function,platform]
 4[Telemetry API Extension Client] INFO: Waiting for next event...
 5[Telemetry API Subscriber] INFO: Received 1 events.
 6[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:32:46.331Z Type:platform.initStart Record:map[initializationType:on-demand phase:init]
 7[Telemetry API Subscriber] INFO: Received 1 events.
 8[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:32:46.389Z Type:platform.telemetrySubscription Record:map[name:telemetry-api-extension state:Subscribed types:[function platform]]
 9EXTENSION	Name: telemetry-api-extension	State: Ready	Events: [SHUTDOWN,INVOKE]
10START RequestId: e63295fe-c7a1-48c2-ada2-c7044c697c12 Version: $LATEST
11[Telemetry API Extension Client] INFO: Received invoke event. awsRequestId:e63295fe-c7a1-48c2-ada2-c7044c697c12 invokedAt:2022-12-11 10:32:46.510767828 +0000 UTC
12[Telemetry API Extension Client] INFO: Waiting for next event...
13[INFO]	2022-12-11T10:32:46.511Z	e63295fe-c7a1-48c2-ada2-c7044c697c12	[e63295fe-c7a1-48c2-ada2-c7044c697c12] Hello Telemetry API!
14END RequestId: e63295fe-c7a1-48c2-ada2-c7044c697c12
15REPORT RequestId: e63295fe-c7a1-48c2-ada2-c7044c697c12	Duration: 16.30 ms	Billed Duration: 17 ms	Memory Size: 128 MB	Max Memory Used: 46 MB	Init Duration: 177.38 ms
16[Telemetry API Subscriber] INFO: Received 7 events.
17[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:32:46.507Z Type:platform.initRuntimeDone Record:map[initializationType:on-demand phase:init status:success]
18[Telemetry API Subscriber] INFO: 1: Time:2022-12-11T10:32:46.508Z Type:platform.extension Record:map[events:[SHUTDOWN INVOKE] name:telemetry-api-extension state:Ready]
19[Telemetry API Subscriber] INFO: 2: Time:2022-12-11T10:32:46.508Z Type:platform.initReport Record:map[initializationType:on-demand metrics:map[durationMs:176.689] phase:init]
20[Telemetry API Subscriber] INFO: 3: Time:2022-12-11T10:32:46.51Z Type:platform.start Record:map[requestId:e63295fe-c7a1-48c2-ada2-c7044c697c12 version:$LATEST]
21[Telemetry API Subscriber] INFO: 4: Time:2022-12-11T10:32:46.511Z Type:function Record:[INFO]	2022-12-11T10:32:46.511Z	e63295fe-c7a1-48c2-ada2-c7044c697c12	[e63295fe-c7a1-48c2-ada2-c7044c697c12] Hello Telemetry API!
22[Telemetry API Subscriber] INFO: 5: Time:2022-12-11T10:32:46.526Z Type:platform.runtimeDone Record:map[metrics:map[durationMs:15.686 producedBytes:53] requestId:e63295fe-c7a1-48c2-ada2-c7044c697c12 spans:[map[durationMs:1.26 name:responseLatency start:2022-12-11T10:32:46.510Z] map[durationMs:0.021 name:responseDuration start:2022-12-11T10:32:46.511Z]] status:success]
23[Telemetry API Subscriber] INFO: 6: Time:2022-12-11T10:32:46.532Z Type:platform.report Record:map[metrics:map[billedDurationMs:17 durationMs:16.295 initDurationMs:177.377 maxMemoryUsedMB:46 memorySizeMB:128] requestId:e63295fe-c7a1-48c2-ada2-c7044c697c12 status:success]
24START RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe Version: $LATEST
25[Telemetry API Extension Client] INFO: Received invoke event. awsRequestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe invokedAt:2022-12-11 10:32:49.885648337 +0000 UTC
26[Telemetry API Extension Client] INFO: Waiting for next event...
27[INFO]	2022-12-11T10:32:49.885Z	29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	[29fffe63-ae9a-4dce-ad28-0a2bd117e5fe] Hello Telemetry API!
28END RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe
29REPORT RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	Duration: 1.30 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 46 MB
30[Telemetry API Subscriber] INFO: Received 4 events.
31[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:32:49.885Z Type:platform.start Record:map[requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe version:$LATEST]
32[Telemetry API Subscriber] INFO: 1: Time:2022-12-11T10:32:49.886Z Type:function Record:[INFO]	2022-12-11T10:32:49.885Z	29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	[29fffe63-ae9a-4dce-ad28-0a2bd117e5fe] Hello Telemetry API!
33[Telemetry API Subscriber] INFO: 2: Time:2022-12-11T10:32:49.886Z Type:platform.runtimeDone Record:map[metrics:map[durationMs:1.065 producedBytes:53] requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe spans:[map[durationMs:0.791 name:responseLatency start:2022-12-11T10:32:49.885Z] map[durationMs:0.032 name:responseDuration start:2022-12-11T10:32:49.886Z]] status:success]
34[Telemetry API Subscriber] INFO: 3: Time:2022-12-11T10:32:49.887Z Type:platform.report Record:map[metrics:map[billedDurationMs:2 durationMs:1.3 maxMemoryUsedMB:46 memorySizeMB:128] requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe status:success]
35[Telemetry API Extension Client] INFO: Received shutdown event. reason:spindown

Telemetry API から送信されるイベントは Subscribe API をコールするときにリクエストボディにセットする buffering の設定に従ってバッファリングされるため実際のイベント発生時とは多少のラグがあります。ただ、 24-34 行目あたりは普段の Lambda 関数実行時に出力されるログと、Telemetry API のイベントとがわかりやすいかと思います。

24START RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe Version: $LATEST
25[Telemetry API Extension Client] INFO: Received invoke event. awsRequestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe invokedAt:2022-12-11 10:32:49.885648337 +0000 UTC
26[Telemetry API Extension Client] INFO: Waiting for next event...
27[INFO]	2022-12-11T10:32:49.885Z	29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	[29fffe63-ae9a-4dce-ad28-0a2bd117e5fe] Hello Telemetry API!
28END RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe
29REPORT RequestId: 29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	Duration: 1.30 ms	Billed Duration: 2 ms	Memory Size: 128 MB	Max Memory Used: 46 MB
30[Telemetry API Subscriber] INFO: Received 4 events.
31[Telemetry API Subscriber] INFO: 0: Time:2022-12-11T10:32:49.885Z Type:platform.start Record:map[requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe version:$LATEST]
32[Telemetry API Subscriber] INFO: 1: Time:2022-12-11T10:32:49.886Z Type:function Record:[INFO]	2022-12-11T10:32:49.885Z	29fffe63-ae9a-4dce-ad28-0a2bd117e5fe	[29fffe63-ae9a-4dce-ad28-0a2bd117e5fe] Hello Telemetry API!
33[Telemetry API Subscriber] INFO: 2: Time:2022-12-11T10:32:49.886Z Type:platform.runtimeDone Record:map[metrics:map[durationMs:1.065 producedBytes:53] requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe spans:[map[durationMs:0.791 name:responseLatency start:2022-12-11T10:32:49.885Z] map[durationMs:0.032 name:responseDuration start:2022-12-11T10:32:49.886Z]] status:success]
34[Telemetry API Subscriber] INFO: 3: Time:2022-12-11T10:32:49.887Z Type:platform.report Record:map[metrics:map[billedDurationMs:2 durationMs:1.3 maxMemoryUsedMB:46 memorySizeMB:128] requestId:29fffe63-ae9a-4dce-ad28-0a2bd117e5fe status:success]

各行のログは下記のような情報を示しています。

  1. Lambda 関数が Invoke された
  2. Extension API の GET /extension/event/next のレスポンスとして INVOKE イベントを取得
  3. 再度 Extension API の GET /extension/event/next をコールして次のイベントを待機
  4. Lambda 関数の logger.info() が出力しているログ
  5. Lambda 関数の終了
  6. Lambda 関数の実行レポート
  7. Subscriber が Telemetry API から、バッファリングされていた 4 つのイベントを受信した
  8. platform.start イベント (24 行目: Lambda 関数の Invoke に対応)
  9. function イベント (27 行目: Lambda 関数内でのログ出力に対応)
  10. platform.runtimeDone イベント (28 行目: Lambda 関数の終了に対応)
  11. platform.report イベント (29 行目: Lambda 関数の実行レポートに対応)

以上で、 Telemetry API によってどのようなイベントが取得できるのか、実際の Lambda 関数の実行と合わせて確認ができました。

まとめ

AWS Lambda の Telemetry API を使った Lambda Extension を作ってみた話でした。

Telemetry API のリリース情報を見たときは「お、なんか凄そう?」という感想だけでしたが、実際にこれを使う Extension を作ってみてどのような挙動をするものなのか、理解ができた気がします。

今回はただ受け取ったイベントをログとして出力するだけでしたが、例えば function イベントを取得して Lambda 関数が出力しているログの文字列を解析して独自のレポートを出力する みたいなことをやると面白そうだなと思います。

弁護士ドットコム Advent Calendar 2022 、明日の担当は @shellme です。お楽しみに。


  1. Subscribe API をコールするところで 404 Page Not Found が返ってきました ↩︎


comments powered by Disqus