AWS Lambda関数の分散トレーシング

45 minutes   Author Guy-Francis Kono

このワークショップでは、AWS Lambda で実行される小規模なサーバーレスアプリケーションの分散トレースを構築し、AWS Kinesis を介してメッセージを produce および consume する方法を学びます。

まず、OpenTelemetry の自動計装がどのようにトレースをキャプチャし、選択した宛先にエクスポートするかを確認します。

次に、手動計装によってコンテキスト伝播を有効にする方法を見ていきます。

このワークショップのために、Splunk は AWS/EC2 上の Ubuntu Linux インスタンスを事前に構成しています。このインスタンスにアクセスするには、ワークショップインストラクターが提供する URL にアクセスしてください。

Last Modified 2025/05/29

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

セットアップ

手動計装されていないLambdaアプリケーション 手動計装されていないLambdaアプリケーション

前提条件

Observability ワークショップインスタンス

Observability ワークショップは、多くの場合、Splunk が提供する事前設定済みの Ubuntu EC2 インスタンス上で実施されます。

ワークショップのインストラクターから、割り当てられたワークショップインスタンスの認証情報が提供されます。

インスタンスには以下の環境変数が既に設定されているはずです:

  • ACCESS_TOKEN
  • REALM
    • これらはワークショップ用の Splunk Observability Cloud の Access TokenRealm です。
    • これらは OpenTelemetry Collector によって、データを正しい Splunk Observability Cloud 組織に転送するために使用されます。

また、Multipass を使用してローカルの Observability ワークショップインスタンスをデプロイすることもできます。

AWS Command Line Interface (awscli)

AWS Command Line Interface、またはawscliは、AWS リソースと対話するために使用される API です。このワークショップでは、特定のスクリプトがデプロイするリソースと対話するために使用されます。

Splunk が提供するワークショップインスタンスには、既に awscli がインストールされているはずです。

  • インスタンスに aws コマンドがインストールされているか、次のコマンドで確認します:

    which aws
    • 予想される出力は /usr/local/bin/aws です
  • インスタンスに aws コマンドがインストールされていない場合は、次のコマンドを実行します:

    sudo apt install awscli

Terraform

Terraform は、リソースを構成ファイルで定義することで、デプロイ、管理、破棄するための Infrastructure as Code(IaC)プラットフォームです。Terraform は HCL を使用してこれらのリソースを定義し、さまざまなプラットフォームやテクノロジのための複数のプロバイダーをサポートしています。

このワークショップでは、コマンドラインで Terraform を使用して、以下のリソースをデプロイします:

  1. AWS API Gateway
  2. Lambda 関数
  3. Kinesis Stream
  4. CloudWatch ロググループ
  5. S3 バケット
    • およびその他のサポートリソース

Splunk が提供するワークショップインスタンスには、既に terraform がインストールされているはずです。

  • インスタンスに terraform コマンドがインストールされているか確認します:

    which terraform
    • 予想される出力は /usr/local/bin/terraform です
  • インスタンスに terraform コマンドがインストールされていない場合は、以下の Terraform が推奨するインストールコマンドを実行してください:

    wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
    
    echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
    
    sudo apt update && sudo apt install terraform

ワークショップディレクトリ (o11y-lambda-workshop)

ワークショップディレクトリ o11y-lambda-workshop は、今日使用する例の Lambda ベースのアプリケーションの自動計装と手動計装の両方を完了するための、すべての設定ファイルとスクリプトを含むリポジトリです。

  • ホームディレクトリにワークショップディレクトリがあることを確認します:

    cd && ls
    • 予想される出力には o11y-lambda-workshop が含まれるはずです
  • o11y-lambda-workshop ディレクトリがホームディレクトリにない場合は、次のコマンドでクローンします:

git clone https://github.com/gkono-splunk/o11y-lambda-workshop.git

AWS & Terraform 変数

AWS

