【アップデート】Lambda Extensionsのオブザーバビリティをさらに強化するTelemetry APIが利用可能になりました

Logs APIの強化版といえるTelemetry APIが利用可能になりました。Logs APIは継続して提供されますが、今後Telemetry APIに移行することが推奨されます。
2022.11.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業部@大阪の岩田です。

11/10付のアップデートでLambdaのTelemetry APIが利用可能になりました。

Lambdaというサービスは従来もLogs APIを提供しており、Lambda ExtensionsからLogs APIを利用することでLambda Functionからはログの出力先を意識することなく、透過的にログを任意のサービスに保存するといった構成が実現できました。以前のブログでもLambda FunctionのログをGoogle CloudのGloud Loggingに送信する例を紹介しています。

今回リリースされたTelemetry APIは従来のLogs APIの強化版とも言うべき存在で、Logs APIで取得できた情報に加えてLambda 実行環境のライフサイクルに関連するイベントとエラーに関するトレースとメトリクスが追加で取得できるようになっています。例えばLogs APIではLambda Functionのinitフェーズの情報が取得できませんでしたが、Telemetry APIではinitフェーズの情報も取得可能です。

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. You can subscribe your extension to a telemetry stream using either the Telemetry API or the Logs API. After subscribing using one of these APIs, any attempt to subscribe using the other API returns an error.

Telemetry APIの概要

Telemetry APIは以下の手順で利用します。このあたりの手順はLogs APIと同様です。

※画像は公式ドキュメントより引用

  1. Lambda Extensions APIを利用してExtensionを登録する
  2. Extension内でテレメトリリスナーを作成する。テレメトリリスナーはTCPサーバーもしくはHTTPサーバーが利用可能で、HTTPサーバーの利用が推奨されています
  3. Telemetry API の Subscribe API を使用して、テレメトリ ストリームをサブスクライブする
  4. 以後Telemetry APIからテレメトリリスナーに対してテレメトリデータがPOSTされてくるので、テレメトリリスナー側で外部サービスとの連携など任意の処理を実行する

Telemetry APIの仕様

Telemetry APIの仕様について簡単に解説します

Subscribe API

まずテレメトリリスナーからTelemetryストリームをサブスクライブする際に利用する Subscribe APIです。

  • エンドポイント: `http://${AWS_LAMBDA_RUNTIME_API}/2022-07-01/telemetry/`
  • メソッド: PUT
  • リクエストヘッダ: Content-Type:application/json
  • リクエストボディ
    • schemaVersion...必須項目。現在は"2022-07-01"のみ指定可能
    • destination...必須項目 以下の構造のオブジェクト
      • protocol...必須項目 TCPもしくはHTTPが指定可能
      • URI...必須項目 テレメトリリスナーのエンドポイントを指定
    • types... 必須項目 サブスクライブ対象の情報を配列で指定 対象は以下の3つが指定可能
      • platform
      • function
      • extension
    • buffering...任意項目 バッファリング関連の挙動を調整するために利用 以下の構造のオブジェクト
      • maxItems... メモリにバッファするイベントの最大数 デフォルト:10,000 最小:1,000 最大:10,000
      • maxBytes... メモリにバッファするログの最大サイズ (バイト単位) デフォルト:262,144 最小:262,144 最大:1,048,576
      • timeoutMs... イベントのバッチをバッファーする最大時間(ミリ秒単位) デフォルト:1000 最小: 25 最大:30000

エンドポイントとリクエストボディのschemaVersionを除いてLogs APIと同様の仕様となっています。

HTTPリクエストの例としては以下のような形式となります。

PUT http://${AWS_LAMBDA_RUNTIME_API}/2022-07-01/telemetry HTTP/1.1
{
   "schemaVersion": "2022-07-01",
   "types": [
        "platform",
        "function",
        "extension"
   ],
   "buffering": {
        "maxItems": 1000,
        "maxBytes": 256*1024,
        "timeoutMs": 100
   },
   "destination": {
        "protocol": "HTTP",
        "URI": "http://sandbox.localdomain:8080"
   }
}

Telemetry APIがテレメトリリスナーにPOSTするデータ

