From 1e3c5de17cfe7441910188ba7d0ff1ca2085404e Mon Sep 17 00:00:00 2001 From: jjllee Date: Mon, 30 Sep 2024 17:36:39 -0700 Subject: [PATCH] avoid unwanted OTel log when OTEL_TRACES_SAMPLER = `xray` --- .../src/aws-opentelemetry-configurator.ts | 59 ++++++++++--------- .../src/register.ts | 25 ++++++-- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts index bdd0daee..52281a66 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts @@ -104,7 +104,7 @@ export class AwsOpentelemetryConfigurator { * @constructor * @param {Instrumentation[]} instrumentations - Auto-Instrumentations to be added to the ADOT Config */ - public constructor(instrumentations: Instrumentation[]) { + public constructor(instrumentations: Instrumentation[], useXraySampler: boolean = false) { /* * Set and Detect Resources via Resource Detectors * @@ -167,7 +167,9 @@ export class AwsOpentelemetryConfigurator { // https://github.com/aws-observability/aws-otel-java-instrumentation/blob/a011b8cc29ee32b7f668c04ccfdf64cd30de467c/awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsTracerCustomizerProvider.java#L36 this.idGenerator = new AWSXRayIdGenerator(); - this.sampler = AwsOpentelemetryConfigurator.customizeSampler(customBuildSamplerFromEnv(this.resource)); + this.sampler = AwsOpentelemetryConfigurator.customizeSampler( + customBuildSamplerFromEnv(this.resource, useXraySampler) + ); // default SpanProcessors with Span Exporters wrapped inside AwsMetricAttributesSpanExporter const awsSpanProcessorProvider: AwsSpanProcessorProvider = new AwsSpanProcessorProvider(this.resource); @@ -291,37 +293,36 @@ export class AwsOpentelemetryConfigurator { } } -export function customBuildSamplerFromEnv(resource: Resource): Sampler { - switch (process.env.OTEL_TRACES_SAMPLER) { - case 'xray': { - const samplerArgumentEnv: string | undefined = process.env.OTEL_TRACES_SAMPLER_ARG; - let endpoint: string | undefined = undefined; - let pollingInterval: number | undefined = undefined; - - if (samplerArgumentEnv !== undefined) { - const args: string[] = samplerArgumentEnv.split(','); - for (const arg of args) { - const equalIndex: number = arg.indexOf('='); - if (equalIndex === -1) { - continue; - } - const keyValue: string[] = [arg.substring(0, equalIndex), arg.substring(equalIndex + 1)]; - if (keyValue[0] === 'endpoint') { - endpoint = keyValue[1]; - } else if (keyValue[0] === 'polling_interval') { - pollingInterval = Number(keyValue[1]); - if (isNaN(pollingInterval)) { - pollingInterval = undefined; - diag.error('polling_interval in OTEL_TRACES_SAMPLER_ARG must be a valid number'); - } +export function customBuildSamplerFromEnv(resource: Resource, useXraySampler: boolean = false): Sampler { + if (useXraySampler || process.env.OTEL_TRACES_SAMPLER === 'xray') { + const samplerArgumentEnv: string | undefined = process.env.OTEL_TRACES_SAMPLER_ARG; + let endpoint: string | undefined = undefined; + let pollingInterval: number | undefined = undefined; + + if (samplerArgumentEnv !== undefined) { + const args: string[] = samplerArgumentEnv.split(','); + for (const arg of args) { + const equalIndex: number = arg.indexOf('='); + if (equalIndex === -1) { + continue; + } + const keyValue: string[] = [arg.substring(0, equalIndex), arg.substring(equalIndex + 1)]; + if (keyValue[0] === 'endpoint') { + endpoint = keyValue[1]; + } else if (keyValue[0] === 'polling_interval') { + pollingInterval = Number(keyValue[1]); + if (isNaN(pollingInterval)) { + pollingInterval = undefined; + diag.error('polling_interval in OTEL_TRACES_SAMPLER_ARG must be a valid number'); } } } - - diag.debug(`XRay Sampler Endpoint: ${endpoint}`); - diag.debug(`XRay Sampler Polling Interval: ${pollingInterval}`); - return new AwsXRayRemoteSampler({ resource: resource, endpoint: endpoint, pollingInterval: pollingInterval }); } + + diag.info('AWS XRay Sampler enabled'); + diag.debug(`XRay Sampler Endpoint: ${endpoint}`); + diag.debug(`XRay Sampler Polling Interval: ${pollingInterval}`); + return new AwsXRayRemoteSampler({ resource: resource, endpoint: endpoint, pollingInterval: pollingInterval }); } return buildSamplerFromEnv(); diff --git a/aws-distro-opentelemetry-node-autoinstrumentation/src/register.ts b/aws-distro-opentelemetry-node-autoinstrumentation/src/register.ts index b1bb6339..aed378d0 100644 --- a/aws-distro-opentelemetry-node-autoinstrumentation/src/register.ts +++ b/aws-distro-opentelemetry-node-autoinstrumentation/src/register.ts @@ -2,7 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 // Modifications Copyright The OpenTelemetry Authors. Licensed under the Apache License 2.0 License. -import { DiagConsoleLogger, diag, trace } from '@opentelemetry/api'; +// Short-term workaround to avoid Upsteam OTel emitting logs such as: +// - `OTEL_TRACES_SAMPLER value "xray invalid, defaulting to always_on".` +// OTel dependencies will always load a default Sampler configuration. Although unused, that +// load process will read the `OTEL_TRACES_SAMPLER` value and may emit the above log, which is +// unwanted for `xray` value. Thus we temporarily remove this env var to avoid the unwanted log. +let useXraySampler = false; +if (process.env.OTEL_TRACES_SAMPLER === 'xray') { + delete process.env.OTEL_TRACES_SAMPLER; + useXraySampler = true; +} + +import { diag, DiagConsoleLogger, trace } from '@opentelemetry/api'; import { getNodeAutoInstrumentations, InstrumentationConfigMap } from '@opentelemetry/auto-instrumentations-node'; import { Instrumentation } from '@opentelemetry/instrumentation'; import * as opentelemetry from '@opentelemetry/sdk-node'; @@ -56,7 +67,7 @@ const instrumentations: Instrumentation[] = getNodeAutoInstrumentations(instrume // Apply instrumentation patches applyInstrumentationPatches(instrumentations); -const configurator: AwsOpentelemetryConfigurator = new AwsOpentelemetryConfigurator(instrumentations); +const configurator: AwsOpentelemetryConfigurator = new AwsOpentelemetryConfigurator(instrumentations, useXraySampler); const configuration: Partial = configurator.configure(); const sdk: opentelemetry.NodeSDK = new opentelemetry.NodeSDK(configuration); @@ -67,14 +78,15 @@ const sdk: opentelemetry.NodeSDK = new opentelemetry.NodeSDK(configuration); // we wish to make contributions to upstream to improve customizability of the Node auto-instrumentation. try { sdk.start(); + + diag.info('Setting TraceProvider for instrumentations at the end of initialization'); for (const instrumentation of instrumentations) { - diag.info('Set TraceProvider for instrumentations at the end of initialization'); instrumentation.setTracerProvider(trace.getTracerProvider()); } - diag.info('AWS Distro of OpenTelemetry automatic instrumentation started successfully'); diag.debug(`Environment variable OTEL_PROPAGATORS is set to '${process.env.OTEL_PROPAGATORS}'`); diag.debug(`Environment variable OTEL_EXPORTER_OTLP_PROTOCOL is set to '${process.env.OTEL_EXPORTER_OTLP_PROTOCOL}'`); + diag.info('AWS Distro of OpenTelemetry automatic instrumentation started successfully'); } catch (error) { diag.error( 'Error initializing AWS Distro of OpenTelemetry SDK. Your application is not instrumented and will not produce telemetry', @@ -90,3 +102,8 @@ process.on('SIGTERM', () => { }); // END The OpenTelemetry Authors code + +// Respect original `OTEL_TRACES_SAMPLER` as we previously deleted it temporarily for value `xray` +if (useXraySampler) { + process.env.OTEL_TRACES_SAMPLER = 'xray'; +}