AWS の CLI では、サービスによってデプロイされたリソースにアクセスし管理するための認証情報が必要です。このワークショップでは、Terraform と Python スクリプトの両方がタスクを実行するためにこれらの変数を必要とします。

  • このワークショップのために awscliaccess key IDsecret access key および region で構成します:

    aws configure
    • このコマンドは以下のようなプロンプトを表示するはずです:

      AWS Access Key ID [None]: XXXXXXXXXXXXXXXX
      AWS Secret Acces Key [None]: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      Default region name [None]: us-east-1
      Default outoput format [None]:
  • インスタンスで awscli が設定されていない場合は、次のコマンドを実行し、インストラクターから提供される値を入力してください。

    aws configure

Terraform

Terraform では、機密情報や動的データを.tf 設定ファイルにハードコーディングさせない、またはそれらの値をリソース定義全体で再利用できるようにするため、変数の受け渡しをサポートしています。

このワークショップでは、OpenTelemetry Lambda layer の適切な値で Lambda 関数をデプロイするため、Splunk Observability Cloud の取り込み値のため、そして環境とリソースを独自で即座に認識できるようにするための変数を Terraform で必要とします。

Terraform 変数(variable)は以下の方法で定義されます:

  • 変数を main.tf ファイルまたは variables.tf に定義する
  • 以下のいずれかの方法で変数の値を設定する:
    • ホストレベルで環境変数を設定し、その定義と同じ変数名を使用して、接頭辞として TF_VAR をつける
    • terraform.tfvars ファイルに変数の値を設定する
    • terraform apply 実行時に引数として値を渡す

このワークショップでは、variables.tfterraform.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
    • これは、自動計装と手動計装の両方の部分で同じ値を使用するためです

ファイル権限

他のすべてのファイルはそのままでよいですが、automanualの両方にあるsend_message.pyスクリプトは、ワークショップの一部として実行する必要があります。そのため、期待通りに実行するには、適切な権限が必要です。以下の手順に従って設定してください。

  • まず、o11y-lambda-workshopディレクトリにいることを確認します:

    cd ~/o11y-lambda-workshop
  • 次に、以下のコマンドを実行してsend_message.pyスクリプトに実行権限を設定します:

    sudo chmod 755 auto/send_message.py manual/send_message.py

これで前提条件が整いましたので、ワークショップを始めることができます!

Last Modified 2025/05/29

自動計装

ワークショップの最初の部分では、OpenTelemetry による自動計装がどのようにして OpenTelemetry Collector に関数がどの言語で書かれているかを自動検出させ、それらの関数のトレースの取得を開始させるかを示します。

自動計装ワークショップディレクトリとコンテンツ

まず、o11y-lambda-workshop/autoディレクトリとそのファイルの一部を見てみましょう。ここにはワークショップの自動計装部分のすべてのコンテンツがあります。

auto ディレクトリ

  • 以下のコマンドを実行して o11y-lambda-workshop/auto ディレクトリに移動します:

    cd ~/o11y-lambda-workshop/auto
  • このディレクトリの内容を確認します:

    ls
    • 出力には以下のファイルとディレクトリが含まれるはずです:

      handler             outputs.tf          terraform.tf        variables.tf
      main.tf             send_message.py     terraform.tfvars
    • 出力には以下のファイルとディレクトリが含まれるはずです:

      get_logs.py    main.tf       send_message.py
      handler        outputs.tf    terraform.tf

main.tf ファイル

  • main.tf ファイルをより詳しく見てみましょう:

    cat 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関数のコードを見てみましょう:

  • 以下のコマンドを実行してproducer.mjsファイルの内容を表示します:

    cat ~/o11y-lambda-workshop/auto/handler/producer.mjs
    • この NodeJS モジュールにはプロデューサー関数のコードが含まれています。
    • 基本的に、この関数はメッセージを受け取り、そのメッセージを対象の Kinesis ストリームにレコードとして配置します

Lambda 関数のデプロイとトレースデータの生成

