From 2276e4fdc63ed4b46640a9f1bb6fee8cf473ebe7 Mon Sep 17 00:00:00 2001 From: Vera Reynolds Date: Wed, 30 Jun 2021 07:09:39 -0600 Subject: [PATCH] feat: otlp-grpc exporter uses headers environment variables (#2304) * feat: otlp-grpc exporter uses headers environment variables * chore: smaller import radius Co-authored-by: Valentin Marchaud Co-authored-by: Daniel Dyla --- .../src/CollectorExporterNodeBase.ts | 10 ++++++++-- .../src/CollectorMetricExporter.ts | 12 +++++++++++- .../src/CollectorTraceExporter.ts | 13 ++++++++++++- .../test/CollectorMetricExporter.test.ts | 19 +++++++++++++++++++ .../test/CollectorTraceExporter.test.ts | 19 +++++++++++++++++++ 5 files changed, 69 insertions(+), 4 deletions(-) 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 });