Subscribe APIでテレメトリストリームのサブスクライブが完了すると、以後はTelemetry APIがテレメトリリスナーに各種イベントのデータをPOSTしてきます。Telemetry APIはLogs APIの上位互換とのことなので、イベントの数や取得可能な情報がLogs APIより増えていると思われます。Telemetry APIのドキュメントLogs APIのドキュメントを比較しながら、それぞれのイベント種別をまとめてみました。

イベントの種別(Telemetry API) イベントの種別(Logs API)
platform.initStart 該当なし
platform.initRuntimeDone 該当なし
platform.initReport 該当なし
platform.start platform.start
platform.runtimeDone platform.runtimeDone
※サブスクライブ時にスキーマバージョン2021-03-18を指定した場合に利用可能
platform.report platform.report
platform.telemetrySubscription platform.logsSubscription
※イベントの名称は違うが実質同じイベントと考えられそう
platform.logsDropped
※ドキュメントにtelemetryDroppedではなくlogsDroppedと記載されている
platform.logsDropped
function function ※ドキュメント上は記載がなさそう
extension extension ※ドキュメント上は記載がなさそう
該当なし?? platform.end
該当なし?? platform.fault
該当なし?? platform.extension

パット見た感じplatform.initxxxというイベントが増えていそうですね。

実際にPOSTされるデータのサンプルをいくつか紹介しておきます。

typeがplatform.initStartの場合

{
    "time": "2022-10-12T00:00:15.064Z",
    "type": "platform.initStart",
    "record": {
        "initializationType": "on-demand",
        "phase": "init",
        "runtimeVersion": "nodejs-14.v3",
        "runtimeVersionArn": "arn"
    }
}

Provisioned Concurrencyの利用有無やランタイムの情報がPOSTされてきます

typeがfunctionの場合

{
    "time": "2022-10-12T00:03:50.000Z",
    "type": "function",
    "record": "[INFO] Hello world, I am a function!"
}

これはLambda Functionから出力したログがPOSTされてくる形になります。

やってみる

では、実際にTelemetry APIを使いながらLogs APIと比較してみましょう。Telemetry APIとLogs APIそれぞれplatform,function,extension3つのイベントをサブスクライブしつつExtensionにPOSTされてきたデータをログに出力してみました。Lambda Function本体では以下のコードを実行しています。

import json
import boto3
from aws_xray_sdk.core import patch_all

print('Lambda Function初期化のログ')
patch_all()
s3 = boto3.client('s3')
buckets = s3.list_buckets()

def lambda_handler(event, context):
    print('Lambda Functionのhandler内のログ')
    s3.list_buckets()
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

LambdaExtensionはサンプル集のリポジトリで公開されているものを利用します。デプロイ手順などは割愛しているので、興味のある方はリポジトリのREADMEを参考にデプロイしてみて下さい。

利用した環境は以下の通りです。

  • サンプルコードのコミットハッシュ: e17cd76e444ab947518e3cab428d574e6ec0a74d
  • Lambdaのランタイム: Python3.9
  • アクティブトレース(X-Ray): 有効

Logs APIの場合

まず従来のLogs APIの場合です。サンプルコードのpython-example-logs-api-extensionというディレクトリ配下のコードをデプロイして利用します。ExtensionをデプロイしてLambdaをテスト実行するとExtensionからBATCH RECEIVED: ...というログが出力されます。以下のようなログが出力されました。