autoディレクトリの内容に慣れたところで、ワークショップ用のリソースをデプロイし、Lambda 関数からトレースデータを生成していきます。

autoディレクトリで Terraform を初期化する

main.tfファイルで定義されたリソースをデプロイするには、まず Terraform がそのファイルと同じフォルダで初期化されていることを確認する必要があります。

  • auto ディレクトリにいることを確認します:

    pwd
    • 予想される出力は ~/o11y-lambda-workshop/auto です
  • auto ディレクトリにいない場合は、次のコマンドを実行します:

    cd ~/o11y-lambda-workshop/auto
  • 次のコマンドを実行して、このディレクトリで Terraform を初期化します

    terraform init
    • このコマンドは同じフォルダにいくつかの要素を作成します:
      • .terraform.lock.hcl ファイル:リソースを提供するために使用するプロバイダーを記録します
      • .terraform ディレクトリ:プロバイダーの構成を保存します
    • 上記のファイルに加えて、apply サブコマンドを使用して terraform を実行すると、デプロイされたリソースの状態を追跡するために terraform.tfstate ファイルが作成されます。
    • これらにより、Terraform は auto ディレクトリの main.tf ファイル内で定義されたとおりに、リソースの作成、状態、破棄を管理できます

Lambda 関数とその他の AWS リソースをデプロイする

このディレクトリで Terraform を初期化したら、リソースのデプロイに進むことができます。

  • まず、terraform plan コマンドを実行して、Terraform が問題なくリソースを作成できることを確認します。

    terraform plan
    • これにより、リソースをデプロイするプランといくつかのデータが出力され、意図したとおりに動作することを確認できます。
    • プランに表示される値の一部は、作成後に判明するか、セキュリティ上の理由でマスクされていることに注意してください。
  • 次に、terraform apply コマンドを実行して、main.tf ファイルから Lambda 関数とその他のサポートリソースをデプロイします:

    terraform apply
    • Enter a value: プロンプトが表示されたら yes と応答します

    • これにより、以下のような出力が得られます:

      Outputs:
      
      base_url = "https://______.amazonaws.com/serverless_stage/producer"
      consumer_function_name = "_____-consumer"
      consumer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-consumer"
      consumer_log_group_name = "/aws/lambda/______-consumer"
      environment = "______-lambda-shop"
      lambda_bucket_name = "lambda-shop-______-______"
      producer_function_name = "______-producer"
      producer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-producer"
      producer_log_group_name = "/aws/lambda/______-producer"
      • Terraform 出力は outputs.tf ファイルで定義されています。
      • これらの出力は、ワークショップの他の部分でもプログラム的に使用されます。

producer-lambda URL (base_url) にトラフィックを送信する

デプロイした Lambda 関数からトレースを取得し始めるには、トラフィックを生成する必要があります。producer-lambda関数のエンドポイントにメッセージを送信し、それを Kinesis ストリームにレコードとして配置し、その後consumer-lambda関数によってストリームから取得されるようにします。

  • auto ディレクトリにいることを確認します:

    pwd
    • 予想される出力は ~/o11y-lambda-workshop/auto です
  • auto ディレクトリにいない場合は、次のコマンドを実行します

    cd ~/o11y-lambda-workshop/auto

send_message.py スクリプトは、コマンドラインで入力を受け取り、JSON ディクショナリに追加し、while ループの一部として producer-lambda 関数のエンドポイントに繰り返し送信する Python スクリプトです。

  • Run the send_message.py script as a background process

    • --name--superpower 引数が必要です
    nohup ./send_message.py --name CHANGEME --superpower CHANGEME &
    • メッセージが成功した場合は、以下のような出力が表示されるはずです

      [1] 79829
      user@host manual % appending output to nohup.out
      • ここで重要な情報は 2 つあります:
        • 1 行目のプロセス ID(この例では 79829)、および
        • appending output to nohup.out メッセージ
      • nohup コマンドはスクリプトがバックグラウンドに送られた時に切断されないようにします。また、コマンドからの curl 出力を、現在いるフォルダと同じフォルダにある nohup.out ファイルにキャプチャします。
      • & はシェルプロセスにこのプロセスをバックグラウンドで実行するよう指示し、シェルが他のコマンドを実行できるようにします。
  • 次に、response.logs ファイルの内容を確認して、producer-lambda エンドポイントへのリクエストが成功したことを確認します:

    cat response.logs
    • メッセージが成功していれば、画面に印刷された行の中に次の出力が表示されるはずです:
    {"message": "Message placed in the Event Stream: {prefix}-lambda_stream"}
    • 失敗した場合は、次のように表示されます:
    {"message": "Internal server error"}
