diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index b40f630371..58eb1baf63 100644 --- a/packages/opentelemetry-context-async-hooks/package.json +++ b/packages/opentelemetry-context-async-hooks/package.json @@ -44,7 +44,7 @@ "@types/mocha": "8.2.2", "@types/node": "14.14.43", "@types/shimmer": "1.0.1", - "codecov": "^3.8.2", + "codecov": "3.8.2", "mocha": "7.2.0", "nyc": "15.1.0", "rimraf": "3.0.2", diff --git a/packages/opentelemetry-exporter-collector-grpc/src/CollectorExporterNodeBase.ts b/packages/opentelemetry-exporter-collector-grpc/src/CollectorExporterNodeBase.ts index c01264cb94..0c14f0063b 100644 --- a/packages/opentelemetry-exporter-collector-grpc/src/CollectorExporterNodeBase.ts +++ b/packages/opentelemetry-exporter-collector-grpc/src/CollectorExporterNodeBase.ts @@ -19,13 +19,14 @@ import { CollectorExporterBase, collectorTypes, } from '@opentelemetry/exporter-collector'; -import type { Metadata } from '@grpc/grpc-js'; +import { Metadata } from '@grpc/grpc-js'; import { CollectorExporterConfigNode, GRPCQueueItem, ServiceClientType, } from './types'; import { ServiceClient } from './types'; +import { getEnv, baggageUtils } from "@opentelemetry/core"; /** * Collector Metric Exporter abstract base class @@ -48,8 +49,13 @@ export abstract class CollectorExporterNodeBase< if (config.headers) { diag.warn('Headers cannot be set when using grpc'); } - this.metadata = config.metadata; + const headers = baggageUtils.parseKeyPairsIntoRecord(getEnv().OTEL_EXPORTER_OTLP_HEADERS); + this.metadata = config.metadata || new Metadata(); + for (const [k, v] of Object.entries(headers)) { + this.metadata.set(k, v) + } } + private _sendPromise( objects: ExportItem[], onSuccess: () => void, diff --git a/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts b/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts index 84a880c16d..c909241a73 100644 --- a/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts +++ b/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts @@ -21,8 +21,9 @@ import { import { MetricRecord, MetricExporter } from '@opentelemetry/metrics'; import { CollectorExporterConfigNode, ServiceClientType } from './types'; import { CollectorExporterNodeBase } from './CollectorExporterNodeBase'; -import { getEnv } from '@opentelemetry/core'; +import { baggageUtils, getEnv } from '@opentelemetry/core'; import { validateAndNormalizeUrl } from './util'; +import { Metadata } from "@grpc/grpc-js"; const DEFAULT_COLLECTOR_URL = 'localhost:4317'; @@ -38,6 +39,15 @@ export class CollectorMetricExporter // Converts time to nanoseconds protected readonly _startTime = new Date().getTime() * 1000000; + constructor(config: CollectorExporterConfigNode = {}) { + super(config); + const headers = baggageUtils.parseKeyPairsIntoRecord(getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS); + this.metadata ||= new Metadata(); + for (const [k, v] of Object.entries(headers)) { + this.metadata.set(k, v) + } + } + convert( metrics: MetricRecord[] ): collectorTypes.opentelemetryProto.collector.metrics.v1.ExportMetricsServiceRequest { diff --git a/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts index aae731d10c..f0b63cbb79 100644 --- a/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts @@ -21,8 +21,9 @@ import { toCollectorExportTraceServiceRequest, } from '@opentelemetry/exporter-collector'; import { CollectorExporterConfigNode, ServiceClientType } from './types'; -import { getEnv } from '@opentelemetry/core'; +import { baggageUtils, getEnv } from '@opentelemetry/core'; import { validateAndNormalizeUrl } from './util'; +import { Metadata } from "@grpc/grpc-js"; const DEFAULT_COLLECTOR_URL = 'localhost:4317'; @@ -35,6 +36,16 @@ export class CollectorTraceExporter collectorTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest > implements SpanExporter { + + constructor(config: CollectorExporterConfigNode = {}) { + super(config); + const headers = baggageUtils.parseKeyPairsIntoRecord(getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS); + this.metadata ||= new Metadata(); + for (const [k, v] of Object.entries(headers)) { + this.metadata.set(k, v) + } + } + convert( spans: ReadableSpan[] ): collectorTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { diff --git a/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts index a0cb218a7e..f765c250cb 100644 --- a/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts @@ -278,6 +278,25 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); + it('should use headers defined via env', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; + const collectorExporter = new CollectorMetricExporter(); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']); + envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; + }); + it('should override global headers config with signal headers defined via env', () => { + const metadata = new grpc.Metadata(); + metadata.set('foo', 'bar'); + metadata.set('goo', 'lol'); + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=jar,bar=foo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; + const collectorExporter = new CollectorMetricExporter({ metadata }); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['boo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['foo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['lol']); + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; + envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; + }); }); testCollectorMetricExporter({ useTLS: true }); diff --git a/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts index 1c91cae6a7..bd498b6de3 100644 --- a/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts @@ -240,6 +240,25 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); + it('should use headers defined via env', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; + const collectorExporter = new CollectorTraceExporter(); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']); + envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; + }); + it('should override global headers config with signal headers defined via env', () => { + const metadata = new grpc.Metadata(); + metadata.set('foo', 'bar'); + metadata.set('goo', 'lol'); + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=jar,bar=foo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo'; + const collectorExporter = new CollectorTraceExporter({ metadata }); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['boo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['foo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['lol']); + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; + envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; + }); }); testCollectorExporter({ useTLS: true }); diff --git a/packages/opentelemetry-propagator-b3/src/B3Propagator.ts b/packages/opentelemetry-propagator-b3/src/B3Propagator.ts index 597873e36d..760752d84b 100644 --- a/packages/opentelemetry-propagator-b3/src/B3Propagator.ts +++ b/packages/opentelemetry-propagator-b3/src/B3Propagator.ts @@ -61,7 +61,10 @@ export class B3Propagator implements TextMapPropagator { } extract(context: Context, carrier: unknown, getter: TextMapGetter): Context { - if (getter.get(carrier, B3_CONTEXT_HEADER)) { + const header = getter.get(carrier, B3_CONTEXT_HEADER); + const b3Context = Array.isArray(header) ? header[0] : header; + + if (b3Context) { return this._b3SinglePropagator.extract(context, carrier, getter); } else { return this._b3MultiPropagator.extract(context, carrier, getter); diff --git a/packages/opentelemetry-propagator-b3/test/B3Propagator.test.ts b/packages/opentelemetry-propagator-b3/test/B3Propagator.test.ts index 6efec8336a..6e5a7b4a7c 100644 --- a/packages/opentelemetry-propagator-b3/test/B3Propagator.test.ts +++ b/packages/opentelemetry-propagator-b3/test/B3Propagator.test.ts @@ -152,6 +152,31 @@ describe('B3Propagator', () => { }); }); + it('extracts multi header b3 using array getter', () => { + const context = propagator.extract( + ROOT_CONTEXT, + b3MultiCarrier, + { + get(carrier, key) { + if (carrier == null || carrier[key] === undefined) { + return []; + } + return [carrier[key]]; + }, + + keys: defaultTextMapGetter.keys + } + ); + + const extractedSpanContext = trace.getSpanContext(context); + assert.deepStrictEqual(extractedSpanContext, { + spanId: '6e0c63257de34c92', + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + isRemote: true, + traceFlags: TraceFlags.SAMPLED, + }); + }); + it('extracts single header over multi', () => { const context = propagator.extract( ROOT_CONTEXT, diff --git a/renovate.json b/renovate.json index debd9bceb4..208c80be86 100644 --- a/renovate.json +++ b/renovate.json @@ -9,6 +9,11 @@ { "matchPackageNames": ["@opentelemetry/api"], "rangeStrategy": "bump" + }, + { + "matchPaths": ["backwards-compatibility/**"], + "matchPackageNames": ["@types/node"], + "enabled": false } ], "ignoreDeps": ["gcp-metadata", "got", "mocha", "husky", "karma-webpack"],