{'record': {'name': 'logs_api_http_extension.py',
             'state': 'Subscribed',
             'types': ['platform', 'function']},
  'time': '2022-11-12T00:13:39.112Z',
  'type': 'platform.logsSubscription'},
 {'record': 'Lambda Function初期化のログ\n',
  'time': '2022-11-12T00:13:39.648Z',
  'type': 'function'},
 {'record': '[WARNING]\t2022-11-12T00:13:39.804Z\t\tSubsegment s3 discarded '
            'due to Lambda worker still initializing\n',
  'time': '2022-11-12T00:13:39.805Z',
  'type': 'function'},
 {'record': '[WARNING]\t2022-11-12T00:13:40.042Z\t\tNo subsegment to end.\n',
  'time': '2022-11-12T00:13:40.042Z',
  'type': 'function'},
 {'record': {'events': ['INVOKE', 'SHUTDOWN'],
             'name': 'logs_api_http_extension.py',
             'state': 'Ready'},
  'time': '2022-11-12T00:13:40.043Z',
  'type': 'platform.extension'},
 {'record': {'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45',
             'version': '$LATEST'},
  'time': '2022-11-12T00:13:40.044Z',
  'type': 'platform.start'},
 {'record': 'Lambda Functionのhandler内のログ\n',
  'time': '2022-11-12T00:13:40.045Z',
  'type': 'function'},
 {'record': {'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45'},
  'time': '2022-11-12T00:13:40.086Z',
  'type': 'platform.end'},
 {'record': {'metrics': {'billedDurationMs': 40,
                         'durationMs': 39.558,
                         'initDurationMs': 1053.794,
                         'maxMemoryUsedMB': 84,
                         'memorySizeMB': 1280},
             'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45',
             'tracing': {'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee532-7dcbb1e45eb845b470906f62;Parent=12877004f17844b3;Sampled=1'}},
  'time': '2022-11-12T00:13:40.086Z',
  'type': 'platform.report'}

Telemetry APIの場合

続いてTelemetry APIです。こちらはサンプルコードのpython-example-telemetry-api-extensionというディレクトリ配下のコードをデプロイして利用します。Logs APIと同様CW Logsに出力されたログを確認したいので、telemetry_dispatcher.pyのコードを以下のように修正して利用します。

if DISPATCH_POST_URI is None:
    # 以下をコメントアウト
    # print ('[telementry_dispatcher:dispatch] dispatchPostUri not found. Discarding log events from the queue')
    # 以下を追加
    print(f"BATCH RECEIVED: {batch}", flush=True)