重要

この場合は、ワークショップ進行役の一人に支援を求めてください。

Lambda 関数のログを表示する

次に、Lambda 関数のログを確認しましょう。

  • producer-lambda ログを表示するには、producer.logs ファイルを確認します:

    cat producer.logs
  • consumer-lambda ログを表示するには、consumer.logs ファイルを確認します:

    cat consumer.logs

ログを注意深く調べてください。

ワークショップの質問
  • OpenTelemetry が読み込まれているのが見えますか?splunk-extension-wrapperのある行に注目してください
      • splunk-extension-wrapperが読み込まれているのを見るためにhead -n 50 producer.logsまたはhead -n 50 consumer.logsの実行を検討してください。
Last Modified 2025/05/29

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 で:

  • 左側のメインメニューからAPMボタンをクリックします。これにより Splunk APM 概要に移動します。

  • Environment:ドロップダウンからあなたの APM 環境を選択します。

    • APM 環境はPREFIX-lambda-shop形式になっているはずです。PREFIXは前提条件セクションで設定した環境変数から取得されます
メモ

トレースが Splunk APM に表示されるまで数分かかる場合があります。環境のリストにあなたの環境名が表示されるまで、ブラウザの更新ボタンを押してみてください

Splunk APM, Environment Name Splunk APM, Environment Name

環境のサービスマップを表示する

Environment ドロップダウンから環境名を選択したら、Lambda 関数のサービスマップを確認できます。

  • APM 概要ページの右側にあるService Mapボタンをクリックします。これによりサービスマップビューに移動します。

Splunk APM、サービスマップボタン Splunk APM、サービスマップボタン

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

Splunk APM、サービスマップ Splunk APM、サービスマップ

ワークショップの質問

あなたのconsumer-lambda関数はどうなっていますか?

Lambda 関数からのトレースを調査する

  • Tracesボタンをクリックしてトレースアナライザーを表示します。

Splunk APM、トレースボタン Splunk APM、トレースボタン

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

Splunk APM、トレースアナライザー Splunk APM、トレースアナライザー

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

Splunk APM、トレースとスパン Splunk APM、トレースとスパン

producer-lambda関数が Kinesis ストリームにレコードを配置しているのが確認できます。しかし、consumer-lambda関数のアクションが見当たりません!

これはトレースコンテキストが伝播されていないためです。このワークショップの時点では、Kinesis サービスはトレースコンテキスト伝播をすぐには対応していません。分散トレースは Kinesis サービスで止まっており、そのコンテキストがストリームを通じて自動的に伝播されないため、それ以上先を見ることができません。

少なくとも、今はまだ…

次のセクションでこの問題にどう対処するか見ていきましょう。しかしその前に、後片付けをしましょう!

クリーンアップ

この自動計装演習の一部としてデプロイしたリソースはクリーンアップする必要があります。同様に、producer-lambdaエンドポイントに対してトラフィックを生成していたスクリプトも、まだ実行中であれば停止する必要があります。以下の手順に従ってクリーンアップを行ってください。

send_messageの停止

  • send_message.pyスクリプトがまだ実行中の場合は、次のコマンドで停止します:

    fg
    • これによりバックグラウンドプロセスがフォアグラウンドに移動します。
    • 次に[CONTROL-C]を押してプロセスを終了できます。

