From f563ced12157d92fab6c274f39ab93959bdac447 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Fri, 8 Aug 2025 15:14:15 -0400 Subject: [PATCH 01/15] feat: upgrade to OpenTelemetry v2.x with cross-platform build support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update package.json to OpenTelemetry v2.x dependencies (47+ packages) - Fix TypeScript compilation errors with global.d.ts declarations - Add automatic architecture detection for arm64/amd64 builds - Update import paths for v2.x compatibility (otlp-proto → otlp-http) - Add webpack TypeScript configuration with test file exclusions - Add install-externals.sh for import-in-the-middle ESM instrumentation - Update opentelemetry-lambda submodule to commit 1fca858 (v2.x) Resolves build failures and enables cross-platform Lambda layer generation. Tested: make build-nodejs now builds successfully on arm64/amd64. --- collector/build.sh | 19 ++++ nodejs/build.sh | 39 ++++++- nodejs/packages/layer/install-externals.sh | 25 +++++ nodejs/packages/layer/package.json | 110 ++++++++++++++------ nodejs/packages/layer/src/global.d.ts | 11 ++ nodejs/packages/layer/src/wrapper.ts | 2 +- nodejs/packages/layer/tsconfig.webpack.json | 14 +++ opentelemetry-lambda | 2 +- 8 files changed, 184 insertions(+), 38 deletions(-) create mode 100755 nodejs/packages/layer/install-externals.sh create mode 100644 nodejs/packages/layer/src/global.d.ts create mode 100644 nodejs/packages/layer/tsconfig.webpack.json diff --git a/collector/build.sh b/collector/build.sh index 7ea6b9c..db1d2c1 100755 --- a/collector/build.sh +++ b/collector/build.sh @@ -15,6 +15,25 @@ popd || exit # Add config.yaml +# Use ARCHITECTURE from environment, default to host architecture if not set +if [ -z "$ARCHITECTURE" ]; then + HOST_ARCH=$(uname -m) + case $HOST_ARCH in + x86_64) + GOARCH="amd64" + ;; + arm64|aarch64) + GOARCH="arm64" + ;; + *) + echo "Unsupported architecture: $HOST_ARCH" + exit 1 + ;; + esac +else + GOARCH="$ARCHITECTURE" +fi + cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${GOARCH}.zip . unzip -qo opentelemetry-collector-layer-${GOARCH}.zip rm opentelemetry-collector-layer-${GOARCH}.zip diff --git a/nodejs/build.sh b/nodejs/build.sh index 70c2872..01ab730 100755 --- a/nodejs/build.sh +++ b/nodejs/build.sh @@ -1,5 +1,25 @@ #!/bin/bash +# Detect host architecture +ARCH=$(uname -m) +case $ARCH in + x86_64) + ARCHITECTURE="amd64" + ;; + arm64|aarch64) + ARCHITECTURE="arm64" + ;; + *) + echo "Unsupported architecture: $ARCH" + exit 1 + ;; +esac + +echo "Building for architecture: $ARCHITECTURE" + +# Export for use in collector build +export ARCHITECTURE + # Build collector pushd ../collector || exit @@ -7,23 +27,34 @@ pushd ../collector || exit popd || exit # Copy wrapper.ts - cp ./packages/layer/src/wrapper.ts ../opentelemetry-lambda/nodejs/packages/layer/src/wrapper.ts # Copy package.json - cp ./packages/layer/package.json ../opentelemetry-lambda/nodejs/packages/layer/package.json -# Build nodejs sdk +# Copy global.d.ts with type declarations +cp ./packages/layer/src/global.d.ts ../opentelemetry-lambda/nodejs/packages/layer/src/global.d.ts + +# Copy other necessary configuration files +cp ./packages/layer/webpack.config.js ../opentelemetry-lambda/nodejs/packages/layer/webpack.config.js 2>/dev/null || true +cp ./packages/layer/tsconfig.webpack.json ../opentelemetry-lambda/nodejs/packages/layer/tsconfig.webpack.json 2>/dev/null || true +cp ./packages/layer/install-externals.sh ../opentelemetry-lambda/nodejs/packages/layer/install-externals.sh 2>/dev/null || true +chmod +x ../opentelemetry-lambda/nodejs/packages/layer/install-externals.sh 2>/dev/null || true +# Build nodejs sdk pushd ../opentelemetry-lambda/nodejs || exit npm install popd || exit +# Build the layer specifically +pushd ../opentelemetry-lambda/nodejs/packages/layer || exit +npm run build +popd || exit + # Combine collector extension with nodejs sdk ## Copy and extract all files mkdir combine -cp ../collector/collector-layer.zip ./combine +cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${ARCHITECTURE}.zip ./combine/collector-layer.zip cp ../opentelemetry-lambda/nodejs/packages/layer/build/layer.zip ./combine unzip -qo combine/collector-layer.zip -d combine diff --git a/nodejs/packages/layer/install-externals.sh b/nodejs/packages/layer/install-externals.sh new file mode 100755 index 0000000..47440b5 --- /dev/null +++ b/nodejs/packages/layer/install-externals.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -euf -o pipefail + +rm -rf ./build/workspace/node_modules + +# Space separated list of external NPM packages +EXTERNAL_PACKAGES=( "import-in-the-middle" ) + +for EXTERNAL_PACKAGE in "${EXTERNAL_PACKAGES[@]}" +do + echo "Installing external package $EXTERNAL_PACKAGE ..." + + PACKAGE_VERSION=$(npm query "#$EXTERNAL_PACKAGE" \ + | grep version \ + | head -1 \ + | awk -F: '{ print $2 }' \ + | sed 's/[",]//g') + + echo "Resolved version of the external package $EXTERNAL_PACKAGE: $PACKAGE_VERSION" + + npm install "$EXTERNAL_PACKAGE@$PACKAGE_VERSION" --prefix ./build/workspace --production --ignore-scripts + + echo "Installed external package $EXTERNAL_PACKAGE" +done diff --git a/nodejs/packages/layer/package.json b/nodejs/packages/layer/package.json index ca290bd..b9bb79a 100644 --- a/nodejs/packages/layer/package.json +++ b/nodejs/packages/layer/package.json @@ -5,12 +5,22 @@ "description": "Layer including OpenTelemetry SDK for use with AWS Lambda.", "repository": "open-telemetry/opentelemetry-lambda", "scripts": { + "build": "npm run clean && npm run compile && npm run install-externals && npm run package", "clean": "rimraf build/*", - "lint": "eslint . --ext .ts", - "lint:fix": "eslint . --ext .ts --fix", - "prepare": "npm run compile", - "compile": "tsc -p .", - "postcompile": "copyfiles 'node_modules/**' build/workspace/nodejs && copyfiles -f 'scripts/*' build/workspace && copyfiles -f 'build/src/*' build/workspace && cd build/workspace && bestzip ../layer.zip *" + "compile:tsc": "tsc --build tsconfig.json", + "compile:webpack": "webpack", + "compile": "npm run compile:webpack", + "copy-js-files": "copyfiles -f 'src/**/*.js' build/workspace && copyfiles 'test/**/*.js' build", + "copy-esm-files": "copyfiles -f 'src/**/*.mjs' build/workspace && copyfiles 'test/**/*.mjs' build", + "install-externals": "./install-externals.sh", + "lint": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .ts", + "lint:fix": "ESLINT_USE_FLAT_CONFIG=false eslint . --ext .ts --fix", + "package": "cd build/workspace && bestzip ../layer.zip *", + "postcompile": "npm run copy-js-files && npm run copy-esm-files && copyfiles -f 'scripts/*' build/workspace && copyfiles -f 'build/src/*.js' build/workspace && copyfiles -f 'build/src/*.mjs' build/workspace", + "pretest": "npm run compile:tsc", + "test:cjs": "mocha 'test/**/*.spec.ts' --exclude 'test/**/*.spec.mjs' --timeout 10000", + "test:esm": "mocha 'test/**/*.spec.mjs' --exclude 'test/**/*.spec.ts' --timeout 10000", + "test": "npm run test:cjs && npm run test:esm" }, "keywords": [ "opentelemetry", @@ -23,33 +33,69 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14.0.0" + "node": ">=18.19.0" }, "dependencies": { - "@opentelemetry/api": "1.6.0", - "@opentelemetry/exporter-trace-otlp-proto": "0.44.0", - "@opentelemetry/exporter-metrics-otlp-proto": "0.44.0", - "@opentelemetry/instrumentation": "0.44.0", - "@opentelemetry/instrumentation-aws-lambda": "0.37.1", - "@opentelemetry/instrumentation-aws-sdk": "0.36.1", - "@opentelemetry/instrumentation-dns": "0.32.3", - "@opentelemetry/instrumentation-express": "0.33.2", - "@opentelemetry/instrumentation-graphql": "0.35.2", - "@opentelemetry/instrumentation-grpc": "0.44.0", - "@opentelemetry/instrumentation-hapi": "0.33.1", - "@opentelemetry/instrumentation-http": "0.44.0", - "@opentelemetry/instrumentation-ioredis": "0.35.2", - "@opentelemetry/instrumentation-koa": "0.36.1", - "@opentelemetry/instrumentation-mongodb": "0.37.1", - "@opentelemetry/instrumentation-mysql": "0.34.2", - "@opentelemetry/instrumentation-net": "0.32.2", - "@opentelemetry/instrumentation-pg": "0.36.2", - "@opentelemetry/instrumentation-redis": "0.35.2", - "@opentelemetry/propagator-aws-xray": "1.3.0", - "@opentelemetry/resource-detector-aws": "1.3.2", - "@opentelemetry/resources": "1.17.1", - "@opentelemetry/sdk-metrics": "1.17.1", - "@opentelemetry/sdk-trace-base": "1.17.1", - "@opentelemetry/sdk-trace-node": "1.17.1" - } + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/api-logs": "^0.203.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.203.0", + "@opentelemetry/exporter-metrics-otlp-http": "^0.203.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.203.0", + "@opentelemetry/instrumentation": "^0.203.0", + "@opentelemetry/instrumentation-amqplib": "^0.50.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.54.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.56.0", + "@opentelemetry/instrumentation-bunyan": "^0.49.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.49.0", + "@opentelemetry/instrumentation-connect": "^0.47.0", + "@opentelemetry/instrumentation-dataloader": "^0.21.0", + "@opentelemetry/instrumentation-dns": "^0.47.0", + "@opentelemetry/instrumentation-express": "^0.52.0", + "@opentelemetry/instrumentation-fs": "^0.23.0", + "@opentelemetry/instrumentation-graphql": "^0.51.0", + "@opentelemetry/instrumentation-grpc": "^0.203.0", + "@opentelemetry/instrumentation-hapi": "^0.50.0", + "@opentelemetry/instrumentation-http": "^0.203.0", + "@opentelemetry/instrumentation-ioredis": "^0.51.0", + "@opentelemetry/instrumentation-kafkajs": "^0.12.0", + "@opentelemetry/instrumentation-knex": "^0.48.0", + "@opentelemetry/instrumentation-koa": "^0.51.0", + "@opentelemetry/instrumentation-memcached": "^0.47.0", + "@opentelemetry/instrumentation-mongodb": "^0.56.0", + "@opentelemetry/instrumentation-mongoose": "^0.50.0", + "@opentelemetry/instrumentation-mysql": "^0.49.0", + "@opentelemetry/instrumentation-mysql2": "^0.49.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.49.0", + "@opentelemetry/instrumentation-net": "^0.47.0", + "@opentelemetry/instrumentation-pg": "^0.55.0", + "@opentelemetry/instrumentation-pino": "^0.50.0", + "@opentelemetry/instrumentation-redis": "^0.51.0", + "@opentelemetry/instrumentation-restify": "^0.49.0", + "@opentelemetry/instrumentation-socket.io": "^0.50.0", + "@opentelemetry/instrumentation-undici": "^0.14.0", + "@opentelemetry/instrumentation-winston": "^0.48.0", + "@opentelemetry/propagator-aws-xray": "^2.0.0", + "@opentelemetry/propagator-aws-xray-lambda": "^0.55.0", + "@opentelemetry/resource-detector-aws": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-logs": "^0.203.0", + "@opentelemetry/sdk-metrics": "^2.0.0", + "@opentelemetry/sdk-trace-node": "^2.0.0" + }, + "devDependencies": { + "@types/mocha": "^10.0.9", + "@types/sinon": "^17.0.4", + "bestzip": "^2.2.1", + "copyfiles": "^2.4.1", + "mocha": "^11.0.1", + "rimraf": "^6.0.1", + "sinon": "^21.0.0", + "ts-loader": "^9.5.2", + "ts-node": "^10.9.2", + "webpack": "^5.98.0", + "webpack-cli": "^6.0.1", + "webpack-node-externals": "^3.0.0" + }, + "sideEffects": false } diff --git a/nodejs/packages/layer/src/global.d.ts b/nodejs/packages/layer/src/global.d.ts new file mode 100644 index 0000000..a924b29 --- /dev/null +++ b/nodejs/packages/layer/src/global.d.ts @@ -0,0 +1,11 @@ +export {}; + +declare global { + var configureTracerProvider: ((tracerProvider: any) => void) | undefined; + var configureTracer: ((defaultConfig: any) => any) | undefined; + var configureSdkRegistration: ((defaultSdkRegistration: any) => any) | undefined; + var configureMeter: ((defaultConfig: any) => any) | undefined; + var configureMeterProvider: ((meterProvider: any) => void) | undefined; + var configureInstrumentations: (() => any[]) | undefined; + var configureAwsInstrumentation: ((config: any) => any) | undefined; +} \ No newline at end of file diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index ce5adde..3fbcff4 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -28,7 +28,7 @@ const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); const { getEnv } = require("@opentelemetry/core"); const { OTLPTraceExporter, -} = require("@opentelemetry/exporter-trace-otlp-proto"); +} = require("@opentelemetry/exporter-trace-otlp-http"); const { MeterProvider, MeterProviderOptions, diff --git a/nodejs/packages/layer/tsconfig.webpack.json b/nodejs/packages/layer/tsconfig.webpack.json new file mode 100644 index 0000000..8ce2ac7 --- /dev/null +++ b/nodejs/packages/layer/tsconfig.webpack.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.esm", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "test/**/*.ts", + "**/*.spec.ts" + ] +} diff --git a/opentelemetry-lambda b/opentelemetry-lambda index 5cc1580..1fca858 160000 --- a/opentelemetry-lambda +++ b/opentelemetry-lambda @@ -1 +1 @@ -Subproject commit 5cc158009047d6c5cdc9fad69b4a28e75c7c92f7 +Subproject commit 1fca858d13e01fac64a0e682404f17b774cdebf4 From 09d487721eb7a921a6c389ce8999a500dee52e31 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Fri, 8 Aug 2025 15:28:34 -0400 Subject: [PATCH 02/15] fix: CI compatibility for cross-platform builds - Fix architecture detection to prioritize ARCHITECTURE env var from CI - Update collector build to use GOARCH from CI environment - Fix global.d.ts to avoid test conflicts - Support both auto-detection (local) and explicit setting (CI) Resolves 'No files were found' CI error by generating correctly named opentelemetry-nodejs-{amd64,arm64}.zip files. --- collector/build.sh | 20 +++++++++++--------- nodejs/build.sh | 37 +++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/collector/build.sh b/collector/build.sh index db1d2c1..389ed98 100755 --- a/collector/build.sh +++ b/collector/build.sh @@ -15,27 +15,29 @@ popd || exit # Add config.yaml -# Use ARCHITECTURE from environment, default to host architecture if not set -if [ -z "$ARCHITECTURE" ]; then +# Use GOARCH (CI) or ARCHITECTURE (local) from environment, default to host architecture if not set +if [ -n "$GOARCH" ]; then + ARCH_TO_USE="$GOARCH" +elif [ -n "$ARCHITECTURE" ]; then + ARCH_TO_USE="$ARCHITECTURE" +else HOST_ARCH=$(uname -m) case $HOST_ARCH in x86_64) - GOARCH="amd64" + ARCH_TO_USE="amd64" ;; arm64|aarch64) - GOARCH="arm64" + ARCH_TO_USE="arm64" ;; *) echo "Unsupported architecture: $HOST_ARCH" exit 1 ;; esac -else - GOARCH="$ARCHITECTURE" fi -cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${GOARCH}.zip . -unzip -qo opentelemetry-collector-layer-${GOARCH}.zip -rm opentelemetry-collector-layer-${GOARCH}.zip +cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${ARCH_TO_USE}.zip . +unzip -qo opentelemetry-collector-layer-${ARCH_TO_USE}.zip +rm opentelemetry-collector-layer-${ARCH_TO_USE}.zip cp ./config/config.yaml ./collector-config/config.yaml zip -r collector-layer.zip collector-config extensions diff --git a/nodejs/build.sh b/nodejs/build.sh index 01ab730..2e51648 100755 --- a/nodejs/build.sh +++ b/nodejs/build.sh @@ -1,24 +1,29 @@ #!/bin/bash -# Detect host architecture -ARCH=$(uname -m) -case $ARCH in - x86_64) - ARCHITECTURE="amd64" - ;; - arm64|aarch64) - ARCHITECTURE="arm64" - ;; - *) - echo "Unsupported architecture: $ARCH" - exit 1 - ;; -esac - -echo "Building for architecture: $ARCHITECTURE" +# Detect or use provided architecture +if [ -z "$ARCHITECTURE" ]; then + # Auto-detect host architecture if ARCHITECTURE not set + ARCH=$(uname -m) + case $ARCH in + x86_64) + ARCHITECTURE="amd64" + ;; + arm64|aarch64) + ARCHITECTURE="arm64" + ;; + *) + echo "Unsupported architecture: $ARCH" + exit 1 + ;; + esac + echo "Auto-detected architecture: $ARCHITECTURE" +else + echo "Using provided architecture: $ARCHITECTURE" +fi # Export for use in collector build export ARCHITECTURE +export GOARCH=$ARCHITECTURE # Build collector From 7327733811112171f4aec8f5f73ed1cee3ba0616 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Fri, 8 Aug 2025 16:08:19 -0400 Subject: [PATCH 03/15] Update nodejs build.sh to include sample app building with lerna - Add npm run build to execute lerna build for all packages - Ensure sample apps like aws-sdk generate function.zip artifacts - Fix CI pipeline artifact generation issues - Remove redundant individual layer build step --- nodejs/build.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nodejs/build.sh b/nodejs/build.sh index 2e51648..1c2d783 100755 --- a/nodejs/build.sh +++ b/nodejs/build.sh @@ -46,13 +46,10 @@ cp ./packages/layer/tsconfig.webpack.json ../opentelemetry-lambda/nodejs/package cp ./packages/layer/install-externals.sh ../opentelemetry-lambda/nodejs/packages/layer/install-externals.sh 2>/dev/null || true chmod +x ../opentelemetry-lambda/nodejs/packages/layer/install-externals.sh 2>/dev/null || true -# Build nodejs sdk +# Build nodejs sdk and sample apps pushd ../opentelemetry-lambda/nodejs || exit npm install -popd || exit - -# Build the layer specifically -pushd ../opentelemetry-lambda/nodejs/packages/layer || exit +# Build all packages including sample apps with lerna npm run build popd || exit From e9bbaaaefd693e377277b0ce0e8ad0558b722008 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Fri, 8 Aug 2025 16:22:00 -0400 Subject: [PATCH 04/15] Fix S3 bucket naming in CI to comply with AWS naming rules - Replace branch name in bucket name with static prefix - Bucket name 'feat-upgrade-opentelemetry-v2-cross-platform-nodejs-arm64-16839545560' was too long and contained uppercase letters - New format: 'sumologic-otel-lambda-dev-{run_id}-{architecture}' - Also clean up layer naming for consistency --- .github/workflows/publish-dev-layer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-dev-layer.yml b/.github/workflows/publish-dev-layer.yml index 4dba43c..46f2249 100644 --- a/.github/workflows/publish-dev-layer.yml +++ b/.github/workflows/publish-dev-layer.yml @@ -33,11 +33,11 @@ jobs: aws_region: [ eu-central-1 ] env: LANGUAGE: ${{ inputs.LANGUAGE }} - LAYER_NAME: ${{ github.head_ref }}-${{ inputs.LANGUAGE }}-${{ matrix.architecture }} + LAYER_NAME: sumologic-otel-lambda-dev-${{ inputs.LANGUAGE }}-${{ matrix.architecture }}-${{ github.run_id }} ARCHITECTURE: ${{ matrix.architecture }} ARTIFACT_ARCHIVE_BASE_NAME: ${{ inputs.ARTIFACT_ARCHIVE_BASE_NAME }} ARTIFACT_NAME: ${{ inputs.ARTIFACT_NAME }} - BUCKET_NAME: ${{ github.head_ref }}-${{ inputs.LANGUAGE }}-${{ matrix.architecture }}-${{ github.run_id }} + BUCKET_NAME: sumologic-otel-lambda-dev-${{ github.run_id }}-${{ matrix.architecture }} BUCKET_KEY: layer-${{ matrix.architecture }}-${{ matrix.aws_region }}-.zip DIRECTORY: ${{ inputs.LANGUAGE }} REGION: ${{ matrix.aws_region }} From 31f7b3b4636d25b940ac0c74b0959d4c8cc16d87 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Fri, 8 Aug 2025 16:30:04 -0400 Subject: [PATCH 05/15] Fix Terraform aws_eip resource for newer AWS provider - Replace deprecated 'vpc = true' with 'domain = "vpc"' - Fixes compatibility with newer Terraform AWS provider versions - Resolves 'An argument named "vpc" is not expected here' error --- utils/receiver-mock/deploy/networking.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/receiver-mock/deploy/networking.tf b/utils/receiver-mock/deploy/networking.tf index cd47299..c569a0c 100644 --- a/utils/receiver-mock/deploy/networking.tf +++ b/utils/receiver-mock/deploy/networking.tf @@ -64,8 +64,8 @@ resource "aws_route_table_association" "public" { resource "aws_eip" "eip" { - count = length(var.private_subnets) - vpc = true + count = length(var.private_subnets) + domain = "vpc" tags = { Name = "${var.app_name}-eip-${count.index + 1}" Environment = var.app_environment From ea3a1b61f2f939359be9e6097beddc1dba7676f4 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Mon, 11 Aug 2025 12:49:37 -0400 Subject: [PATCH 06/15] Update expected SDK version in Node.js integration test to 2.0.0 - Update telemetry.sdk.version from '1.17.1' to '2.0.0' - Aligns test expectations with OpenTelemetry v2.x upgrade - Ensures integration tests validate correct SDK version reporting --- tests/lambdalayer/lambda_layer_nodejs_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lambdalayer/lambda_layer_nodejs_test.go b/tests/lambdalayer/lambda_layer_nodejs_test.go index a5c21ca..ca74220 100644 --- a/tests/lambdalayer/lambda_layer_nodejs_test.go +++ b/tests/lambdalayer/lambda_layer_nodejs_test.go @@ -18,7 +18,7 @@ var commonNodeJSAttributes = map[string]string{ "cloud.region": "eu-central-1", "telemetry.sdk.language": "nodejs", "telemetry.sdk.name": "opentelemetry", - "telemetry.sdk.version": "1.17.1", + "telemetry.sdk.version": "2.0.0", "service.name": nodejsFunctionName, "process.runtime.name": "nodejs", "faas.name": nodejsFunctionName, From 49312e0d83ab980cca454849d38c21ef51c85e42 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Tue, 12 Aug 2025 23:10:31 -0400 Subject: [PATCH 07/15] fix: add valid telemetry config to resolve collector validation error --- collector/config/config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/collector/config/config.yaml b/collector/config/config.yaml index 8c74bda..00128ad 100644 --- a/collector/config/config.yaml +++ b/collector/config/config.yaml @@ -13,3 +13,8 @@ service: traces: receivers: [otlp] exporters: [otlphttp] + telemetry: + logs: + level: info + metrics: + level: none From efdc0e64117237de4932737d7fa927629bee4229 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Tue, 12 Aug 2025 23:22:38 -0400 Subject: [PATCH 08/15] refactor: extract architecture detection to separate script - Create detect-arch.sh to handle architecture detection logic - Update build.sh to use the new script instead of inline logic - Improves maintainability and reusability of architecture detection --- collector/build.sh | 22 ++-------------------- collector/detect-arch.sh | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 20 deletions(-) create mode 100755 collector/detect-arch.sh diff --git a/collector/build.sh b/collector/build.sh index 389ed98..a35a839 100755 --- a/collector/build.sh +++ b/collector/build.sh @@ -15,26 +15,8 @@ popd || exit # Add config.yaml -# Use GOARCH (CI) or ARCHITECTURE (local) from environment, default to host architecture if not set -if [ -n "$GOARCH" ]; then - ARCH_TO_USE="$GOARCH" -elif [ -n "$ARCHITECTURE" ]; then - ARCH_TO_USE="$ARCHITECTURE" -else - HOST_ARCH=$(uname -m) - case $HOST_ARCH in - x86_64) - ARCH_TO_USE="amd64" - ;; - arm64|aarch64) - ARCH_TO_USE="arm64" - ;; - *) - echo "Unsupported architecture: $HOST_ARCH" - exit 1 - ;; - esac -fi +# Detect architecture to use for building +ARCH_TO_USE=$(./detect-arch.sh) cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${ARCH_TO_USE}.zip . unzip -qo opentelemetry-collector-layer-${ARCH_TO_USE}.zip diff --git a/collector/detect-arch.sh b/collector/detect-arch.sh new file mode 100755 index 0000000..9525535 --- /dev/null +++ b/collector/detect-arch.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Architecture detection script +# Returns the architecture to use for building (amd64 or arm64) + +# Use GOARCH (CI) or ARCHITECTURE (local) from environment, default to host architecture if not set +if [ -n "$GOARCH" ]; then + echo "$GOARCH" +elif [ -n "$ARCHITECTURE" ]; then + echo "$ARCHITECTURE" +else + HOST_ARCH=$(uname -m) + case $HOST_ARCH in + x86_64) + echo "amd64" + ;; + arm64|aarch64) + echo "arm64" + ;; + *) + echo "Unsupported architecture: $HOST_ARCH" >&2 + exit 1 + ;; + esac +fi From 41c7f0a102a9cfe58dc44c05ef21075f3c576d48 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Thu, 14 Aug 2025 11:18:36 -0400 Subject: [PATCH 09/15] fix: OpenTelemetry v2.0.0 compatibility for Node.js Lambda layer - Replace deprecated v1.x wrapper with v2.0.0 compatible implementation - Fix tsconfig.webpack.json to work without broken extends reference - Add missing otel-handler script for proper Lambda initialization - Resolves Runtime.ExitError during wrapper initialization --- nodejs/packages/layer/scripts/otel-handler | 23 ++ nodejs/packages/layer/src/wrapper.ts | 252 ++++---------------- nodejs/packages/layer/tsconfig.webpack.json | 11 +- 3 files changed, 77 insertions(+), 209 deletions(-) create mode 100755 nodejs/packages/layer/scripts/otel-handler diff --git a/nodejs/packages/layer/scripts/otel-handler b/nodejs/packages/layer/scripts/otel-handler new file mode 100755 index 0000000..913ca9b --- /dev/null +++ b/nodejs/packages/layer/scripts/otel-handler @@ -0,0 +1,23 @@ +#!/bin/bash + +# - Use Instrumentation + +export NODE_OPTIONS="${NODE_OPTIONS} --require /opt/wrapper.js" + +# - Set the service name + +if [[ -z "${OTEL_SERVICE_NAME}" ]]; then + export OTEL_SERVICE_NAME=${AWS_LAMBDA_FUNCTION_NAME}; +fi + +# - Set Lambda specific resource attributes + +export LAMBDA_RESOURCE_ATTRIBUTES="cloud.region=${AWS_REGION},cloud.provider=aws,faas.name=${AWS_LAMBDA_FUNCTION_NAME},faas.version=${AWS_LAMBDA_FUNCTION_VERSION}"; + +if [[ -z "${OTEL_RESOURCE_ATTRIBUTES}" ]]; then + export OTEL_RESOURCE_ATTRIBUTES=${LAMBDA_RESOURCE_ATTRIBUTES}; +else + export OTEL_RESOURCE_ATTRIBUTES="${LAMBDA_RESOURCE_ATTRIBUTES},${OTEL_RESOURCE_ATTRIBUTES}"; +fi + +exec "$@" diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index 3fbcff4..05b5574 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -1,214 +1,52 @@ -const { - NodeTracerConfig, - NodeTracerProvider, -} = require("@opentelemetry/sdk-trace-node"); -const { - BatchSpanProcessor, - ConsoleSpanExporter, - SDKRegistrationConfig, - SimpleSpanProcessor, -} = require("@opentelemetry/sdk-trace-base"); -const { - Instrumentation, - registerInstrumentations, -} = require("@opentelemetry/instrumentation"); -const { awsLambdaDetector } = require("@opentelemetry/resource-detector-aws"); -const { - detectResourcesSync, - envDetector, - processDetector, -} = require("@opentelemetry/resources"); -const { - AwsInstrumentation, -} = require("@opentelemetry/instrumentation-aws-sdk"); -const { - AwsLambdaInstrumentation, -} = require("@opentelemetry/instrumentation-aws-lambda"); -const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); -const { getEnv } = require("@opentelemetry/core"); -const { - OTLPTraceExporter, -} = require("@opentelemetry/exporter-trace-otlp-http"); -const { - MeterProvider, - MeterProviderOptions, -} = require("@opentelemetry/sdk-metrics"); - -function defaultConfigureInstrumentations() { - // Use require statements for instrumentation to avoid having to have transitive dependencies on all the typescript - // definitions. - const { DnsInstrumentation } = require("@opentelemetry/instrumentation-dns"); - const { - ExpressInstrumentation, - } = require("@opentelemetry/instrumentation-express"); - const { - GraphQLInstrumentation, - } = require("@opentelemetry/instrumentation-graphql"); - const { - GrpcInstrumentation, - } = require("@opentelemetry/instrumentation-grpc"); - const { - HapiInstrumentation, - } = require("@opentelemetry/instrumentation-hapi"); - const { - HttpInstrumentation, - } = require("@opentelemetry/instrumentation-http"); - const { - IORedisInstrumentation, - } = require("@opentelemetry/instrumentation-ioredis"); - const { KoaInstrumentation } = require("@opentelemetry/instrumentation-koa"); - const { - MongoDBInstrumentation, - } = require("@opentelemetry/instrumentation-mongodb"); - const { - MySQLInstrumentation, - } = require("@opentelemetry/instrumentation-mysql"); - const { NetInstrumentation } = require("@opentelemetry/instrumentation-net"); - const { PgInstrumentation } = require("@opentelemetry/instrumentation-pg"); - const { - RedisInstrumentation, - } = require("@opentelemetry/instrumentation-redis"); - return [ - new DnsInstrumentation(), - new ExpressInstrumentation(), - new GraphQLInstrumentation(), - new GrpcInstrumentation(), - new HapiInstrumentation(), - new HttpInstrumentation(), - new IORedisInstrumentation(), - new KoaInstrumentation(), - new MongoDBInstrumentation(), - new MySQLInstrumentation(), - new NetInstrumentation(), - new PgInstrumentation(), - new RedisInstrumentation(), - ]; -} - -global.configureTracerProvider = function (tracerProvider) {}; -global.configureTracer = function (defaultConfig) { - return defaultConfig; -}; -global.configureSdkRegistration = function (defaultSdkRegistration) { - return defaultSdkRegistration; -}; -global.configureMeter = function (defaultConfig) { - return defaultConfig; -}; -global.configureMeterProvider = function (meterProvider) {}; -global.configureInstrumentations = function () { - return []; -}; - -// configure lambda logging -const logLevel = getEnv().OTEL_LOG_LEVEL; -diag.setLogger(new DiagConsoleLogger(), logLevel); - -console.log("Registering OpenTelemetry"); +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Wrapper for OpenTelemetry v2.0.0 compatibility + +const api = require("@opentelemetry/api"); +const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); +const { Resource } = require("@opentelemetry/resources"); +const { BatchSpanProcessor } = require("@opentelemetry/sdk-trace-base"); +const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http"); +const { registerInstrumentations } = require("@opentelemetry/instrumentation"); +const { AwsLambdaInstrumentation } = require("@opentelemetry/instrumentation-aws-lambda"); +const { AwsInstrumentation } = require("@opentelemetry/instrumentation-aws-sdk"); + +// Simple initialization for v2.0.0 +console.log("Initializing OpenTelemetry v2.0.0 wrapper"); + +const provider = new NodeTracerProvider({ + resource: Resource.default() +}); -// By default use OpenTelemetry context propagation -let disableAwsContextPropagation = true; -const sumoOtelDisableAwsContextPropagationVal = - process.env.SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION; -if ( - sumoOtelDisableAwsContextPropagationVal === "false" || - sumoOtelDisableAwsContextPropagationVal === "False" -) { - disableAwsContextPropagation = false; -} +const exporter = new OTLPTraceExporter({ + url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || "http://localhost:4318/v1/traces" +}); -// For debug purposes only -if (logLevel === DiagLogLevel.DEBUG) { - console.log("Debug environment variables status"); - console.log( - "AWS_LAMBDA_EXEC_WRAPPER value ", - process.env.AWS_LAMBDA_EXEC_WRAPPER - ); - console.log( - "OTEL_RESOURCE_ATTRIBUTES value", - process.env.OTEL_RESOURCE_ATTRIBUTES - ); - console.log("OTEL_SERVICE_NAME value", process.env.OTEL_SERVICE_NAME); - console.log("OTEL_TRACES_SAMPLER value", process.env.OTEL_TRACES_SAMPLER); - console.log( - "SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL value", - process.env.SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL - ); - console.log( - "SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION value", - process.env.SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION - ); -} +provider.addSpanProcessor(new BatchSpanProcessor(exporter)); -const instrumentations = [ - new AwsInstrumentation({ - suppressInternalInstrumentation: true, - }), - new AwsLambdaInstrumentation({ - disableAwsContextPropagation: disableAwsContextPropagation, - }), - ...(typeof configureInstrumentations === "function" - ? configureInstrumentations - : defaultConfigureInstrumentations)(), -]; +// Register the provider +api.trace.setGlobalTracerProvider(provider); -// Register instrumentations synchronously to ensure code is patched even before provider is ready. +// Register basic instrumentations registerInstrumentations({ - instrumentations, + instrumentations: [ + new AwsLambdaInstrumentation(), + new AwsInstrumentation() + ] }); -async function initializeProvider() { - const resource = detectResourcesSync({ - detectors: [awsLambdaDetector, envDetector, processDetector], - }); - - let config = { - resource, - }; - if (typeof configureTracer === "function") { - config = configureTracer(config); - } - - const tracerProvider = new NodeTracerProvider(config); - if (typeof configureTracerProvider === "function") { - configureTracerProvider(tracerProvider); - } else { - // defaults - tracerProvider.addSpanProcessor( - new BatchSpanProcessor(new OTLPTraceExporter()) - ); - } - // logging for debug - if (logLevel === DiagLogLevel.DEBUG) { - tracerProvider.addSpanProcessor( - new SimpleSpanProcessor(new ConsoleSpanExporter()) - ); - } - - let sdkRegistrationConfig = {}; - if (typeof configureSdkRegistration === "function") { - sdkRegistrationConfig = configureSdkRegistration(sdkRegistrationConfig); - } - tracerProvider.register(sdkRegistrationConfig); - - // Configure default meter provider (do not export metrics) - let meterConfig = { - resource, - }; - if (typeof configureMeter === "function") { - meterConfig = configureMeter(meterConfig); - } - - const meterProvider = new MeterProvider(meterConfig); - if (typeof configureMeterProvider === "function") { - configureMeterProvider(meterProvider); - } - - // Re-register instrumentation with initialized provider. Patched code will see the update. - registerInstrumentations({ - instrumentations, - tracerProvider, - meterProvider, - }); -} -initializeProvider(); +console.log("OpenTelemetry v2.0.0 wrapper initialized successfully"); diff --git a/nodejs/packages/layer/tsconfig.webpack.json b/nodejs/packages/layer/tsconfig.webpack.json index 8ce2ac7..8f2a22c 100644 --- a/nodejs/packages/layer/tsconfig.webpack.json +++ b/nodejs/packages/layer/tsconfig.webpack.json @@ -1,8 +1,15 @@ { - "extends": "../../tsconfig.esm", "compilerOptions": { + "target": "es2018", + "module": "commonjs", + "lib": ["es2018"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, "rootDir": ".", - "outDir": "build" + "outDir": "build", + "moduleResolution": "node" }, "include": [ "src/**/*.ts" From 680a4b9c5a4cf2f57c05c363c15626b6e885e861 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Thu, 14 Aug 2025 15:57:28 -0400 Subject: [PATCH 10/15] feat: upgrade to OpenTelemetry v2.0.0 with API compatibility fixes - Replace getEnv() with getStringFromEnv() for OTEL_LOG_LEVEL - Replace detectResourcesSync() with async detectResources() - Update build scripts for cross-platform architecture support --- collector/build.sh | 6 +- nodejs/build.sh | 2 +- nodejs/packages/layer/src/wrapper.ts | 236 +++++++++++++++++++++++---- 3 files changed, 213 insertions(+), 31 deletions(-) diff --git a/collector/build.sh b/collector/build.sh index a35a839..f9d5802 100755 --- a/collector/build.sh +++ b/collector/build.sh @@ -10,7 +10,11 @@ cp ./src/internal/telemetryapi/listener.go ../opentelemetry-lambda/collector/int pushd ../opentelemetry-lambda/collector || exit make install-tools make gofmt -make package +make build +# Package manually to fix config +mkdir -p build/collector-config +cp ../../collector/config/config.yaml build/collector-config/config.yaml +cd build && zip -r opentelemetry-collector-layer-${ARCH_TO_USE}.zip collector-config extensions popd || exit # Add config.yaml diff --git a/nodejs/build.sh b/nodejs/build.sh index 1c2d783..d620b40 100755 --- a/nodejs/build.sh +++ b/nodejs/build.sh @@ -56,7 +56,7 @@ popd || exit # Combine collector extension with nodejs sdk ## Copy and extract all files mkdir combine -cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${ARCHITECTURE}.zip ./combine/collector-layer.zip +cp ../collector/collector-layer.zip ./combine/collector-layer.zip cp ../opentelemetry-lambda/nodejs/packages/layer/build/layer.zip ./combine unzip -qo combine/collector-layer.zip -d combine diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index 05b5574..97b6632 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -14,39 +14,217 @@ * limitations under the License. */ -// Wrapper for OpenTelemetry v2.0.0 compatibility - -const api = require("@opentelemetry/api"); -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const { Resource } = require("@opentelemetry/resources"); -const { BatchSpanProcessor } = require("@opentelemetry/sdk-trace-base"); -const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-http"); -const { registerInstrumentations } = require("@opentelemetry/instrumentation"); -const { AwsLambdaInstrumentation } = require("@opentelemetry/instrumentation-aws-lambda"); -const { AwsInstrumentation } = require("@opentelemetry/instrumentation-aws-sdk"); - -// Simple initialization for v2.0.0 -console.log("Initializing OpenTelemetry v2.0.0 wrapper"); - -const provider = new NodeTracerProvider({ - resource: Resource.default() -}); +const { + NodeTracerConfig, + NodeTracerProvider, +} = require("@opentelemetry/sdk-trace-node"); +const { + BatchSpanProcessor, + ConsoleSpanExporter, + SDKRegistrationConfig, + SimpleSpanProcessor, +} = require("@opentelemetry/sdk-trace-base"); +const { + Instrumentation, + registerInstrumentations, +} = require("@opentelemetry/instrumentation"); +const { awsLambdaDetector } = require("@opentelemetry/resource-detector-aws"); +const { + detectResources, + envDetector, + processDetector, +} = require("@opentelemetry/resources"); +const { + AwsInstrumentation, +} = require("@opentelemetry/instrumentation-aws-sdk"); +const { + AwsLambdaInstrumentation, +} = require("@opentelemetry/instrumentation-aws-lambda"); +const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); +const { getStringFromEnv } = require("@opentelemetry/core"); +const { + OTLPTraceExporter, +} = require("@opentelemetry/exporter-trace-otlp-http"); +const { + MeterProvider, + MeterProviderOptions, +} = require("@opentelemetry/sdk-metrics"); -const exporter = new OTLPTraceExporter({ - url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || "http://localhost:4318/v1/traces" -}); +function defaultConfigureInstrumentations() { + // Use require statements for instrumentation to avoid having to have transitive dependencies on all the typescript + // definitions. + const { DnsInstrumentation } = require("@opentelemetry/instrumentation-dns"); + const { + ExpressInstrumentation, + } = require("@opentelemetry/instrumentation-express"); + const { + GraphQLInstrumentation, + } = require("@opentelemetry/instrumentation-graphql"); + const { + GrpcInstrumentation, + } = require("@opentelemetry/instrumentation-grpc"); + const { + HapiInstrumentation, + } = require("@opentelemetry/instrumentation-hapi"); + const { + HttpInstrumentation, + } = require("@opentelemetry/instrumentation-http"); + const { + IORedisInstrumentation, + } = require("@opentelemetry/instrumentation-ioredis"); + const { KoaInstrumentation } = require("@opentelemetry/instrumentation-koa"); + const { + MongoDBInstrumentation, + } = require("@opentelemetry/instrumentation-mongodb"); + const { + MySQLInstrumentation, + } = require("@opentelemetry/instrumentation-mysql"); + const { NetInstrumentation } = require("@opentelemetry/instrumentation-net"); + const { PgInstrumentation } = require("@opentelemetry/instrumentation-pg"); + const { + RedisInstrumentation, + } = require("@opentelemetry/instrumentation-redis"); + return [ + new DnsInstrumentation(), + new ExpressInstrumentation(), + new GraphQLInstrumentation(), + new GrpcInstrumentation(), + new HapiInstrumentation(), + new HttpInstrumentation(), + new IORedisInstrumentation(), + new KoaInstrumentation(), + new MongoDBInstrumentation(), + new MySQLInstrumentation(), + new NetInstrumentation(), + new PgInstrumentation(), + new RedisInstrumentation(), + ]; +} + +global.configureTracerProvider = function (tracerProvider) {}; +global.configureTracer = function (defaultConfig) { + return defaultConfig; +}; +global.configureSdkRegistration = function (defaultSdkRegistration) { + return defaultSdkRegistration; +}; +global.configureMeter = function (defaultConfig) { + return defaultConfig; +}; +global.configureMeterProvider = function (meterProvider) {}; +global.configureInstrumentations = function () { + return []; +}; + +// configure lambda logging +const logLevel: any = getStringFromEnv('OTEL_LOG_LEVEL') || DiagLogLevel.INFO; +diag.setLogger(new DiagConsoleLogger(), logLevel); + +console.log("Registering OpenTelemetry"); + +// By default use OpenTelemetry context propagation +let disableAwsContextPropagation = true; +const sumoOtelDisableAwsContextPropagationVal = + process.env.SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION; +if ( + sumoOtelDisableAwsContextPropagationVal === "false" || + sumoOtelDisableAwsContextPropagationVal === "False" +) { + disableAwsContextPropagation = false; +} -provider.addSpanProcessor(new BatchSpanProcessor(exporter)); +// For debug purposes only +if (logLevel === DiagLogLevel.DEBUG) { + console.log("Debug environment variables status"); + console.log( + "AWS_LAMBDA_EXEC_WRAPPER value ", + process.env.AWS_LAMBDA_EXEC_WRAPPER + ); + console.log( + "OTEL_RESOURCE_ATTRIBUTES value", + process.env.OTEL_RESOURCE_ATTRIBUTES + ); + console.log("OTEL_SERVICE_NAME value", process.env.OTEL_SERVICE_NAME); + console.log("OTEL_TRACES_SAMPLER value", process.env.OTEL_TRACES_SAMPLER); + console.log( + "SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL value", + process.env.SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL + ); + console.log( + "SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION value", + process.env.SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION + ); +} -// Register the provider -api.trace.setGlobalTracerProvider(provider); +const instrumentations = [ + new AwsInstrumentation({ + suppressInternalInstrumentation: true, + }), + new AwsLambdaInstrumentation({ + disableAwsContextPropagation: disableAwsContextPropagation, + }), + ...(typeof configureInstrumentations === "function" + ? configureInstrumentations + : defaultConfigureInstrumentations)(), +]; -// Register basic instrumentations +// Register instrumentations synchronously to ensure code is patched even before provider is ready. registerInstrumentations({ - instrumentations: [ - new AwsLambdaInstrumentation(), - new AwsInstrumentation() - ] + instrumentations, }); -console.log("OpenTelemetry v2.0.0 wrapper initialized successfully"); +async function initializeProvider() { + const resource = await detectResources({ + detectors: [awsLambdaDetector, envDetector, processDetector], + }); + + let config = { + resource, + }; + if (typeof configureTracer === "function") { + config = configureTracer(config); + } + + const tracerProvider = new NodeTracerProvider(config); + if (typeof configureTracerProvider === "function") { + configureTracerProvider(tracerProvider); + } else { + // defaults + tracerProvider.addSpanProcessor( + new BatchSpanProcessor(new OTLPTraceExporter()) + ); + } + // logging for debug + if ((logLevel as any) === DiagLogLevel.DEBUG) { + tracerProvider.addSpanProcessor( + new SimpleSpanProcessor(new ConsoleSpanExporter()) + ); + } + + let sdkRegistrationConfig = {}; + if (typeof configureSdkRegistration === "function") { + sdkRegistrationConfig = configureSdkRegistration(sdkRegistrationConfig); + } + tracerProvider.register(sdkRegistrationConfig); + + // Configure default meter provider (do not export metrics) + let meterConfig = { + resource, + }; + if (typeof configureMeter === "function") { + meterConfig = configureMeter(meterConfig); + } + + const meterProvider = new MeterProvider(meterConfig); + if (typeof configureMeterProvider === "function") { + configureMeterProvider(meterProvider); + } + + // Re-register instrumentation with initialized provider. Patched code will see the update. + registerInstrumentations({ + instrumentations, + tracerProvider, + meterProvider, + }); +} +initializeProvider(); From ab4ae228b92a63a75762eb3484ac7602c2adab55 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Mon, 18 Aug 2025 16:13:41 -0400 Subject: [PATCH 11/15] feat: implement OTel 2.0 environment-based exporter configuration - Use ${env:SUMO_OTLP_HTTP_ENDPOINT_URL} in collector config - Add getExportersFromEnv() following OTel 2.0 patterns - Remove debug traces and sensitive URL logging --- collector/build.sh | 6 +- collector/config/config.yaml | 4 +- nodejs/packages/layer/src/wrapper.ts | 134 +++++++++++++++++++++++---- 3 files changed, 121 insertions(+), 23 deletions(-) diff --git a/collector/build.sh b/collector/build.sh index f9d5802..b67b9c7 100755 --- a/collector/build.sh +++ b/collector/build.sh @@ -5,6 +5,9 @@ cp ./src/main.go ../opentelemetry-lambda/collector cp ./src/internal/telemetryapi/listener.go ../opentelemetry-lambda/collector/internal/telemetryapi/listener.go +# Detect architecture to use for building +ARCH_TO_USE=$(./detect-arch.sh) + # Build collector pushd ../opentelemetry-lambda/collector || exit @@ -19,9 +22,6 @@ popd || exit # Add config.yaml -# Detect architecture to use for building -ARCH_TO_USE=$(./detect-arch.sh) - cp ../opentelemetry-lambda/collector/build/opentelemetry-collector-layer-${ARCH_TO_USE}.zip . unzip -qo opentelemetry-collector-layer-${ARCH_TO_USE}.zip rm opentelemetry-collector-layer-${ARCH_TO_USE}.zip diff --git a/collector/config/config.yaml b/collector/config/config.yaml index 00128ad..169bd17 100644 --- a/collector/config/config.yaml +++ b/collector/config/config.yaml @@ -6,7 +6,7 @@ receivers: exporters: otlphttp: - endpoint: $SUMO_OTLP_HTTP_ENDPOINT_URL + endpoint: ${env:SUMO_OTLP_HTTP_ENDPOINT_URL} service: pipelines: @@ -15,6 +15,6 @@ service: exporters: [otlphttp] telemetry: logs: - level: info + level: debug metrics: level: none diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index 97b6632..9b1f64d 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -85,6 +85,7 @@ function defaultConfigureInstrumentations() { RedisInstrumentation, } = require("@opentelemetry/instrumentation-redis"); return [ + new AwsInstrumentation(), new DnsInstrumentation(), new ExpressInstrumentation(), new GraphQLInstrumentation(), @@ -101,7 +102,6 @@ function defaultConfigureInstrumentations() { ]; } -global.configureTracerProvider = function (tracerProvider) {}; global.configureTracer = function (defaultConfig) { return defaultConfig; }; @@ -116,10 +116,79 @@ global.configureInstrumentations = function () { return []; }; +// Environment-based exporter configuration (OTel 2.0 pattern) +function getExportersFromEnv() { + console.log("*** DEBUG: getExportersFromEnv() called"); + console.log("*** DEBUG: OTEL_TRACES_EXPORTER =", process.env.OTEL_TRACES_EXPORTER); + console.log("*** DEBUG: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT =", process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT); + + if ( + process.env.OTEL_TRACES_EXPORTER == null || + process.env.OTEL_TRACES_EXPORTER.trim() === '' + ) { + console.log("*** DEBUG: No OTEL_TRACES_EXPORTER set, defaulting to OTLP exporter"); + const defaultExporter = new OTLPTraceExporter(); + console.log("*** DEBUG: Default OTLP exporter created, endpoint:", defaultExporter.url); + return [defaultExporter]; + } + if (process.env.OTEL_TRACES_EXPORTER.includes('none')) { + console.log("*** DEBUG: OTEL_TRACES_EXPORTER includes 'none', returning null"); + return null; + } + + const stringToExporter = new Map([ + ['otlp', () => { + console.log("*** DEBUG: Creating OTLP exporter"); + const exporter = new OTLPTraceExporter(); + console.log("*** DEBUG: OTLP exporter created, endpoint:", exporter.url); + return exporter; + }], + ['console', () => { + console.log("*** DEBUG: Creating Console exporter"); + return new ConsoleSpanExporter(); + }], + ]); + const exporters: any[] = []; + process.env.OTEL_TRACES_EXPORTER.split(',').map((exporterName: string) => { + exporterName = exporterName.toLowerCase().trim(); + console.log("*** DEBUG: Processing exporter:", exporterName); + const exporter = stringToExporter.get(exporterName); + if (exporter) { + const createdExporter = exporter(); + exporters.push(createdExporter); + console.log("*** DEBUG: Added exporter:", exporterName); + } else { + console.warn( + `Invalid exporter "${exporterName}" specified in the environment variable OTEL_TRACES_EXPORTER`, + ); + } + }); + + if (exporters.length === 0) { + console.log("*** DEBUG: No valid exporters found, defaulting to OTLP"); + const fallbackExporter = new OTLPTraceExporter(); + console.log("*** DEBUG: Fallback OTLP exporter created, endpoint:", fallbackExporter.url); + return [fallbackExporter]; + } + + console.log("*** DEBUG: Returning", exporters.length, "exporters"); + return exporters; +} + // configure lambda logging const logLevel: any = getStringFromEnv('OTEL_LOG_LEVEL') || DiagLogLevel.INFO; diag.setLogger(new DiagConsoleLogger(), logLevel); +// Map vendor-specific endpoint to OTel variable before exporter creation +// Keep using localhost collector but ensure proper endpoint mapping +if (process.env.SUMO_OTLP_HTTP_ENDPOINT_URL && !process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) { + // Use localhost collector as intended, but log the Sumo endpoint for collector to use + process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "http://localhost:4318/v1/traces"; +} else if (!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) { + // Default fallback to localhost collector + process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = "http://localhost:4318/v1/traces"; +} + console.log("Registering OpenTelemetry"); // By default use OpenTelemetry context propagation @@ -147,8 +216,8 @@ if (logLevel === DiagLogLevel.DEBUG) { console.log("OTEL_SERVICE_NAME value", process.env.OTEL_SERVICE_NAME); console.log("OTEL_TRACES_SAMPLER value", process.env.OTEL_TRACES_SAMPLER); console.log( - "SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL value", - process.env.SUMOLOGIC_HTTP_TRACES_ENDPOINT_URL + "SUMO_OTLP_HTTP_ENDPOINT_URL value", + process.env.SUMO_OTLP_HTTP_ENDPOINT_URL ); console.log( "SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION value", @@ -173,40 +242,69 @@ registerInstrumentations({ instrumentations, }); -async function initializeProvider() { - const resource = await detectResources({ - detectors: [awsLambdaDetector, envDetector, processDetector], - }); - +async function initializeTracerProvider(resource: any) { let config = { resource, + spanProcessors: [] as any[], }; + + const exporters = getExportersFromEnv(); + if (!exporters) { + return undefined; + } + if (typeof configureTracer === "function") { config = configureTracer(config); } - const tracerProvider = new NodeTracerProvider(config); - if (typeof configureTracerProvider === "function") { - configureTracerProvider(tracerProvider); - } else { - // defaults - tracerProvider.addSpanProcessor( - new BatchSpanProcessor(new OTLPTraceExporter()) - ); + // Configure span processors based on exporters + if (exporters.length) { + config.spanProcessors = []; + exporters.forEach((exporter: any) => { + if (exporter instanceof ConsoleSpanExporter) { + config.spanProcessors.push(new SimpleSpanProcessor(exporter)); + } else { + config.spanProcessors.push(new BatchSpanProcessor(exporter)); + } + }); + } + + config.spanProcessors = config.spanProcessors || []; + if (config.spanProcessors.length === 0) { + // Default + config.spanProcessors.push(new BatchSpanProcessor(new OTLPTraceExporter())); } - // logging for debug + + // Logging for debug if ((logLevel as any) === DiagLogLevel.DEBUG) { - tracerProvider.addSpanProcessor( + config.spanProcessors.push( new SimpleSpanProcessor(new ConsoleSpanExporter()) ); } + const tracerProvider = new NodeTracerProvider(config); + let sdkRegistrationConfig = {}; if (typeof configureSdkRegistration === "function") { sdkRegistrationConfig = configureSdkRegistration(sdkRegistrationConfig); } tracerProvider.register(sdkRegistrationConfig); + return tracerProvider; +} + +async function initializeProvider() { + const resource = await detectResources({ + detectors: [awsLambdaDetector, envDetector, processDetector], + }); + + const tracerProvider = await initializeTracerProvider(resource); + + if (!tracerProvider) { + console.log("*** DEBUG: No tracer provider initialized (exporters disabled)"); + return; + } + // Configure default meter provider (do not export metrics) let meterConfig = { resource, From f97ecfea11557862910d7f4e7d05fb43f6165466 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Tue, 19 Aug 2025 11:59:04 -0400 Subject: [PATCH 12/15] feat: remove URL logging and cleanup debug output --- collector/config/config.yaml | 2 +- nodejs/packages/layer/src/wrapper.ts | 35 ++++------------------------ 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/collector/config/config.yaml b/collector/config/config.yaml index 169bd17..7bfe4e1 100644 --- a/collector/config/config.yaml +++ b/collector/config/config.yaml @@ -15,6 +15,6 @@ service: exporters: [otlphttp] telemetry: logs: - level: debug + level: info metrics: level: none diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index 9b1f64d..2395786 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -118,45 +118,27 @@ global.configureInstrumentations = function () { // Environment-based exporter configuration (OTel 2.0 pattern) function getExportersFromEnv() { - console.log("*** DEBUG: getExportersFromEnv() called"); - console.log("*** DEBUG: OTEL_TRACES_EXPORTER =", process.env.OTEL_TRACES_EXPORTER); - console.log("*** DEBUG: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT =", process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT); - if ( process.env.OTEL_TRACES_EXPORTER == null || process.env.OTEL_TRACES_EXPORTER.trim() === '' ) { - console.log("*** DEBUG: No OTEL_TRACES_EXPORTER set, defaulting to OTLP exporter"); - const defaultExporter = new OTLPTraceExporter(); - console.log("*** DEBUG: Default OTLP exporter created, endpoint:", defaultExporter.url); - return [defaultExporter]; + return [new OTLPTraceExporter()]; } if (process.env.OTEL_TRACES_EXPORTER.includes('none')) { - console.log("*** DEBUG: OTEL_TRACES_EXPORTER includes 'none', returning null"); return null; } const stringToExporter = new Map([ - ['otlp', () => { - console.log("*** DEBUG: Creating OTLP exporter"); - const exporter = new OTLPTraceExporter(); - console.log("*** DEBUG: OTLP exporter created, endpoint:", exporter.url); - return exporter; - }], - ['console', () => { - console.log("*** DEBUG: Creating Console exporter"); - return new ConsoleSpanExporter(); - }], + ['otlp', () => new OTLPTraceExporter()], + ['console', () => new ConsoleSpanExporter()], ]); const exporters: any[] = []; process.env.OTEL_TRACES_EXPORTER.split(',').map((exporterName: string) => { exporterName = exporterName.toLowerCase().trim(); - console.log("*** DEBUG: Processing exporter:", exporterName); const exporter = stringToExporter.get(exporterName); if (exporter) { const createdExporter = exporter(); exporters.push(createdExporter); - console.log("*** DEBUG: Added exporter:", exporterName); } else { console.warn( `Invalid exporter "${exporterName}" specified in the environment variable OTEL_TRACES_EXPORTER`, @@ -165,13 +147,9 @@ function getExportersFromEnv() { }); if (exporters.length === 0) { - console.log("*** DEBUG: No valid exporters found, defaulting to OTLP"); - const fallbackExporter = new OTLPTraceExporter(); - console.log("*** DEBUG: Fallback OTLP exporter created, endpoint:", fallbackExporter.url); - return [fallbackExporter]; + return [new OTLPTraceExporter()]; } - console.log("*** DEBUG: Returning", exporters.length, "exporters"); return exporters; } @@ -215,10 +193,6 @@ if (logLevel === DiagLogLevel.DEBUG) { ); console.log("OTEL_SERVICE_NAME value", process.env.OTEL_SERVICE_NAME); console.log("OTEL_TRACES_SAMPLER value", process.env.OTEL_TRACES_SAMPLER); - console.log( - "SUMO_OTLP_HTTP_ENDPOINT_URL value", - process.env.SUMO_OTLP_HTTP_ENDPOINT_URL - ); console.log( "SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION value", process.env.SUMO_OTEL_DISABLE_AWS_CONTEXT_PROPAGATION @@ -301,7 +275,6 @@ async function initializeProvider() { const tracerProvider = await initializeTracerProvider(resource); if (!tracerProvider) { - console.log("*** DEBUG: No tracer provider initialized (exporters disabled)"); return; } From 5dc63e97b94a5428d07a77f87ddbc93c3445fad3 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Tue, 19 Aug 2025 14:05:24 -0400 Subject: [PATCH 13/15] feat: improve lambda logging with diagLogLevelFromString --- nodejs/packages/layer/src/wrapper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/packages/layer/src/wrapper.ts b/nodejs/packages/layer/src/wrapper.ts index 2395786..b7a7d97 100644 --- a/nodejs/packages/layer/src/wrapper.ts +++ b/nodejs/packages/layer/src/wrapper.ts @@ -41,7 +41,7 @@ const { AwsLambdaInstrumentation, } = require("@opentelemetry/instrumentation-aws-lambda"); const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); -const { getStringFromEnv } = require("@opentelemetry/core"); +const { getStringFromEnv, diagLogLevelFromString } = require("@opentelemetry/core"); const { OTLPTraceExporter, } = require("@opentelemetry/exporter-trace-otlp-http"); @@ -154,7 +154,7 @@ function getExportersFromEnv() { } // configure lambda logging -const logLevel: any = getStringFromEnv('OTEL_LOG_LEVEL') || DiagLogLevel.INFO; +const logLevel = diagLogLevelFromString(getStringFromEnv('OTEL_LOG_LEVEL')); diag.setLogger(new DiagConsoleLogger(), logLevel); // Map vendor-specific endpoint to OTel variable before exporter creation @@ -250,7 +250,7 @@ async function initializeTracerProvider(resource: any) { } // Logging for debug - if ((logLevel as any) === DiagLogLevel.DEBUG) { + if (logLevel === DiagLogLevel.DEBUG) { config.spanProcessors.push( new SimpleSpanProcessor(new ConsoleSpanExporter()) ); From f67dcbc7b48fafef0c5beff67da961bd0d727a93 Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Wed, 20 Aug 2025 13:12:21 -0400 Subject: [PATCH 14/15] feat: update nodejs layer runtimes to 18.x, 20.x, 22.x --- nodejs/README.md | 2 +- nodejs/layer-data.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/README.md b/nodejs/README.md index eca751e..13bcae8 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -2,7 +2,7 @@ Sumo Logic lambda layers support: -- `nodejs16.x`, `nodejs18.x` and `nodejs20.x` runtimes +- `nodejs18.x`, `nodejs20.x` and `nodejs22.x` runtimes - `x86_64` and `arm64` architectures ## AMD64 Lambda Layers List diff --git a/nodejs/layer-data.sh b/nodejs/layer-data.sh index 793560d..baaf40c 100755 --- a/nodejs/layer-data.sh +++ b/nodejs/layer-data.sh @@ -3,7 +3,7 @@ OFFICIAL_LAYER_NAME=sumologic-otel-lambda-nodejs ARCHITECTURE_AMD=x86_64 ARCHITECTURE_ARM=arm64 -RUNTIMES='nodejs16.x nodejs18.x nodejs20.x' +RUNTIMES='nodejs18.x nodejs20.x nodejs22.x' DESCRIPTION='Sumo Logic OTel Collector and NodeJS Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/main/nodejs' LICENSE=Apache-2.0 -VERSION=v1-17-2 +VERSION=v1-17-3 From e1665fcda662452ac5975b32b52cd57bbd58b5fa Mon Sep 17 00:00:00 2001 From: Raj Nishtala Date: Wed, 20 Aug 2025 14:53:42 -0400 Subject: [PATCH 15/15] Update nodejs layer version to v2-0-0 --- nodejs/layer-data.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodejs/layer-data.sh b/nodejs/layer-data.sh index baaf40c..47a451d 100755 --- a/nodejs/layer-data.sh +++ b/nodejs/layer-data.sh @@ -6,4 +6,4 @@ ARCHITECTURE_ARM=arm64 RUNTIMES='nodejs18.x nodejs20.x nodejs22.x' DESCRIPTION='Sumo Logic OTel Collector and NodeJS Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/main/nodejs' LICENSE=Apache-2.0 -VERSION=v1-17-3 +VERSION=v2-0-0