opentelemetry-js icon indicating copy to clipboard operation
opentelemetry-js copied to clipboard

Unable to access to trace information using opentelemetry-js SDK + aws lambda layer

Open jarpz opened this issue 1 year ago • 2 comments
trafficstars

What happened?

We are unable to access tracecontext like showed here: https://opentelemetry.io/docs/languages/js/propagation/#generic-example

We want tracecontext information to propagate manually to other services like SNS, SQS, KaFka.

Even we can see in Xray traces working correctly, due the example acces to other service like s3 and trace is visualized.

Steps to Reproduce

  • Use only OTEL API
  • Use aws lambda layer => "arn:aws:lambda:us-east-1:901920570463:layer:aws-otel-nodejs-amd64-ver-1-18-1:1"
  • Execute lambda code to access to trace info using Otel SDK API.

Expected Result

Access to current trace information using OTEL API SDK

Actual Result

Empty trace information from OTEL API SDK

Additional Details

IaC code

resource "aws_iam_role" "lambda_role" {
  name = "CreateFnRole"
  assume_role_policy = jsonencode(
    {
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Action" : "sts:AssumeRole",
          "Principal" : {
            "Service" : "lambda.amazonaws.com"
          },
          "Effect" : "Allow",
          "Sid" : ""
        }
      ]
    })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/AmazonS3FullAccess",
    "arn:aws:iam::aws:policy/AWSLambda_FullAccess",
    "arn:aws:iam::aws:policy/CloudWatchFullAccess",
    "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",
    "arn:aws:iam::aws:policy/AWSXrayFullAccess"
  ]

  inline_policy {
    name = "CreateFnPolicy"
    policy = jsonencode(
      {
        "Version" : "2012-10-17",
        "Statement" : [
          {
            "Action" : [
              "appconfig:*",
              "kms:*"
            ],
            "Resource" : "*",
            "Effect" : "Allow"
          }
        ]
      },
    )
  }
}

variable "service_name" {}
variable "env" {}

data "archive_file" "zip" {
  source_dir  = "../app/dist/functions/create"
  output_path = "../app/dist/create.zip"
  type        = "zip"
}

resource "aws_lambda_function" "create_fnc" {
  function_name = "${var.env}-${var.service_name}_create"

  runtime          = "nodejs18.x"
  filename         = data.archive_file.zip.output_path
  source_code_hash = data.archive_file.zip.output_base64sha256
  handler          = "handler.main"
  role             = aws_iam_role.lambda_role.arn
  memory_size      = 256
  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      AWS_LAMBDA_EXEC_WRAPPER : "/opt/otel-handler"
      SERVICE_NAME          = var.service_name
      ENV                   = var.env
      OTEL_TRACES_EXPORTER  = "oltp"
      OTEL_METRICS_EXPORTER = "oltp"
      OTEL_LOG_LEVEL        = "ERROR"
      OTEL_TRACES_SAMPLER   = "xray"
      OTEL_PROPAGATORS      = "tracecontext, baggage, xray-lambda"
      OTEL_SERVICE_NAME     = var.service_name
    }
  }

  layers = [
    "arn:aws:lambda:us-east-1:901920570463:layer:aws-otel-nodejs-amd64-ver-1-18-1:1"
  ]
}

output "create_fn_arn" {
  value = aws_lambda_function.create_fnc.arn
}

OpenTelemetry Setup Code

import "reflect-metadata"
import {Context} from 'aws-lambda';
import {Logger} from '@aws-lambda-powertools/logger';
import {LambdaInterface} from '@aws-lambda-powertools/commons/types';
import middy from '@middy/core';
import {ListBucketsCommand, S3Client} from '@aws-sdk/client-s3';
import {inject, injectable, singleton} from "tsyringe";
import api, {context, propagation} from '@opentelemetry/api';

const logger = new Logger();

const s3 = new S3Client({});

@injectable()
@singleton()
class Handler implements LambdaInterface {

    constructor() {
    }