全ての AWS リソースを破棄する

Terraform は個々のリソースの状態をデプロイメントとして管理するのに優れています。定義に変更があっても、デプロイされたリソースを更新することもできます。しかし、一からやり直すために、リソースを破棄し、このワークショップの手動計装部分の一部として再デプロイします。

以下の手順に従ってリソースを破棄してください:

  • autoディレクトリにいることを確認します:

    pwd
    • 期待される出力は ~/o11y-lambda-workshop/auto です
  • autoディレクトリにいない場合は、以下のコマンドを実行します:

    cd ~/o11y-lambda-workshop/auto
  • 先ほどデプロイした Lambda 関数とその他の AWS リソースを破棄します:

    terraform destroy
    • Enter a value:プロンプトが表示されたらyesと応答します
    • これによりリソースが破棄され、クリーンな環境が残ります

このプロセスにより、私たちの活動の結果として作成されたファイルとディレクトリは残ります。それらについては心配する必要はありません。

Last Modified 2025/05/29

手動計装

ワークショップの第 2 部では、OpenTelemetry による手動計装が計測データ収集を強化する方法を実演することに焦点を当てます。より具体的には、今回のケースでは、producer-lambda関数からconsumer-lambda関数にトレースコンテキストデータを伝播させることができるようになります。これにより、現在は自動コンテキスト伝播をサポートしていない Kinesis ストリームを介しても、2 つの関数間の関係を見ることができるようになります。

手動計装ワークショップディレクトリとコンテンツ

再度、作業ディレクトリとそのファイルの一部を確認することから始めます。今回は o11y-lambda-workshop/manual ディレクトリです。ここにはワークショップの手動計装部分のすべてのコンテンツがあります。

manual ディレクトリ

  • 以下のコマンドを実行して o11y-lambda-workshop/manual ディレクトリに移動します:

    cd ~/o11y-lambda-workshop/manual
  • ls コマンドでこのディレクトリの内容を確認します:

    ls
    • 出力には以下のファイルとディレクトリが含まれるはずです:

      handler             outputs.tf          terraform.tf        variables.tf
      main.tf             send_message.py     terraform.tfvars
ワークショップの質問

このディレクトリと最初に始めた auto ディレクトリに何か違いがありますか?

automanual のファイルを比較する

見た目が同じように見えるこれらのファイルが実際に同じかどうか確認しましょう。

  • automanual ディレクトリの 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";
    • プロデューサー関数でコンテキストを伝播するために、@opentelemetry/api から次のオブジェクトをインポートしています:
      • context
      • propagation
      • trace
  • 最後に、consumer.mjs ファイルを比較します:

    diff ~/o11y-lambda-workshop/auto/handler/consumer.mjs ~/o11y-lambda-workshop/manual/handler/consumer.mjs
    • ここにもいくつかの注目すべき違いがあります。より詳しく見てみましょう:

      cat handler/consumer.mjs
      • このファイルでは、次の @opentelemetry/api オブジェクトをインポートしています:
        • propagation
        • trace
        • ROOT_CONTEXT
      • これらを使用して、プロデューサー関数から伝播されたトレースコンテキストを抽出します
      • その後、抽出したトレースコンテキストに namesuperpower に基づいた新しいスパン属性を追加します

プロデューサー関数からのトレースコンテキスト伝播

以下のコードはプロデューサー関数内で次のステップを実行します:

  1. このトレース用のトレーサーを取得する
  2. コンテキストキャリアオブジェクトを初期化する
  3. アクティブスパンのコンテキストをキャリアオブジェクトに注入する
  4. 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();

コンシューマー関数でのトレースコンテキスト抽出

以下のコードはコンシューマー関数内で次のステップを実行します:

  1. producer-lambdaから取得したコンテキストをキャリアオブジェクトに抽出する
  2. 現在のコンテキストからトレーサーを抽出する
  3. 抽出したコンテキスト内でトレーサーを使用して新しいスパンを開始する
  4. ボーナス:メッセージからの値を含むカスタム属性など、追加の属性をスパンに追加する!
  5. 完了したら、スパンを終了する
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();