これで環境変数DISPATCH_POST_URIが設定されていない場合にログを破棄していたところが、ClW Logsにログを出力するような動きに変わります。ExtensionをデプロイしてLambdaをテスト実行するとExtensionから`BATCH RECEIVED: ...から始まる以下のようなログが出力されました。

{'record': {'initializationType': 'on-demand', 'phase': 'init'},
  'time': '2022-11-12T00:30:50.187Z',
  'type': 'platform.initStart'},
 {'record': 'python_example_telemetry_api_extension  launching extension\n',
  'time': '2022-11-12T00:30:50.198Z',
  'type': 'extension'},
 {'record': 'Starting the Telemetry API Extension\n',
  'time': '2022-11-12T00:30:50.492Z',
  'type': 'extension'},
 {'record': 'Extension Main: Registring the extension using extension name: '
            'python_example_telemetry_api_extension\n',
  'time': '2022-11-12T00:30:50.493Z',
  'type': 'extension'},
 {'record': '[extension_api_client.register_extension] Registering Extension '
            'using http://127.0.0.1:9001/2020-01-01/extension\n',
  'time': '2022-11-12T00:30:50.497Z',
  'type': 'extension'},
 {'record': '[extension_api_client.register_extension] Registration success '
            'with extensionId 303f3da2-32bb-48a5-b9bf-2fe2a3e5bc97\n',
  'time': '2022-11-12T00:30:50.497Z',
  'type': 'extension'},
 {'record': 'Extension Main: Starting the http listener which will receive '
            'data from Telemetry API\n',
  'time': '2022-11-12T00:30:50.497Z',
  'type': 'extension'},
 {'record': '[telemetery_http_listener.start_http_listener] Starting http '
            'listener on sandbox.localdomain:4243\n',
  'time': '2022-11-12T00:30:50.510Z',
  'type': 'extension'},
 {'record': '[telemetery_http_listener.start_http_listener] Started http '
            'listener\n',
  'time': '2022-11-12T00:30:50.510Z',
  'type': 'extension'},
 {'record': 'Extension Main: Subscribing the listener to TelemetryAPI\n',
  'time': '2022-11-12T00:30:50.510Z',
  'type': 'extension'},
 {'record': {'name': 'python_example_telemetry_api_extension',
             'state': 'Subscribed',
             'types': ['platform', 'function', 'extension']},
  'time': '2022-11-12T00:30:50.513Z',
  'type': 'platform.telemetrySubscription'},  
{'record': '169.254.79.129 - - [12/Nov/2022 00:30:50] "POST / HTTP/1.1" 200 '
            '-\n',
  'time': '2022-11-12T00:30:50.515Z',
  'type': 'extension'},
 {'record': '[telemetry_api_client.subscibe_listener] Subscribing Extension to '
            'receive telemetry data. ExtenionsId: '
            '303f3da2-32bb-48a5-b9bf-2fe2a3e5bc97, listener url: '
            'http://sandbox.localdomain:4243, telemetry api url: '
            'http://127.0.0.1:9001/2022-07-01/telemetry\n',
  'time': '2022-11-12T00:30:50.517Z',
  'type': 'extension'},
 {'record': '[telemetry_api_client.subscibe_listener] Extension successfully '
            'subscribed to telemetry api "OK"\n',
  'time': '2022-11-12T00:30:50.517Z',
  'type': 'extension'},
 {'record': 'Extension Main: Next\n',
  'time': '2022-11-12T00:30:50.517Z',
  'type': 'extension'},
 {'record': 'Lambda Function初期化のログ\n',
  'time': '2022-11-12T00:30:51.048Z',
  'type': 'function'},
 {'record': '[WARNING]\t2022-11-12T00:30:51.204Z\t\tSubsegment s3 discarded '
            'due to Lambda worker still initializing\n',
  'time': '2022-11-12T00:30:51.204Z',
  'type': 'function'},
 {'record': '[WARNING]\t2022-11-12T00:30:51.427Z\t\tNo subsegment to end.\n',
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'function'},
 {'record': {'initializationType': 'on-demand',
             'phase': 'init',
             'status': 'success'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.initRuntimeDone'},
 {'record': {'events': ['INVOKE', 'SHUTDOWN'],
             'name': 'python_example_telemetry_api_extension',
             'state': 'Ready'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.extension'},
 {'record': {'initializationType': 'on-demand',
             'metrics': {'durationMs': 1242.974},
             'phase': 'init'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.initReport'},
 {'record': {'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'},
             'version': '$LATEST'},
  'time': '2022-11-12T00:30:51.432Z',
  'type': 'platform.start'},
 {'record': 'Extension Main: Handle Invoke Event\n',
  'time': '2022-11-12T00:30:51.433Z',
  'type': 'extension'},
 {'record': '[telementry_dispatcher] Dispatch telemetry data\n',
  'time': '2022-11-12T00:30:51.433Z',
  'type': 'extension'},
 {'record': "BATCH RECEIVED: [{'time': '2022-11-12T00:30:50.187Z', 'type': "
            "'platform.initStart', 'record': {'initializationType': "
            "'on-demand', 'phase': 'init'}}, {'time': "
            "'2022-11-12T00:30:50.198Z', 'type': 'extension', 'record': "
            "'python_example_telemetry_api_extension  launching "
            "extension\\n'}, {'time': '2022-11-12T00:30:50.492Z', 'type': "
            "'extension', 'record': 'Starting the Telemetry API "
            "Extension\\n'}, {'time': '2022-11-12T00:30:50.493Z', 'type': "
            "'extension', 'record': 'Extension Main: Registring the extension "
            'using extension name: '
            "python_example_telemetry_api_extension\\n'}, {'time': "
            "'2022-11-12T00:30:50.497Z', 'type': 'extension', 'record': "
            "'[extension_api_client.register_extension] Registering Extension "
            "using http://127.0.0.1:9001/2020-01-01/extension\\n'}, {'time': "
            "'2022-11-12T00:30:50.497Z', 'type': 'extension', 'record': "
            "'[extension_api_client.register_extension] Registration success "
            "with extensionId 303f3da2-32bb-48a5-b9bf-2fe2a3e5bc97\\n'}, "
            "{'time': '2022-11-12T00:30:50.497Z', 'type': 'extension', "
            "'record': 'Extension Main: Starting the http listener which will "
            "receive data from Telemetry API\\n'}, {'time': "
            "'2022-11-12T00:30:50.510Z', 'type': 'extension', 'record': "
            "'[telemetery_http_listener.start_http_listener] Starting http "
            "listener on sandbox.localdomain:4243\\n'}, {'time': "
            "'2022-11-12T00:30:50.510Z', 'type': 'extension', 'record': "
            "'[telemetery_http_listener.start_http_listener] Started http "
            "listener\\n'}, {'time': '2022-11-12T00:30:50.510Z', 'type': "
            "'extension', 'record': 'Extension Main: Subscribing the listener "
            "to TelemetryAPI\\n'}, {'time': '2022-11-12T00:30:50.513Z', "
            "'type': 'platform.telemetrySubscription', 'record': {'name': "
            "'python_example_telemetry_api_extension', 'state': 'Subscribed', "
            "'types': ['platform', 'function', 'extension']}}]\n",
  'time': '2022-11-12T00:30:51.433Z',
  'type': 'extension'},
 {'record': 'Extension Main: Next\n',
  'time': '2022-11-12T00:30:51.433Z',
  'type': 'extension'},
 {'record': 'Lambda Functionのhandler内のログ\n',
  'time': '2022-11-12T00:30:51.434Z',
  'type': 'function'},
 {'record': {'metrics': {'durationMs': 39.245, 'producedBytes': 53},
             'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'spans': [{'durationMs': 38.699,
                        'name': 'responseLatency',
                        'start': '2022-11-12T00:30:51.432Z'},
                       {'durationMs': 0.083,
                        'name': 'responseDuration',
                        'start': '2022-11-12T00:30:51.470Z'}],
             'status': 'success',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'}},
  'time': '2022-11-12T00:30:51.471Z',
  'type': 'platform.runtimeDone'},
 {'record': {'metrics': {'billedDurationMs': 40,
                         'durationMs': 39.798,
                         'initDurationMs': 1243.106,
                         'maxMemoryUsedMB': 91,
                         'memorySizeMB': 1280},
             'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'status': 'success',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'}},
  'time': '2022-11-12T00:30:51.473Z',
  'type': 'platform.report'}

Logs APIに比べて情報量が多いですね。

比較

Logs APIとTelemetryAPI両方のログが収集できたのでそれぞれのログのtypeを比較してみましょう。typeがfunctionもしくはextensionのログを除くと、出力されたログのtypeは以下のようになりました。

Logs APIの場合

  • platform.logsSubscription
  • platform.extension
  • platform.start
  • platform.end
  • platform.report

※ サンプルのExtensionがログのサブスクライブ時に指定しているスキーマバージョンが2020-08-15なのでplatform.runtimeDoneのログは出力されていません

Telemetry APIの場合

  • platform.initStart
  • platform.telemetrySubscription
  • platform.initRuntimeDone
  • platform.extension
  • platform.initReport
  • platform.start
  • platform.runtimeDone
  • platform.report

情報量が増えているのが分かりますね。

Logs API利用時のログからtypeがfunctionもしくはextensionのログを除いた全体像です

{'record': {'name': 'logs_api_http_extension.py',
             'state': 'Subscribed',
             'types': ['platform', 'function']},
  'time': '2022-11-12T00:13:39.112Z',
  'type': 'platform.logsSubscription'},
 {'record': {'events': ['INVOKE', 'SHUTDOWN'],
             'name': 'logs_api_http_extension.py',
             'state': 'Ready'},
  'time': '2022-11-12T00:13:40.043Z',
  'type': 'platform.extension'},
 {'record': {'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45',
             'version': '$LATEST'},
  'time': '2022-11-12T00:13:40.044Z',
  'type': 'platform.start'},
 {'record': {'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45'},
  'time': '2022-11-12T00:13:40.086Z',
  'type': 'platform.end'},
 {'record': {'metrics': {'billedDurationMs': 40,
                         'durationMs': 39.558,
                         'initDurationMs': 1053.794,
                         'maxMemoryUsedMB': 84,
                         'memorySizeMB': 1280},
             'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45',
             'tracing': {'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee532-7dcbb1e45eb845b470906f62;Parent=12877004f17844b3;Sampled=1'}},
  'time': '2022-11-12T00:13:40.086Z',
  'type': 'platform.report'}

Telemetry API利用時のログからtypeがfunctionもしくはextensionのログを除いた全体像です

[{'record': {'initializationType': 'on-demand', 'phase': 'init'},
  'time': '2022-11-12T00:30:50.187Z',
  'type': 'platform.initStart'},
 {'record': {'name': 'python_example_telemetry_api_extension',
             'state': 'Subscribed',
             'types': ['platform', 'function', 'extension']},
  'time': '2022-11-12T00:30:50.513Z',
  'type': 'platform.telemetrySubscription'},
 {'record': {'initializationType': 'on-demand',
             'phase': 'init',
             'status': 'success'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.initRuntimeDone'},
 {'record': {'events': ['INVOKE', 'SHUTDOWN'],
             'name': 'python_example_telemetry_api_extension',
             'state': 'Ready'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.extension'},
 {'record': {'initializationType': 'on-demand',
             'metrics': {'durationMs': 1242.974},
             'phase': 'init'},
  'time': '2022-11-12T00:30:51.430Z',
  'type': 'platform.initReport'},
 {'record': {'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'},
             'version': '$LATEST'},
  'time': '2022-11-12T00:30:51.432Z',
  'type': 'platform.start'},
 {'record': {'metrics': {'durationMs': 39.245, 'producedBytes': 53},
             'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'spans': [{'durationMs': 38.699,
                        'name': 'responseLatency',
                        'start': '2022-11-12T00:30:51.432Z'},
                       {'durationMs': 0.083,
                        'name': 'responseDuration',
                        'start': '2022-11-12T00:30:51.470Z'}],
             'status': 'success',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'}},
  'time': '2022-11-12T00:30:51.471Z',
  'type': 'platform.runtimeDone'},
 {'record': {'metrics': {'billedDurationMs': 40,
                         'durationMs': 39.798,
                         'initDurationMs': 1243.106,
                         'maxMemoryUsedMB': 91,
                         'memorySizeMB': 1280},
             'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'status': 'success',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'}},
  'time': '2022-11-12T00:30:51.473Z',
  'type': 'platform.report'}]

単にtypeが増えただけではなく、tracingというキー配下にトレース情報が出力されていることが分かります。Logs API/Telemetry API両方が対応しているtype:platform.startのログを比較すると、以下の様にTelemetry APIの方が情報量が多いことが分かります。

Logs APIの場合

{'record': {'requestId': '004d2785-c4f6-4660-86ca-55df3cd7ec45',
             'version': '$LATEST'},
  'time': '2022-11-12T00:13:40.044Z',
  'type': 'platform.start'}

Telemetry APIの場合

{'record': {'requestId': '06d3dee7-5e32-4566-8faa-8e4c8bebf2f8',
             'tracing': {'spanId': '45c22174077fb60e',
                         'type': 'X-Amzn-Trace-Id',
                         'value': 'Root=1-636ee939-7a7bb0813822700c02063428;Parent=099ada3558fb0c87;Sampled=1'},
             'version': '$LATEST'},
  'time': '2022-11-12T00:30:51.432Z',
  'type': 'platform.start'}

Telemetry APIを利用した方がオブザーバビリティが向上しそうですね。一方注意点として、Lambdaのコード内で

from aws_xray_sdk.core import patch_all
patch_all()
s3 = boto3.client('s3')
buckets = s3.list_buckets()

のようにX-Ray SDKを利用してトレースした情報については特にログに出力されていませんでした。Lambda FunctionがX-Rayデーモンに送信する情報についてはTelemetry API側は関与しないということでしょう。まあ、当たり前といえば当たり前かもしれません。

まとめ

新しく利用可能になったTelemetry APIについてご紹介しました。Logs APIに比べて多くの情報が取得できるようになったので、現在Logs APIを利用している環境ではTelemetry APIへの移行を検討してみると良いでしょう。

すでに多くのベンダーからTelemetry APIに対応したLambda Extensionが提供されています。

参考