diff --git a/lambda/package.json b/lambda/package.json index 6f7bfe84..79f572bd 100644 --- a/lambda/package.json +++ b/lambda/package.json @@ -6,6 +6,7 @@ "{{name}}": "{{version}}", "@opentelemetry/api": "{{api-version}}", "@opentelemetry/exporter-trace-otlp-grpc": "{{exporters-version}}", - "@opentelemetry/exporter-metrics-otlp-grpc": "{{exporters-version}}" + "@opentelemetry/exporter-metrics-otlp-grpc": "{{exporters-version}}", + "semver": "^7" } } diff --git a/lambda/shim.cjs b/lambda/shim.cjs deleted file mode 100644 index 7241c1cb..00000000 --- a/lambda/shim.cjs +++ /dev/null @@ -1 +0,0 @@ -require("{{name}}") diff --git a/lambda/shim.mjs b/lambda/shim.mjs index 98da8f78..0fa7c152 100644 --- a/lambda/shim.mjs +++ b/lambda/shim.mjs @@ -1 +1,58 @@ -await import("{{name}}") +import fs from "node:fs" +import path from "node:path" +import satisfies from "semver/functions/satisfies" + +try { + const BUNDLED_API = "/opt/solarwinds-apm/node_modules/@opentelemetry/api" + const dirs = [] + + // Add relative node_modules dirs to the search paths + const TASK_ROOT = process.env.LAMBDA_TASK_ROOT + if (TASK_ROOT) { + let dir = TASK_ROOT + while (true) { + dirs.push(path.join(dir, "node_modules")) + + const parent = path.dirname(dir) + if (dir !== parent) { + dir = parent + } else { + break + } + } + } + + // Add entries from NODE_PATH to the search paths + const NODE_PATH = process.env.NODE_PATH?.split(":") ?? [] + dirs.push(...NODE_PATH) + + // Search for a use-provided OTel API + for (const dir of dirs) { + const api = path.join(dir, "@opentelemetry", "api") + let version + try { + // Try and read the package.json version in this search path + version = JSON.parse( + fs.readFileSync(path.join(api, "package.json"), { encoding: "utf-8" }), + ).version + } catch { + // No valid package.json found, search next path + continue + } + + try { + // Try and override our bundled OTel API if the user provides it + if (satisfies(version, "{{api-version}}")) { + fs.rmSync(BUNDLED_API, { recursive: true, force: true }) + fs.symlinkSync(api, BUNDLED_API) + } + } catch { + // Something is wrong, bail + break + } + } + + await import("{{name}}") +} catch (error) { + console.error(error) +} diff --git a/lambda/wrapper b/lambda/wrapper index 707e9ac3..d59cf410 100755 --- a/lambda/wrapper +++ b/lambda/wrapper @@ -1,11 +1,5 @@ #!/bin/bash - -# Only use --require to load if SW_APM_CJS is set -if [ -z "${SW_APM_CJS}" ]; then - export NODE_OPTIONS="${NODE_OPTIONS} --import /opt/solarwinds-apm/shim.mjs" -else - export NODE_OPTIONS="${NODE_OPTIONS} --require /opt/solarwinds-apm/shim.cjs" -fi +export NODE_OPTIONS="${NODE_OPTIONS} --import /opt/solarwinds-apm/shim.mjs" # The default for Node is http/proto but we only include the gRPC exporters export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"