これでどのような違いが生まれるか見てみましょう!

Last Modified 2025/05/13

Lambda関数のデプロイとトレースデータの生成

トレースデータを収集したい関数やサービスに手動計装を適用する方法がわかったので、Lambda 関数を再度デプロイして、producer-lambdaエンドポイントに対するトラフィックを生成していきましょう。

manual ディレクトリで Terraform を初期化する

新しいディレクトリにいるので、ここでもう一度 Terraform を初期化する必要があります。

  • manual ディレクトリにいることを確認します:

    pwd
    • 予想される出力は ~/o11y-lambda-workshop/manual です
  • manual ディレクトリにいない場合は、次のコマンドを実行します:

    cd ~/o11y-lambda-workshop/manual
  • 次のコマンドを実行して、このディレクトリで Terraform を初期化します:

    terraform init

Lambda 関数とその他の AWS リソースをデプロイする

それでは、これらのリソースを再度デプロイしましょう!

  • 問題がないことを確認するために、terraform plan コマンドを実行します。

    terraform plan
  • 続いて、terraform apply コマンドを使用して main.tf ファイルから Lambda 関数とその他のサポートリソースをデプロイします:

    terraform apply
    • Enter a value: プロンプトが表示されたら yes と応答します

    • これにより、以下のような出力が得られます:

      Outputs:
      
      base_url = "https://______.amazonaws.com/serverless_stage/producer"
      consumer_function_name = "_____-consumer"
      consumer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-consumer"
      consumer_log_group_name = "/aws/lambda/______-consumer"
      environment = "______-lambda-shop"
      lambda_bucket_name = "lambda-shop-______-______"
      producer_function_name = "______-producer"
      producer_log_group_arn = "arn:aws:logs:us-east-1:############:log-group:/aws/lambda/______-producer"
      producer_log_group_name = "/aws/lambda/______-producer"

見ての通り、base_url の最初の部分とログループ ARN 以外は、このワークショップの自動計装部分をこの同じ時点まで実行したときと出力は概ね同じはずです。

producer-lambda エンドポイント (base_url) にトラフィックを送信する

もう一度、namesuperpower をメッセージとしてエンドポイントに送信します。これはトレースコンテキストとともに、Kinesis ストリーム内のレコードに追加されます。

  • manual ディレクトリにいることを確認します:

    pwd
    • 予想される出力は ~/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エンドポイントへの呼び出しが成功しているか確認します:

    cat response.logs
    • メッセージが成功していれば、画面に表示される行の中に次の出力が表示されるはずです:

      {"message": "Message placed in the Event Stream: hostname-eventStream"}
    • 失敗した場合は、次のように表示されます:

      {"message": "Internal server error"}
重要

これが発生した場合は、ワークショップ進行役の一人に支援を求めてください。

Lambda 関数のログの確認

ログがどのようになっているか見てみましょう。

  • producer.logs ファイルを確認します:

    cat producer.logs
  • そして consumer.logs ファイルを確認します:

    cat consumer.logs

ログを注意深く調べてください。

ワークショップの質問

違いに気づきましたか?

consumer-lambda ログからのトレース ID のコピー

今回は、consumer-lambda のロググループが、我々が伝播したtracecontextとともに、メッセージをrecordとしてログに記録しているのが確認できます。

トレース ID をコピーするには:

  • Kinesis Messageログの 1 つを見てみましょう。その中にはdataディクショナリがあります
  • ネストされたtracecontextディクショナリを見るために、dataをより詳しく見てください
  • tracecontextディクショナリ内には、traceparentというキーと値のペアがあります
  • traceparentキーと値のペアには、私たちが探しているトレース ID が含まれています
    • -で区切られた 4 つの値のグループがあります。トレース ID は 2 番目の文字グループです
  • トレース ID をコピーして保存してください。 このワークショップの後のステップで必要になります

