From dd9429a102a6a3bdab28f2715bfe76872ffbe89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Sumis=C5=82awski?= Date: Wed, 4 Dec 2024 12:50:29 +0100 Subject: [PATCH] Warm up http/proto exporter by sending special spans (#56) * Use http/proto exporter instead of grpc to reduce the cost of loading libraries * Disable tracing/metrics of http exporter * Warm up http/proto exporter by sending special spans --- nodejs/packages/cx-wrapper/index.ts | 24 +++++++++++++++++++-- nodejs/packages/cx-wrapper/provider-init.ts | 6 ++++-- nodejs/packages/layer/package-lock.json | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/nodejs/packages/cx-wrapper/index.ts b/nodejs/packages/cx-wrapper/index.ts index d26df611fe..0285b264c1 100644 --- a/nodejs/packages/cx-wrapper/index.ts +++ b/nodejs/packages/cx-wrapper/index.ts @@ -10,25 +10,45 @@ import { load } from './loader.js'; import { initializeInstrumentations } from './instrumentation-init.js'; import { initializeProvider } from './provider-init.js'; import { makeLambdaInstrumentation } from './lambda-instrumentation-init.js'; +import { parseBooleanEnvvar } from './common.js'; const instrumentations = initializeInstrumentations(); -initializeProvider(instrumentations); +const tracerProvider = initializeProvider(instrumentations); const lambdaInstrumentation = makeLambdaInstrumentation(); if (process.env.CX_ORIGINAL_HANDLER === undefined) throw Error('CX_ORIGINAL_HANDLER is missing'); // We want user code to get initialized during lambda init phase -diag.debug(`Initialization: Loading original handler ${process.env.CX_ORIGINAL_HANDLER}`); try { (async () => { + diag.debug(`Initialization: Loading original handler ${process.env.CX_ORIGINAL_HANDLER}`); await load( process.env.LAMBDA_TASK_ROOT, process.env.CX_ORIGINAL_HANDLER ); + diag.debug(`Initialization: Original handler loaded`); })(); } catch (e) {} +if (parseBooleanEnvvar("OTEL_WARM_UP_EXPORTER") ?? true) { + // We want exporter code to get initialized during lambda init phase + try { + (async () => { + try { + diag.debug(`Initialization: warming up exporter`); + const warmupSpan = tracerProvider.getTracer('cx-wrapper').startSpan('warmup'); + warmupSpan.setAttribute('cx.internal.span.role', 'warmup'); + warmupSpan.end(); + await tracerProvider.forceFlush(); + diag.debug(`Initialization: exporter warmed up`); + } catch (e) { + diag.error(`Initialization: exporter warmup failed: ${e}`); + } + })(); + } catch (e) {} +} + export const handler = (event: any, context: Context, callback: Callback) => { diag.debug(`Loading original handler ${process.env.CX_ORIGINAL_HANDLER}`); load( diff --git a/nodejs/packages/cx-wrapper/provider-init.ts b/nodejs/packages/cx-wrapper/provider-init.ts index dd01344b7d..17f35bbeb4 100644 --- a/nodejs/packages/cx-wrapper/provider-init.ts +++ b/nodejs/packages/cx-wrapper/provider-init.ts @@ -22,7 +22,7 @@ declare global { const DEFAULT_OTEL_EXPORT_TIMEOUT = 2000; // this is a localhost call, and we don't want to block the function for too long -export function initializeProvider(instrumentations: any[]): void { +export function initializeProvider(instrumentations: any[]): NodeTracerProvider { diag.debug('Initializing OpenTelemetry providers'); const export_timeout = parseIntEnvvar("OTEL_EXPORT_TIMEOUT") ?? DEFAULT_OTEL_EXPORT_TIMEOUT; @@ -106,4 +106,6 @@ export function initializeProvider(instrumentations: any[]): void { tracerProvider, meterProvider }); -} \ No newline at end of file + + return tracerProvider +} diff --git a/nodejs/packages/layer/package-lock.json b/nodejs/packages/layer/package-lock.json index 10dabc1626..9895f67d01 100644 --- a/nodejs/packages/layer/package-lock.json +++ b/nodejs/packages/layer/package-lock.json @@ -788,7 +788,7 @@ "node_modules/cx-wrapper": { "version": "0.0.1", "resolved": "file:../cx-wrapper/cx-wrapper-0.0.1.tgz", - "integrity": "sha512-yq8alkohZzFLDOjgM/1FBlLwBQf4+M0+jM7yrVeabMnHrcFdeyyJNyj1wuAXxaYfLXwFwnaYN3HndvxvzD5FTA==", + "integrity": "sha512-dXU/aOLoYO7DM6bkdoIZ81c2cF/UJ+u/CeC1H2aE2WoayMTvkZp7apBHE3HrYrktF14MGkXxxJrskGCzH6oPoA==", "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/auto-configuration-propagators": "0.3.0",