Lambdaトレーシングのサブセクション
セットアップ

前提条件
Observability ワークショップインスタンス
Observability ワークショップは、多くの場合、Splunk が提供する事前設定済みの Ubuntu EC2 インスタンス上で実施されます。
ワークショップのインストラクターから、割り当てられたワークショップインスタンスの認証情報が提供されます。
インスタンスには以下の環境変数が既に設定されているはずです:
- ACCESS_TOKEN
- REALM
- これらはワークショップ用の Splunk Observability Cloud の Access Token と Realm です。
- これらは OpenTelemetry Collector によって、データを正しい Splunk Observability Cloud 組織に転送するために使用されます。
また、Multipass を使用してローカルの Observability ワークショップインスタンスをデプロイすることもできます。
AWS Command Line Interface (awscli)
AWS Command Line Interface、またはawscli
は、AWS リソースと対話するために使用される API です。このワークショップでは、特定のスクリプトがデプロイするリソースと対話するために使用されます。
Splunk が提供するワークショップインスタンスには、既に awscli がインストールされているはずです。
Terraform は、リソースを構成ファイルで定義することで、デプロイ、管理、破棄するための Infrastructure as Code(IaC)プラットフォームです。Terraform は HCL を使用してこれらのリソースを定義し、さまざまなプラットフォームやテクノロジのための複数のプロバイダーをサポートしています。
このワークショップでは、コマンドラインで Terraform を使用して、以下のリソースをデプロイします:
- AWS API Gateway
- Lambda 関数
- Kinesis Stream
- CloudWatch ロググループ
- S3 バケット
Splunk が提供するワークショップインスタンスには、既に terraform がインストールされているはずです。
ワークショップディレクトリ (o11y-lambda-workshop)
ワークショップディレクトリ o11y-lambda-workshop
は、今日使用する例の Lambda ベースのアプリケーションの自動計装と手動計装の両方を完了するための、すべての設定ファイルとスクリプトを含むリポジトリです。
git clone https://github.com/gkono-splunk/o11y-lambda-workshop.git
AWS
AWS の CLI では、サービスによってデプロイされたリソースにアクセスし管理するための認証情報が必要です。このワークショップでは、Terraform と Python スクリプトの両方がタスクを実行するためにこれらの変数を必要とします。
Terraform では、機密情報や動的データを.tf 設定ファイルにハードコーディングさせない、またはそれらの値をリソース定義全体で再利用できるようにするため、変数の受け渡しをサポートしています。
このワークショップでは、OpenTelemetry Lambda layer の適切な値で Lambda 関数をデプロイするため、Splunk Observability Cloud の取り込み値のため、そして環境とリソースを独自で即座に認識できるようにするための変数を Terraform で必要とします。
Terraform 変数(variable)は以下の方法で定義されます:
- 変数を main.tf ファイルまたは variables.tf に定義する
- 以下のいずれかの方法で変数の値を設定する:
- ホストレベルで環境変数を設定し、その定義と同じ変数名を使用して、接頭辞として TF_VAR をつける
- terraform.tfvars ファイルに変数の値を設定する
- terraform apply 実行時に引数として値を渡す
このワークショップでは、variables.tf と terraform.tfvars ファイルの組み合わせを使用して変数を設定します。
vi または nano のいずれかを使用して、auto または manual ディレクトリにある terraform.tfvars ファイルを開きます
vi ~/o11y-lambda-workshop/auto/terraform.tfvars
変数に値を設定します。CHANGEME プレースホルダーをインストラクターから提供された値に置き換えてください。
o11y_access_token = "CHANGEME"
o11y_realm = "CHANGEME"
otel_lambda_layer = ["CHANGEME"]
prefix = "CHANGEME"
- 引用符(")や括弧 ( [ ] ) はそのまま残し、プレースホルダー
CHANGEME
のみを変更してください。 - prefix は、他の参加者のリソースと区別するため、任意の文字列で設定する固有の識別子です。氏名やメールアドレスのエイリアスを使用することをお勧めします。
- prefix には小文字のみを使用してください。S3 のような特定の AWS リソースでは、大文字を使用するとエラーが発生します。
ファイルを保存してエディタを終了します。
最後に、編集した terraform.tfvars ファイルを他のディレクトリにコピーします。
cp ~/o11y-lambda-workshop/auto/terraform.tfvars ~/o11y-lambda-workshop/manual
- これは、自動計装と手動計装の両方の部分で同じ値を使用するためです
ファイル権限
他のすべてのファイルはそのままでよいですが、auto
とmanual
の両方にあるsend_message.pyスクリプトは、ワークショップの一部として実行する必要があります。そのため、期待通りに実行するには、適切な権限が必要です。以下の手順に従って設定してください。
これで前提条件が整いましたので、ワークショップを始めることができます!
自動計装
ワークショップの最初の部分では、OpenTelemetry による自動計装がどのようにして OpenTelemetry Collector に関数がどの言語で書かれているかを自動検出させ、それらの関数のトレースの取得を開始させるかを示します。
自動計装ワークショップディレクトリとコンテンツ
まず、o11y-lambda-workshop/auto
ディレクトリとそのファイルの一部を見てみましょう。ここにはワークショップの自動計装部分のすべてのコンテンツがあります。
auto
ディレクトリ
main.tf
ファイル
ワークショップの質問
- このテンプレートによってどの AWS リソースが作成されているか特定できますか?
- OpenTelemetry 計装がどこでセットアップされているか特定できますか?
- ヒント: Lambda 関数の定義を調べてください
- 以前に設定した環境変数によってどの計装情報が提供されているか判断できますか?
各 Lambda 関数の環境変数が設定されているセクションが見つかるはずです。
environment {
variables = {
SPLUNK_ACCESS_TOKEN = var.o11y_access_token
SPLUNK_REALM = var.o11y_realm
OTEL_SERVICE_NAME = "producer-lambda"
OTEL_RESOURCE_ATTRIBUTES = "deployment.environment=${var.prefix}-lambda-shop"
AWS_LAMBDA_EXEC_WRAPPER = "/opt/nodejs-otel-handler"
KINESIS_STREAM = aws_kinesis_stream.lambda_streamer.name
}
}
これらの環境変数を使用することで、いくつかの方法で自動計装を構成しています:
環境変数を設定して、データのエクスポート先となる Splunk Observability Cloud 組織を OpenTelemetry collector に伝えています。
SPLUNK_ACCESS_TOKEN = var.o11y_access_token
SPLUNK_ACCESS_TOKEN = var.o11y_realm
また、OpenTelemetry が関数/サービスを識別し、それが属する環境/アプリケーションを認識するのに役立つ変数も設定しています。
OTEL_SERVICE_NAME = "producer-lambda" # consumer関数の場合はconsumer-lambda
OTEL_RESOURCE_ATTRIBUTES = "deployment.environment=${var.prefix}-lambda-shop"
コード言語に基づいて、関数のハンドラーに自動的にトレースデータを取得するために適用する必要があるラッパーを OpenTelemetry に知らせる環境変数を設定しています。
AWS_LAMBDA_EXEC_WRAPPER - "/opt/nodejs-otel-handler"
producer-lambda
関数の場合、レコードを配置する Kinesis ストリームを関数に知らせるための環境変数を設定しています。
KINESIS_STREAM = aws_kinesis_stream.lambda_streamer.name
これらの値は、「前提条件」セクションで設定した環境変数、および、この Terraform 構成ファイルの一部としてデプロイされるリソースから取得されます。
また、各関数に Splunk OpenTelemetry Lambda layer を設定する引数も確認できるはずです
layers = var.otel_lambda_layer
OpenTelemetry Lambda layer は、Lambda 関数の呼び出し時に計測データを収集、処理、およびエクスポートするために必要なライブラリと依存関係を含むパッケージです。
すべての OpenTelemetry サポート言語のライブラリと依存関係を持つ一般的な OTel Lambda layer がありますが、関数をさらに軽量化するための言語固有の Lambda layer も存在します。
- 各 AWS リージョンの関連する Splunk OpenTelemetry Lambda layer ARN(Amazon Resource Name)と最新バージョンはこちらで確認できます
producer.mjs
ファイル
次に、producer-lambda
関数のコードを見てみましょう:
Lambda 関数のデプロイとトレースデータの生成
auto
ディレクトリの内容に慣れたところで、ワークショップ用のリソースをデプロイし、Lambda 関数からトレースデータを生成していきます。
main.tf
ファイルで定義されたリソースをデプロイするには、まず Terraform がそのファイルと同じフォルダで初期化されていることを確認する必要があります。
Lambda 関数とその他の AWS リソースをデプロイする
このディレクトリで Terraform を初期化したら、リソースのデプロイに進むことができます。
producer-lambda
URL (base_url
) にトラフィックを送信する
デプロイした Lambda 関数からトレースを取得し始めるには、トラフィックを生成する必要があります。producer-lambda
関数のエンドポイントにメッセージを送信し、それを Kinesis ストリームにレコードとして配置し、その後consumer-lambda
関数によってストリームから取得されるようにします。
send_message.py
スクリプトは、コマンドラインで入力を受け取り、JSON ディクショナリに追加し、while ループの一部として producer-lambda
関数のエンドポイントに繰り返し送信する Python スクリプトです。
重要
この場合は、ワークショップ進行役の一人に支援を求めてください。
Lambda 関数のログを表示する
次に、Lambda 関数のログを確認しましょう。
ログを注意深く調べてください。
ワークショップの質問
- OpenTelemetry が読み込まれているのが見えますか?
splunk-extension-wrapper
のある行に注目してください- splunk-extension-wrapperが読み込まれているのを見るために
head -n 50 producer.logs
またはhead -n 50 consumer.logs
の実行を検討してください。
Splunk APM、Lambda関数およびトレース
Lambda 関数は相当量のトレースデータを生成しているはずで、それを確認する必要があります。Lambda 関数のリソース定義で構成された環境変数と OpenTelemetry Lambda layer の組み合わせにより、Splunk APM で関数とトレースを表示する準備が整いました。
Splunk APM 概要で環境名を確認する
まず、Splunk APM が受信しているトレースデータからEnvironment
を認識していることを確認しましょう。これはmain.tf
の Lambda 関数定義で設定したOTEL_RESOURCE_ATTRIBUTES
変数の一部として設定したdeployment.name
です。これは先ほど実行したterraform apply
コマンドの出力の 1 つでもありました。
Splunk Observability Cloud で:
メモ
トレースが Splunk APM に表示されるまで数分かかる場合があります。環境のリストにあなたの環境名が表示されるまで、ブラウザの更新ボタンを押してみてください

環境のサービスマップを表示する
Environment ドロップダウンから環境名を選択したら、Lambda 関数のサービスマップを確認できます。
- APM 概要ページの右側にある
Service Map
ボタンをクリックします。これによりサービスマップビューに移動します。

producer-lambda
関数とそのレコードを配置するために Kinesis ストリームに対して行っている呼び出しが表示されるはずです。

ワークショップの質問
あなたのconsumer-lambda
関数はどうなっていますか?
Lambda 関数からのトレースを調査する
Traces
ボタンをクリックしてトレースアナライザーを表示します。

このページでは、producer-lambda
関数の OpenTelemetry Lambda layer から取り込まれたトレースを確認できます。

- リストからハイパーリンクされた
Trace ID
をクリックして、調査するトレースを選択します。

producer-lambda
関数が Kinesis ストリームにレコードを配置しているのが確認できます。しかし、consumer-lambda
関数のアクションが見当たりません!
これはトレースコンテキストが伝播されていないためです。このワークショップの時点では、Kinesis サービスはトレースコンテキスト伝播をすぐには対応していません。分散トレースは Kinesis サービスで止まっており、そのコンテキストがストリームを通じて自動的に伝播されないため、それ以上先を見ることができません。
少なくとも、今はまだ…
次のセクションでこの問題にどう対処するか見ていきましょう。しかしその前に、後片付けをしましょう!
クリーンアップ
この自動計装演習の一部としてデプロイしたリソースはクリーンアップする必要があります。同様に、producer-lambda
エンドポイントに対してトラフィックを生成していたスクリプトも、まだ実行中であれば停止する必要があります。以下の手順に従ってクリーンアップを行ってください。
send_message
の停止
全ての AWS リソースを破棄する
Terraform は個々のリソースの状態をデプロイメントとして管理するのに優れています。定義に変更があっても、デプロイされたリソースを更新することもできます。しかし、一からやり直すために、リソースを破棄し、このワークショップの手動計装部分の一部として再デプロイします。
以下の手順に従ってリソースを破棄してください:
このプロセスにより、私たちの活動の結果として作成されたファイルとディレクトリは残ります。それらについては心配する必要はありません。
手動計装
ワークショップの第 2 部では、OpenTelemetry による手動計装が計測データ収集を強化する方法を実演することに焦点を当てます。より具体的には、今回のケースでは、producer-lambda
関数からconsumer-lambda
関数にトレースコンテキストデータを伝播させることができるようになります。これにより、現在は自動コンテキスト伝播をサポートしていない Kinesis ストリームを介しても、2 つの関数間の関係を見ることができるようになります。
手動計装ワークショップディレクトリとコンテンツ
再度、作業ディレクトリとそのファイルの一部を確認することから始めます。今回は o11y-lambda-workshop/manual
ディレクトリです。ここにはワークショップの手動計装部分のすべてのコンテンツがあります。
manual
ディレクトリ
ワークショップの質問
このディレクトリと最初に始めた auto ディレクトリに何か違いがありますか?
auto
と manual
のファイルを比較する
見た目が同じように見えるこれらのファイルが実際に同じかどうか確認しましょう。
auto
と manual
ディレクトリの main.tf
ファイルを比較します:
diff ~/o11y-lambda-workshop/auto/main.tf ~/o11y-lambda-workshop/manual/main.tf
- 違いはありません!(違いがあるはずはありません。もし違いがあれば、ワークショップ進行役に支援を求めてください)
次に、producer.mjs
ファイルを比較してみましょう:
diff ~/o11y-lambda-workshop/auto/handler/producer.mjs ~/o11y-lambda-workshop/manual/handler/producer.mjs
ファイル全体を表示してその内容を調べたい場合は以下を実行します:
cat ~/o11y-lambda-workshop/handler/producer.mjs
- 必要な手動計装タスクを処理するために、いくつかの OpenTelemetry オブジェクトを関数に直接インポートしていることに注目してください。
import { context, propagation, trace } from "@opentelemetry/api";
最後に、consumer.mjs
ファイルを比較します:
diff ~/o11y-lambda-workshop/auto/handler/consumer.mjs ~/o11y-lambda-workshop/manual/handler/consumer.mjs
プロデューサー関数からのトレースコンテキスト伝播
以下のコードはプロデューサー関数内で次のステップを実行します:
- このトレース用のトレーサーを取得する
- コンテキストキャリアオブジェクトを初期化する
- アクティブスパンのコンテキストをキャリアオブジェクトに注入する
- Kinesis ストリームに配置しようとしているレコードを修正し、アクティブスパンのコンテキストをコンシューマーに運ぶキャリアを含める
...
import { context, propagation, trace, } from "@opentelemetry/api";
...
const tracer = trace.getTracer('lambda-app');
...
return tracer.startActiveSpan('put-record', async(span) => {
let carrier = {};
propagation.inject(context.active(), carrier);
const eventBody = Buffer.from(event.body, 'base64').toString();
const data = "{\"tracecontext\": " + JSON.stringify(carrier) + ", \"record\": " + eventBody + "}";
console.log(
`Record with Trace Context added:
${data}`
);
try {
await kinesis.send(
new PutRecordCommand({
StreamName: streamName,
PartitionKey: "1234",
Data: data,
}),
message = `Message placed in the Event Stream: ${streamName}`
)
...
span.end();
コンシューマー関数でのトレースコンテキスト抽出
以下のコードはコンシューマー関数内で次のステップを実行します:
producer-lambda
から取得したコンテキストをキャリアオブジェクトに抽出する- 現在のコンテキストからトレーサーを抽出する
- 抽出したコンテキスト内でトレーサーを使用して新しいスパンを開始する
- ボーナス:メッセージからの値を含むカスタム属性など、追加の属性をスパンに追加する!
- 完了したら、スパンを終了する
import { propagation, trace, ROOT_CONTEXT } from "@opentelemetry/api";
...
const carrier = JSON.parse( message ).tracecontext;
const parentContext = propagation.extract(ROOT_CONTEXT, carrier);
const tracer = trace.getTracer(process.env.OTEL_SERVICE_NAME);
const span = tracer.startSpan("Kinesis.getRecord", undefined, parentContext);
span.setAttribute("span.kind", "server");
const body = JSON.parse( message ).record;
if (body.name) {
span.setAttribute("custom.tag.name", body.name);
}
if (body.superpower) {
span.setAttribute("custom.tag.superpower", body.superpower);
}
...
span.end();
これでどのような違いが生まれるか見てみましょう!
Lambda関数のデプロイとトレースデータの生成
トレースデータを収集したい関数やサービスに手動計装を適用する方法がわかったので、Lambda 関数を再度デプロイして、producer-lambda
エンドポイントに対するトラフィックを生成していきましょう。
新しいディレクトリにいるので、ここでもう一度 Terraform を初期化する必要があります。
manual
ディレクトリにいることを確認します:
- 予想される出力は ~/o11y-lambda-workshop/manual です
manual
ディレクトリにいない場合は、次のコマンドを実行します:
cd ~/o11y-lambda-workshop/manual
次のコマンドを実行して、このディレクトリで Terraform を初期化します:
Lambda 関数とその他の AWS リソースをデプロイする
それでは、これらのリソースを再度デプロイしましょう!
見ての通り、base_url の最初の部分とログループ ARN 以外は、このワークショップの自動計装部分をこの同じ時点まで実行したときと出力は概ね同じはずです。
producer-lambda
エンドポイント (base_url) にトラフィックを送信する
もう一度、name
と superpower
をメッセージとしてエンドポイントに送信します。これはトレースコンテキストとともに、Kinesis ストリーム内のレコードに追加されます。
manual
ディレクトリにいることを確認します:
- 予想される出力は ~/o11y-lambda-workshop/manual です
manual
ディレクトリにいない場合は、次のコマンドを実行します:
cd ~/o11y-lambda-workshop/manual
send_message.py
スクリプトをバックグラウンドプロセスとして実行します:
nohup ./send_message.py --name CHANGEME --superpower CHANGEME &
次に、response.logs ファイルの内容を確認して、producer-lambdaエンドポイントへの呼び出しが成功しているか確認します:
重要
これが発生した場合は、ワークショップ進行役の一人に支援を求めてください。
Lambda 関数のログの確認
ログがどのようになっているか見てみましょう。
ログを注意深く調べてください。
ワークショップの質問
違いに気づきましたか?
consumer-lambda
ログからのトレース ID のコピー
今回は、consumer-lambda のロググループが、我々が伝播したtracecontext
とともに、メッセージをrecord
としてログに記録しているのが確認できます。
トレース ID をコピーするには:
Kinesis Message
ログの 1 つを見てみましょう。その中にはdata
ディクショナリがあります- ネストされた
tracecontext
ディクショナリを見るために、data
をより詳しく見てください tracecontext
ディクショナリ内には、traceparent
というキーと値のペアがありますtraceparent
キーと値のペアには、私たちが探しているトレース ID が含まれています-
で区切られた 4 つの値のグループがあります。トレース ID は 2 番目の文字グループです
- トレース ID をコピーして保存してください。 このワークショップの後のステップで必要になります

Splunk APM、Lambda関数とトレース、再び!
ログの外部でコンテキスト伝播の結果を確認するために、もう一度Splunk APM UIを参照します。
Splunk APM サービスマップで Lambda 関数を表示する
もう一度 APM で環境のサービスマップを確認してみましょう。
Splunk Observability Cloud で:
> 注意:トレースが Splunk APM に表示されるまで数分かかる場合があります。環境のリストにあなたの環境名が表示されるまで、ブラウザの更新ボタンを押してみてください
ワークショップの質問
- 今回は、伝播されたコンテキストによってリンクされた
producer-lambda
とconsumer-lambda
関数が見えるはずです!

トレース ID で Lambda トレースを調査する
次に、環境に関連するトレースをもう一度確認します。
- コンシューマー関数のログからコピーしたトレース ID を、Traces 下の
View Trace ID
検索ボックスに貼り付け、Go
をクリックします

メモ
トレース ID は、私たちが伝播したトレースコンテキストの一部でした。
最も一般的な 2 つの伝播規格について読むことができます:
- W3C
- B3
ワークショップの質問
私たちはどちらを使用していますか?
- 私たちの NodeJS 関数をサポートする Splunk Distribution of Opentelemetry JS は、デフォルトで
W3C
標準を使用しています
ワークショップの質問
ボーナス質問:W3C ヘッダーと B3 ヘッダーを混在させるとどうなりますか?

consumer-lambda
スパンをクリックしてください。
ワークショップの質問
あなたのメッセージからの属性を見つけることができますか?

クリーンアップ
いよいよワークショップの最後に来ました。後片付けをしましょう!
send_message
の停止
すべての AWS リソースを破棄する
Terraform は個々のリソースの状態をデプロイメントとして管理するのに優れています。定義に変更があっても、デプロイされたリソースを更新することもできます。しかし、一からやり直すために、リソースを破棄し、このワークショップの手動計装部分の一部として再デプロイします。
以下の手順に従ってリソースを破棄してください:
結論
Lambda Tracing ワークショップを終えたことをおめでとうございます!自動計装を手動のステップで補完して、producer-lambda
関数のコンテキストを Kinesis ストリーム内のレコードを介してconsumer-lambda
関数に送信する方法を見てきました。これにより、期待される分散トレースを構築し、Splunk APM で両方の関数間の関係をコンテキスト化することができました。

これで、2 つの異なる関数を手動でリンクしてトレースを構築することができます。これは、自動計装や第三者のシステムがコンテキスト伝播を標準でサポートしていない場合や、より関連性の高いトレース分析のためにカスタム属性をトレースに追加したい場合に役立ちます。