Lambda Consumer Logs、手動計装 Lambda Consumer Logs、手動計装

Last Modified 2025/05/29

Splunk APM、Lambda関数とトレース、再び!

ログの外部でコンテキスト伝播の結果を確認するために、もう一度Splunk APM UIを参照します。

Splunk APM サービスマップで Lambda 関数を表示する

もう一度 APM で環境のサービスマップを確認してみましょう。

Splunk Observability Cloud で:

  • メインメニューのAPMボタンをクリックします。

  • Environment:ドロップダウンからあなたの APM 環境を選択します。

  • APM 概要ページの右側にあるService Mapボタンをクリックします。これによりサービスマップビューに移動します。

> 注意:トレースが Splunk APM に表示されるまで数分かかる場合があります。環境のリストにあなたの環境名が表示されるまで、ブラウザの更新ボタンを押してみてください
ワークショップの質問

違いに気づきましたか?

  • 今回は、伝播されたコンテキストによってリンクされたproducer-lambdaconsumer-lambda関数が見えるはずです!

Splunk APM、サービスマップ Splunk APM、サービスマップ

トレース ID で Lambda トレースを調査する

次に、環境に関連するトレースをもう一度確認します。

  • コンシューマー関数のログからコピーしたトレース ID を、Traces 下のView Trace ID検索ボックスに貼り付け、Goをクリックします

Splunk APM、トレースボタン Splunk APM、トレースボタン

メモ

トレース ID は、私たちが伝播したトレースコンテキストの一部でした。

最も一般的な 2 つの伝播規格について読むことができます:

  1. W3C
  2. B3
ワークショップの質問

私たちはどちらを使用していますか?

  • 私たちの NodeJS 関数をサポートする Splunk Distribution of Opentelemetry JS は、デフォルトW3C標準を使用しています
ワークショップの質問

ボーナス質問:W3C ヘッダーと B3 ヘッダーを混在させるとどうなりますか?

Splunk APM、IDによるトレース Splunk APM、IDによるトレース

consumer-lambdaスパンをクリックしてください。

ワークショップの質問

あなたのメッセージからの属性を見つけることができますか?

Splunk APM、スパンタグ Splunk APM、スパンタグ

クリーンアップ

いよいよワークショップの最後に来ました。後片付けをしましょう!

send_messageの停止

  • send_message.pyスクリプトがまだ実行中の場合は、次のコマンドで停止します:

    fg
    • これによりバックグラウンドプロセスがフォアグラウンドに移動します。
    • 次に[CONTROL-C]を押してプロセスを終了できます。

すべての AWS リソースを破棄する

Terraform は個々のリソースの状態をデプロイメントとして管理するのに優れています。定義に変更があっても、デプロイされたリソースを更新することもできます。しかし、一からやり直すために、リソースを破棄し、このワークショップの手動計装部分の一部として再デプロイします。

以下の手順に従ってリソースを破棄してください:

  • manualディレクトリにいることを確認します:

    pwd
    • 予想される出力は ~/o11y-lambda-workshop/manual です
  • manualディレクトリにいない場合は、次のコマンドを実行します:

    cd ~/o11y-lambda-workshop/manual
  • 以前にデプロイした Lambda 関数とその他の AWS リソースを破棄します:

    terraform destroy
    • Enter a value:プロンプトが表示されたらyesと応答します
    • これにより、リソースが破棄され、クリーンな環境が残ります
Last Modified 2025/05/13

結論

Lambda Tracing ワークショップを終えたことをおめでとうございます!自動計装を手動のステップで補完して、producer-lambda関数のコンテキストを Kinesis ストリーム内のレコードを介してconsumer-lambda関数に送信する方法を見てきました。これにより、期待される分散トレースを構築し、Splunk APM で両方の関数間の関係をコンテキスト化することができました。

完全に計装されたLambdaアプリケーション 完全に計装されたLambdaアプリケーション

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