    public async handler(_event: any, _context: Context): Promise<any> {
        logger.info(`==> currentTrace: ${currentSpan()} | ${JSON.stringify(_event)}`);

        const result = await s3.send(new ListBucketsCommand({}));

        logger.info(`context => ${JSON.stringify(api.context.active())} || ${JSON.stringify(currentContext())}`);
        if (api.context.active()) {
            const span = api.trace.getSpan(api.context.active());
            logger.info(`span => ${span}`);
            if (span) {
                logger.info(`QUE PASO??? ==> ${JSON.stringify(span)}`);
            }
        }

        return {
            result: 'hello world => ' + result.Buckets.length,
        };
    }
}

const main = middy()
        .handler(new Handler().handler)

module.exports = {main};

export function currentContext(): Record<string, any> {
    const output = {};

    propagation.inject(context.active(), output);

    return output;
}

export function currentSpan(): Record<string, string> | null {
    if (!api.context.active() || !api.trace.getSpan(api.context.active())) {
        return null;
    }

    let currentSpan = api.trace.getSpan(api.context.active());

    return {
        // @ts-ignore
        traceId: currentSpan.spanContext().traceId,
        // @ts-ignore
        spanId: currentSpan.spanContext().spanId,
        // @ts-ignore
        traceFlags: currentSpan.spanContext().traceFlags
    }
}

package.json

{
  "name": "hello_world",
  "version": "1.0.0",
  "description": "hello world sample for NodeJS",
  "main": "app.js",
  "repository": "https://github.com/aws/aws-sam-cli-app-templates/tree/master/nodejs18.x/hello-ts-pt",
  "author": "SAM CLI",
  "license": "MIT",
  "dependencies": {
    "@aws-lambda-powertools/commons": "^2.1.1",
    "@aws-lambda-powertools/logger": "^2.0.3",
    "@aws-lambda-powertools/metrics": "^2.0.3",
    "@aws-lambda-powertools/parameters": "^2.2.0",
    "@aws-lambda-powertools/tracer": "^2.0.3",
    "@aws-sdk/client-s3": "^3.592.0",
    "@middy/appconfig": "^5.4.0",
    "@opentelemetry/api": "^1.9.0",
    "esbuild": "^0.17.6",
    "reflect-metadata": "^0.1.13",
    "tiny-glob": "^0.2.9",
    "tsyringe": "4.8.0"
  },
  "scripts": {
    "unit": "jest",
    "lint": "eslint '*.ts' --quiet --fix",
    "compile": "tsc",
    "test": "npm run compile && npm run unit",
    "build": "esbuild src/functions/**/*.ts --bundle --minify --outdir=dist --outbase=src --sourcemap=inline --platform=node --target=node18.16.1 "
  },
  "devDependencies": {
    "@aws-sdk/client-appconfigdata": "^3.598.0",
    "@jest/globals": "^29.4.0",
    "@middy/core": "^5.4.0",
    "@middy/util": "^5.4.0",
    "@types/aws-lambda": "^8.10.109",
    "@types/jest": "^29.4.0",
    "@types/node": "^18.13.0",
    "@typescript-eslint/eslint-plugin": "^5.46.1",
    "@typescript-eslint/parser": "^5.46.1",
    "eslint": "^8.30.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "jest": "^29.3.1",
    "prettier": "^2.5.1",
    "ts-jest": "^29.0.5",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.4"
  }
}

Relevant log output

{
    "level": "INFO",
    "message": "==> 10 currentTrace: null | {\"go\":1}",
    "sampling_rate": 0,
    "service": "service_undefined",
    "timestamp": "2024-07-05T23:26:10.195Z",
    "xray_trace_id": "1-6688810f-a224dfbcdd26280c3fd8f8c6"
}

{
    "level": "INFO",
    "message": "context => {\"_currentContext\":{}} || {}",
    "sampling_rate": 0,
    "service": "service_undefined",
    "timestamp": "2024-07-05T23:26:10.358Z",
    "xray_trace_id": "1-6688810f-a224dfbcdd26280c3fd8f8c6"
}

jarpz avatar Jul 05 '24 23:07 jarpz