From 75c03912e12a5b9773aabba58becf05de6f608a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 16:57:58 +0800 Subject: [PATCH 01/12] Revert "feat(otlp-metric-exporters): Add User-Agent header to OTLP metric exporters (#3806)" This reverts commit 6a876a053fdcaeea20e53c2fa0d829c8a6819826. --- .../src/OTLPMetricExporter.ts | 15 +++------------ .../test/OTLPMetricExporter.test.ts | 8 -------- .../src/platform/node/OTLPMetricExporter.ts | 15 +++++---------- .../test/node/CollectorMetricExporter.test.ts | 8 -------- .../src/OTLPMetricExporter.ts | 15 +++++---------- .../test/OTLPMetricExporter.test.ts | 11 ----------- 6 files changed, 13 insertions(+), 59 deletions(-) diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts index 0ada75d4375..20f917e5439 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts @@ -32,11 +32,6 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from './version'; - -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase< ResourceMetrics, @@ -44,13 +39,9 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase< > { constructor(config?: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions) { super(config); - const headers = { - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ), - }; - + 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); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts index 9e4e27ecb0a..4b8d3265459 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts @@ -43,7 +43,6 @@ import { IExportMetricsServiceRequest, IResourceMetrics, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../src/version'; const metricsServiceProtoPath = 'opentelemetry/proto/collector/metrics/v1/metrics_service.proto'; @@ -315,13 +314,6 @@ describe('when configuring via environment', () => { ); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should include user agent in header', () => { - const collectorExporter = new OTLPMetricExporter(); - assert.deepStrictEqual( - collectorExporter._otlpExporter.metadata?.get('User-Agent'), - [`OTel-OTLP-Exporter-JavaScript/${VERSION}`] - ); - }); it('should override global headers config with signal headers defined via env', () => { const metadata = new grpc.Metadata(); metadata.set('foo', 'bar'); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts index f83e414e701..980931a6cb0 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts @@ -28,13 +28,9 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../version'; const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/metrics'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; class OTLPExporterNodeProxy extends OTLPExporterNodeBase< ResourceMetrics, @@ -42,13 +38,12 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase< > { constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) { super(config); - this.headers = { - ...this.headers, - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( + this.headers = Object.assign( + this.headers, + baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ), - }; + ) + ); } convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts index 042e5ebb4be..d23ca628f70 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -50,7 +50,6 @@ import { OTLPExporterNodeConfigBase, } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -189,13 +188,6 @@ describe('OTLPMetricExporter - node with json over http', () => { assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should include user agent in header', () => { - const collectorExporter = new OTLPMetricExporter(); - assert.strictEqual( - collectorExporter._otlpExporter.headers['User-Agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should override global headers config with signal headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts index 8d1fb114b3f..c29ae0085ca 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts @@ -31,13 +31,9 @@ import { createExportMetricsServiceRequest, IExportMetricsServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from './version'; const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/metrics'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase< ResourceMetrics, @@ -45,13 +41,12 @@ class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase< > { constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) { super(config); - this.headers = { - ...this.headers, - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( + this.headers = Object.assign( + this.headers, + baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ), - }; + ) + ); } convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts index d3270b6a9f3..05ca183dcc8 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts @@ -46,7 +46,6 @@ import { OTLPMetricExporterOptions } from '@opentelemetry/exporter-metrics-otlp- import { Stream, PassThrough } from 'stream'; import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../src/version'; let fakeRequest: PassThrough; @@ -61,16 +60,6 @@ describe('OTLPMetricExporter - node with proto over http', () => { sinon.restore(); }); - describe('default behavior for headers', () => { - const collectorExporter = new OTLPMetricExporter(); - it('should include user agent in header', () => { - assert.strictEqual( - collectorExporter._otlpExporter.headers['User-Agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); - }); - describe('when configuring via environment', () => { const envSource = process.env; it('should use url defined in env that ends with root path and append version and signal path', () => { From 8592a088ea8491f4303b82b0ac7f2f2f16181105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 14:36:54 +0800 Subject: [PATCH 02/12] Revert "feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters (#3790)" This reverts commit 758c7af0c183b36bbce0b0dfbda3dd43bdc0ca8d. --- .../src/OTLPTraceExporter.ts | 14 +++----------- .../test/OTLPTraceExporter.test.ts | 7 ------- .../src/platform/node/OTLPTraceExporter.ts | 15 +++++---------- .../test/node/CollectorTraceExporter.test.ts | 8 -------- .../src/platform/node/OTLPTraceExporter.ts | 15 +++++---------- .../test/node/OTLPTraceExporter.test.ts | 11 ----------- 6 files changed, 13 insertions(+), 57 deletions(-) diff --git a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts index c99826a176f..2cc5abcb2e8 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts @@ -28,11 +28,6 @@ import { createExportTraceServiceRequest, IExportTraceServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from './version'; - -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; /** * OTLP Trace Exporter for Node @@ -43,12 +38,9 @@ export class OTLPTraceExporter { constructor(config: OTLPGRPCExporterConfigNode = {}) { super(config); - const headers = { - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ), - }; + 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); diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts index 17e55110105..29c080b9660 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts @@ -27,7 +27,6 @@ import * as grpc from '@grpc/grpc-js'; import * as path from 'path'; import * as sinon from 'sinon'; import { OTLPTraceExporter } from '../src'; -import { VERSION } from '../src/version'; import { ensureExportedSpanIsCorrect, @@ -337,12 +336,6 @@ describe('when configuring via environment', () => { assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should include user agent in header', () => { - const collectorExporter = new OTLPTraceExporter(); - assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ - `OTel-OTLP-Exporter-JavaScript/${VERSION}`, - ]); - }); it('should override global headers config with signal headers defined via env', () => { const metadata = new grpc.Metadata(); metadata.set('foo', 'bar'); diff --git a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts index f10fbd0ec0a..8704baf5769 100644 --- a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts @@ -26,13 +26,9 @@ import { createExportTraceServiceRequest, IExportTraceServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../version'; const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/traces'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; /** * Collector Trace Exporter for Node @@ -43,13 +39,12 @@ export class OTLPTraceExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { super(config); - this.headers = { - ...this.headers, - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( + this.headers = Object.assign( + this.headers, + baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ), - }; + ) + ); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { diff --git a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts index 9238260d309..426aed4431f 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts @@ -36,7 +36,6 @@ import { import { nextTick } from 'process'; import { MockedResponse } from './nodeHelpers'; import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -161,13 +160,6 @@ describe('OTLPTraceExporter - node with json over http', () => { assert.strictEqual(collectorExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should include user agent in header', () => { - const collectorExporter = new OTLPTraceExporter(); - assert.strictEqual( - collectorExporter.headers['User-Agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should override global headers config with signal headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo'; diff --git a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts index 210a16145a5..0634013311e 100644 --- a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts @@ -29,13 +29,9 @@ import { createExportTraceServiceRequest, IExportTraceServiceRequest, } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../version'; const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/traces'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`; -const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, -}; /** * Collector Trace Exporter for Node with protobuf @@ -46,13 +42,12 @@ export class OTLPTraceExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { super(config); - this.headers = { - ...this.headers, - ...USER_AGENT, - ...baggageUtils.parseKeyPairsIntoRecord( + this.headers = Object.assign( + this.headers, + baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ), - }; + ) + ); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { diff --git a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts index c0a604ce90b..64f0e40ea0e 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts @@ -39,7 +39,6 @@ import { ServiceClientType, } from '@opentelemetry/otlp-proto-exporter-base'; import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; -import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -53,16 +52,6 @@ describe('OTLPTraceExporter - node with proto over http', () => { sinon.restore(); }); - describe('default behavior for headers', () => { - const collectorExporter = new OTLPTraceExporter(); - it('should include user agent in header', () => { - assert.strictEqual( - collectorExporter.headers['User-Agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); - }); - describe('when configuring via environment', () => { const envSource = process.env; it('should use url defined in env that ends with root path and append version and signal path', () => { From 0fca00ec3fae6aa62fde274fd12ea360bfd32a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 16:44:51 +0800 Subject: [PATCH 03/12] feat(otlp-exporter): add `user-agent` header to otlp exporters and remove `sendBeacon` which does not support custom headers --- .../browser/OTLPExporterBrowserBase.ts | 61 ++++++------- .../src/platform/browser/util.ts | 47 ++-------- .../src/platform/node/OTLPExporterNodeBase.ts | 24 ++++-- .../packages/otlp-exporter-base/src/util.ts | 5 ++ .../test/browser/util.test.ts | 86 ------------------- .../src/OTLPGRPCExporterNodeBase.ts | 10 ++- .../otlp-grpc-exporter-base/src/util.ts | 3 + 7 files changed, 70 insertions(+), 166 deletions(-) diff --git a/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts b/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts index 57556d81a58..6b6de76d2be 100644 --- a/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts +++ b/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts @@ -17,39 +17,42 @@ import { OTLPExporterBase } from '../../OTLPExporterBase'; import { OTLPExporterConfigBase } from '../../types'; import * as otlpTypes from '../../types'; -import { parseHeaders } from '../../util'; -import { sendWithBeacon, sendWithXhr } from './util'; +import { USER_AGENT, parseHeaders } from '../../util'; +import { sendWithXhr } from './util'; import { diag } from '@opentelemetry/api'; import { getEnv, baggageUtils } from '@opentelemetry/core'; /** - * Collector Metric Exporter abstract base class + * OTLP Exporter abstract base class */ export abstract class OTLPExporterBrowserBase< ExportItem, ServiceRequest > extends OTLPExporterBase { protected _headers: Record; - private _useXHR: boolean = false; /** * @param config */ constructor(config: OTLPExporterConfigBase = {}) { super(config); - this._useXHR = - !!config.headers || typeof navigator.sendBeacon !== 'function'; - if (this._useXHR) { - this._headers = Object.assign( - {}, - parseHeaders(config.headers), - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_HEADERS - ) - ); - } else { - this._headers = {}; + + const headersBeforeUserAgent = { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_HEADERS + ), + ...parseHeaders(config.headers), + }; + if ( + Object.keys(headersBeforeUserAgent) + .map(key => key.toLowerCase()) + .includes('user-agent') + ) { + diag.warn('User-Agent header should not be set via config.'); } + this._headers = Object.assign(headersBeforeUserAgent, USER_AGENT); } onInit(): void { @@ -73,24 +76,14 @@ export abstract class OTLPExporterBrowserBase< const body = JSON.stringify(serviceRequest); const promise = new Promise((resolve, reject) => { - if (this._useXHR) { - sendWithXhr( - body, - this.url, - this._headers, - this.timeoutMillis, - resolve, - reject - ); - } else { - sendWithBeacon( - body, - this.url, - { type: 'application/json' }, - resolve, - reject - ); - } + sendWithXhr( + body, + this.url, + this._headers, + this.timeoutMillis, + resolve, + reject + ); }).then(onSuccess, onError); this._sendingPromises.push(promise); diff --git a/experimental/packages/otlp-exporter-base/src/platform/browser/util.ts b/experimental/packages/otlp-exporter-base/src/platform/browser/util.ts index fade4afa88b..e2d25deae30 100644 --- a/experimental/packages/otlp-exporter-base/src/platform/browser/util.ts +++ b/experimental/packages/otlp-exporter-base/src/platform/browser/util.ts @@ -24,30 +24,6 @@ import { parseRetryAfterToMills, } from '../../util'; -/** - * Send metrics/spans using browser navigator.sendBeacon - * @param body - * @param url - * @param blobPropertyBag - * @param onSuccess - * @param onError - */ -export function sendWithBeacon( - body: string, - url: string, - blobPropertyBag: BlobPropertyBag, - onSuccess: () => void, - onError: (error: OTLPExporterError) => void -): void { - if (navigator.sendBeacon(url, new Blob([body], blobPropertyBag))) { - diag.debug('sendBeacon - can send', body); - onSuccess(); - } else { - const error = new OTLPExporterError(`sendBeacon - cannot send ${body}`); - onError(error); - } -} - /** * function to send metrics/spans using browser XMLHttpRequest * used when navigator.sendBeacon is not available @@ -88,16 +64,12 @@ export function sendWithXhr( xhr = new XMLHttpRequest(); xhr.open('POST', url); - const defaultHeaders = { - Accept: 'application/json', - 'Content-Type': 'application/json', - }; - - Object.entries({ - ...defaultHeaders, - ...headers, - }).forEach(([k, v]) => { - xhr.setRequestHeader(k, v); + Object.entries(headers).forEach(([k, v]) => { + try { + xhr.setRequestHeader(k, v); + } catch (e) { + // Chrome will throw an error on setting user-agent, ignore it. + } }); xhr.send(body); @@ -114,10 +86,9 @@ export function sendWithXhr( minDelay = DEFAULT_EXPORT_BACKOFF_MULTIPLIER * minDelay; // retry after interval specified in Retry-After header - if (xhr.getResponseHeader('Retry-After')) { - retryTime = parseRetryAfterToMills( - xhr.getResponseHeader('Retry-After')! - ); + const retryAfter = xhr.getResponseHeader('Retry-After'); + if (retryAfter) { + retryTime = parseRetryAfterToMills(retryAfter); } else { // exponential backoff with jitter retryTime = Math.round( diff --git a/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts b/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts index 088a0fd0a02..2d19b472bad 100644 --- a/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts +++ b/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts @@ -20,13 +20,13 @@ import type * as https from 'https'; import { OTLPExporterBase } from '../../OTLPExporterBase'; import { OTLPExporterNodeConfigBase, CompressionAlgorithm } from './types'; import * as otlpTypes from '../../types'; -import { parseHeaders } from '../../util'; +import { USER_AGENT, parseHeaders } from '../../util'; import { createHttpAgent, sendWithHttp, configureCompression } from './util'; import { diag } from '@opentelemetry/api'; import { getEnv, baggageUtils } from '@opentelemetry/core'; /** - * Collector Metric Exporter abstract base class + * OTLP Exporter abstract base class */ export abstract class OTLPExporterNodeBase< ExportItem, @@ -47,11 +47,21 @@ export abstract class OTLPExporterNodeBase< if ((config as any).metadata) { diag.warn('Metadata cannot be set when using http'); } - this.headers = Object.assign( - this.DEFAULT_HEADERS, - parseHeaders(config.headers), - baggageUtils.parseKeyPairsIntoRecord(getEnv().OTEL_EXPORTER_OTLP_HEADERS) - ); + const headersBeforeUserAgent = { + ...this.DEFAULT_HEADERS, + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_HEADERS + ), + ...parseHeaders(config.headers), + }; + if ( + Object.keys(headersBeforeUserAgent) + .map(key => key.toLowerCase()) + .includes('user-agent') + ) { + diag.warn('User-Agent header should not be set via config.'); + } + this.headers = Object.assign(headersBeforeUserAgent, USER_AGENT); this.agent = createHttpAgent(config); this.compression = configureCompression(config.compression); } diff --git a/experimental/packages/otlp-exporter-base/src/util.ts b/experimental/packages/otlp-exporter-base/src/util.ts index f5dc70c9e88..1fd226a7603 100644 --- a/experimental/packages/otlp-exporter-base/src/util.ts +++ b/experimental/packages/otlp-exporter-base/src/util.ts @@ -16,6 +16,7 @@ import { diag } from '@opentelemetry/api'; import { getEnv } from '@opentelemetry/core'; +import { VERSION } from './version'; const DEFAULT_TRACE_TIMEOUT = 10000; export const DEFAULT_EXPORT_MAX_ATTEMPTS = 5; @@ -23,6 +24,10 @@ export const DEFAULT_EXPORT_INITIAL_BACKOFF = 1000; export const DEFAULT_EXPORT_MAX_BACKOFF = 5000; export const DEFAULT_EXPORT_BACKOFF_MULTIPLIER = 1.5; +export const USER_AGENT = { + 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, +}; + /** * Parses headers from config leaving only those that have defined values * @param partialHeaders diff --git a/experimental/packages/otlp-exporter-base/test/browser/util.test.ts b/experimental/packages/otlp-exporter-base/test/browser/util.test.ts index 1dd3b77d588..081a7b3346e 100644 --- a/experimental/packages/otlp-exporter-base/test/browser/util.test.ts +++ b/experimental/packages/otlp-exporter-base/test/browser/util.test.ts @@ -39,83 +39,13 @@ describe('util - browser', () => { }); describe('when XMLHTTPRequest is used', () => { - let expectedHeaders: Record; let clock: sinon.SinonFakeTimers; beforeEach(() => { // fakeTimers is used to replace the next setTimeout which is // located in sendWithXhr function called by the export method clock = sinon.useFakeTimers(); - - expectedHeaders = { - // ;charset=utf-8 is applied by sinon.fakeServer - 'Content-Type': 'application/json;charset=utf-8', - Accept: 'application/json', - }; - }); - describe('and Content-Type header is set', () => { - beforeEach(() => { - const explicitContentType = { - 'Content-Type': 'application/json', - }; - const exporterTimeout = 10000; - sendWithXhr( - body, - url, - explicitContentType, - exporterTimeout, - onSuccessStub, - onErrorStub - ); - }); - it('Request Headers should contain "Content-Type" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); - it('Request Headers should contain "Accept" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); }); - describe('and empty headers are set', () => { - beforeEach(() => { - const emptyHeaders = {}; - // use default exporter timeout - const exporterTimeout = 10000; - sendWithXhr( - body, - url, - emptyHeaders, - exporterTimeout, - onSuccessStub, - onErrorStub - ); - }); - it('Request Headers should contain "Content-Type" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); - it('Request Headers should contain "Accept" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); - }); describe('and custom headers are set', () => { let customHeaders: Record; beforeEach(() => { @@ -130,22 +60,6 @@ describe('util - browser', () => { onErrorStub ); }); - it('Request Headers should contain "Content-Type" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); - it('Request Headers should contain "Accept" header', done => { - nextTick(() => { - const { requestHeaders } = server.requests[0]; - ensureHeadersContain(requestHeaders, expectedHeaders); - clock.restore(); - done(); - }); - }); it('Request Headers should contain custom headers', done => { nextTick(() => { const { requestHeaders } = server.requests[0]; diff --git a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts index 884505daa86..87964e56320 100644 --- a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts +++ b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts @@ -23,7 +23,11 @@ import { } from './types'; import { ServiceClient } from './types'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -import { configureCompression, GrpcCompressionAlgorithm } from './util'; +import { + configureCompression, + GrpcCompressionAlgorithm, + USER_AGENT, +} from './util'; import { OTLPExporterBase, OTLPExporterError, @@ -58,6 +62,10 @@ export abstract class OTLPGRPCExporterNodeBase< for (const [k, v] of Object.entries(headers)) { this.metadata.set(k, v); } + if (this.metadata.get('user-agent')) { + diag.warn('User-Agent header should not be set via config.'); + } + this.metadata.set('user-agent', USER_AGENT); this.compression = configureCompression(config.compression); } diff --git a/experimental/packages/otlp-grpc-exporter-base/src/util.ts b/experimental/packages/otlp-grpc-exporter-base/src/util.ts index 7e1d58dff74..f7a14b44deb 100644 --- a/experimental/packages/otlp-grpc-exporter-base/src/util.ts +++ b/experimental/packages/otlp-grpc-exporter-base/src/util.ts @@ -35,9 +35,12 @@ import { import { MetricExportServiceClient } from './MetricsExportServiceClient'; import { TraceExportServiceClient } from './TraceExportServiceClient'; import { LogsExportServiceClient } from './LogsExportServiceClient'; +import { VERSION } from './version'; export const DEFAULT_COLLECTOR_URL = 'http://localhost:4317'; +export const USER_AGENT = `OTel-OTLP-Exporter-JavaScript/${VERSION}`; + export function onInit( collector: OTLPGRPCExporterNodeBase, config: OTLPGRPCExporterConfigNode From 786797acf054060b51acf8cc4265c20955808900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 17:14:22 +0800 Subject: [PATCH 04/12] fix(otlp-http-exporter): remove test cases of `sendBeacon` --- .../browser/CollectorTraceExporter.test.ts | 470 +++++++----------- .../browser/CollectorMetricExporter.test.ts | 419 +++++----------- 2 files changed, 295 insertions(+), 594 deletions(-) diff --git a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts index 4e8bc1d6e17..5edc240d00d 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts @@ -85,189 +85,104 @@ describe('OTLPTraceExporter - web', () => { }); describe('export', () => { + let server: any; + let clock: sinon.SinonFakeTimers; beforeEach(() => { collectorExporterConfig = { hostname: 'foo', url: 'http://foo.bar.com', }; - }); - describe('when "sendBeacon" is available', () => { - beforeEach(() => { - collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); - }); - - it('should successfully send the spans using sendBeacon', done => { - collectorTraceExporter.export(spans, () => {}); - - setTimeout(async () => { - try { - const args = stubBeacon.args[0]; - const url = args[0]; - const blob: Blob = args[1]; - const body = await blob.text(); - const json = JSON.parse(body) as IExportTraceServiceRequest; - const span1 = json.resourceSpans?.[0].scopeSpans?.[0].spans?.[0]; - - assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); - ensureSpanIsCorrect(span1); - - const resource = json.resourceSpans?.[0].resource; - assert.ok( - typeof resource !== 'undefined', - "resource doesn't exist" - ); - ensureWebResourceIsCorrect(resource); - - assert.strictEqual(url, 'http://foo.bar.com'); - assert.strictEqual(stubBeacon.callCount, 1); - - assert.strictEqual(stubOpen.callCount, 0); - - ensureExportTraceServiceRequestIsSet(json); - done(); - } catch (err) { - done(err); - } - }); - }); + clock = sinon.useFakeTimers(); + collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); + server = sinon.fakeServer.create(); + }); - it('should log the successful message', done => { - const spyLoggerDebug = sinon.stub(); - const spyLoggerError = sinon.stub(); - const nop = () => {}; - const diagLogger: DiagLogger = { - debug: spyLoggerDebug, - error: spyLoggerError, - info: nop, - verbose: nop, - warn: nop, - }; + afterEach(() => { + server.restore(); + }); - diag.setLogger(diagLogger, DiagLogLevel.ALL); + it('should successfully send the spans using XMLHttpRequest', done => { + collectorTraceExporter.export(spans, () => {}); - stubBeacon.returns(true); + queueMicrotask(() => { + const request = server.requests[0]; + assert.strictEqual(request.method, 'POST'); + assert.strictEqual(request.url, 'http://foo.bar.com'); - collectorTraceExporter.export(spans, () => {}); + const body = request.requestBody; + const json = JSON.parse(body) as IExportTraceServiceRequest; + const span1 = json.resourceSpans?.[0].scopeSpans?.[0].spans?.[0]; - setTimeout(() => { - const response: any = spyLoggerDebug.args[2][0]; - assert.strictEqual(response, 'sendBeacon - can send'); - assert.strictEqual(spyLoggerError.args.length, 0); + assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); + ensureSpanIsCorrect(span1); - done(); - }); - }); + const resource = json.resourceSpans?.[0].resource; + assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); + ensureWebResourceIsCorrect(resource); - it('should log the error message', done => { - stubBeacon.returns(false); + assert.strictEqual(stubBeacon.callCount, 0); + ensureExportTraceServiceRequestIsSet(json); - collectorTraceExporter.export(spans, result => { - assert.deepStrictEqual(result.code, ExportResultCode.FAILED); - assert.ok(result.error?.message.includes('cannot send')); - done(); - }); + clock.restore(); + done(); }); }); - describe('when "sendBeacon" is NOT available', () => { - let server: any; - let clock: sinon.SinonFakeTimers; - beforeEach(() => { - // fakeTimers is used to replace the next setTimeout which is - // located in sendWithXhr function called by the export method - clock = sinon.useFakeTimers(); - - (window.navigator as any).sendBeacon = false; - collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); - server = sinon.fakeServer.create(); - }); - afterEach(() => { - server.restore(); - }); - - it('should successfully send the spans using XMLHttpRequest', done => { - collectorTraceExporter.export(spans, () => {}); - - queueMicrotask(() => { - const request = server.requests[0]; - assert.strictEqual(request.method, 'POST'); - assert.strictEqual(request.url, 'http://foo.bar.com'); - - const body = request.requestBody; - const json = JSON.parse(body) as IExportTraceServiceRequest; - const span1 = json.resourceSpans?.[0].scopeSpans?.[0].spans?.[0]; + it('should log the successful message', done => { + const spyLoggerDebug = sinon.stub(); + const spyLoggerError = sinon.stub(); + const nop = () => {}; + const diagLogger: DiagLogger = { + debug: spyLoggerDebug, + error: spyLoggerError, + info: nop, + verbose: nop, + warn: nop, + }; - assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); - ensureSpanIsCorrect(span1); + diag.setLogger(diagLogger, DiagLogLevel.ALL); - const resource = json.resourceSpans?.[0].resource; - assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); - ensureWebResourceIsCorrect(resource); + collectorTraceExporter.export(spans, () => {}); - assert.strictEqual(stubBeacon.callCount, 0); - ensureExportTraceServiceRequestIsSet(json); + queueMicrotask(() => { + const request = server.requests[0]; + request.respond(200); + const response: any = spyLoggerDebug.args[2][0]; + assert.strictEqual(response, 'xhr success'); + assert.strictEqual(spyLoggerError.args.length, 0); + assert.strictEqual(stubBeacon.callCount, 0); - clock.restore(); - done(); - }); + clock.restore(); + done(); }); + }); - it('should log the successful message', done => { - const spyLoggerDebug = sinon.stub(); - const spyLoggerError = sinon.stub(); - const nop = () => {}; - const diagLogger: DiagLogger = { - debug: spyLoggerDebug, - error: spyLoggerError, - info: nop, - verbose: nop, - warn: nop, - }; - - diag.setLogger(diagLogger, DiagLogLevel.ALL); - - collectorTraceExporter.export(spans, () => {}); - - queueMicrotask(() => { - const request = server.requests[0]; - request.respond(200); - const response: any = spyLoggerDebug.args[2][0]; - assert.strictEqual(response, 'xhr success'); - assert.strictEqual(spyLoggerError.args.length, 0); - assert.strictEqual(stubBeacon.callCount, 0); - - clock.restore(); - done(); - }); + it('should log the error message', done => { + collectorTraceExporter.export(spans, result => { + assert.deepStrictEqual(result.code, ExportResultCode.FAILED); + assert.ok(result.error?.message.includes('Failed to export')); + done(); }); - it('should log the error message', done => { - collectorTraceExporter.export(spans, result => { - assert.deepStrictEqual(result.code, ExportResultCode.FAILED); - assert.ok(result.error?.message.includes('Failed to export')); - done(); - }); - - queueMicrotask(() => { - const request = server.requests[0]; - request.respond(400); - clock.restore(); - done(); - }); + queueMicrotask(() => { + const request = server.requests[0]; + request.respond(400); + clock.restore(); + done(); }); + }); - it('should send custom headers', done => { - collectorTraceExporter.export(spans, () => {}); + it('should send custom headers', done => { + collectorTraceExporter.export(spans, () => {}); - queueMicrotask(() => { - const request = server.requests[0]; - request.respond(200); + queueMicrotask(() => { + const request = server.requests[0]; + request.respond(200); - assert.strictEqual(stubBeacon.callCount, 0); - clock.restore(); - done(); - }); + assert.strictEqual(stubBeacon.callCount, 0); + clock.restore(); + done(); }); }); }); @@ -349,6 +264,7 @@ describe('OTLPTraceExporter - web', () => { describe('export with custom headers', () => { let server: any; + let clock: sinon.SinonFakeTimers; const customHeaders = { foo: 'bar', bar: 'baz', @@ -359,77 +275,44 @@ describe('OTLPTraceExporter - web', () => { headers: customHeaders, }; server = sinon.fakeServer.create(); + // fakeTimers is used to replace the next setTimeout which is + // located in sendWithXhr function called by the export method + clock = sinon.useFakeTimers(); + collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); }); afterEach(() => { server.restore(); }); - describe('when "sendBeacon" is available', () => { - let clock: sinon.SinonFakeTimers; - beforeEach(() => { - // fakeTimers is used to replace the next setTimeout which is - // located in sendWithXhr function called by the export method - clock = sinon.useFakeTimers(); - - collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); - }); - it('should successfully send custom headers using XMLHTTPRequest', done => { - collectorTraceExporter.export(spans, () => {}); + it('should successfully send spans using XMLHttpRequest', done => { + collectorTraceExporter.export(spans, () => {}); - queueMicrotask(() => { - const [{ requestHeaders }] = server.requests; + queueMicrotask(() => { + const [{ requestHeaders }] = server.requests; - ensureHeadersContain(requestHeaders, customHeaders); - assert.strictEqual(stubBeacon.callCount, 0); - assert.strictEqual(stubOpen.callCount, 0); + ensureHeadersContain(requestHeaders, customHeaders); + assert.strictEqual(stubBeacon.callCount, 0); + assert.strictEqual(stubOpen.callCount, 0); - clock.restore(); - done(); - }); + clock.restore(); + done(); }); }); + it('should log the timeout request error message', done => { + const responseSpy = sinon.spy(); + collectorTraceExporter.export(spans, responseSpy); + clock.tick(10000); + clock.restore(); - describe('when "sendBeacon" is NOT available', () => { - let clock: sinon.SinonFakeTimers; - beforeEach(() => { - // fakeTimers is used to replace the next setTimeout which is - // located in sendWithXhr function called by the export method - clock = sinon.useFakeTimers(); - - (window.navigator as any).sendBeacon = false; - collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); - }); - - it('should successfully send spans using XMLHttpRequest', done => { - collectorTraceExporter.export(spans, () => {}); - - queueMicrotask(() => { - const [{ requestHeaders }] = server.requests; - - ensureHeadersContain(requestHeaders, customHeaders); - assert.strictEqual(stubBeacon.callCount, 0); - assert.strictEqual(stubOpen.callCount, 0); - - clock.restore(); - done(); - }); - }); - it('should log the timeout request error message', done => { - const responseSpy = sinon.spy(); - collectorTraceExporter.export(spans, responseSpy); - clock.tick(10000); - clock.restore(); - - setTimeout(() => { - const result = responseSpy.args[0][0] as core.ExportResult; - assert.strictEqual(result.code, core.ExportResultCode.FAILED); - const error = result.error as OTLPExporterError; - assert.ok(error !== undefined); - assert.strictEqual(error.message, 'Request Timeout'); + setTimeout(() => { + const result = responseSpy.args[0][0] as core.ExportResult; + assert.strictEqual(result.code, core.ExportResultCode.FAILED); + const error = result.error as OTLPExporterError; + assert.ok(error !== undefined); + assert.strictEqual(error.message, 'Request Timeout'); - done(); - }); + done(); }); }); }); @@ -596,109 +479,92 @@ describe('export with retry - real http request destroyed', () => { collectorExporterConfig = { timeoutMillis: 1500, }; + collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); }); afterEach(() => { server.restore(); }); - describe('when "sendBeacon" is NOT available', () => { - beforeEach(() => { - (window.navigator as any).sendBeacon = false; - collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig); - }); - it('should log the timeout request error message when retrying with exponential backoff with jitter', done => { - spans = []; - spans.push(Object.assign({}, mockedReadableSpan)); + it('should log the timeout request error message when retrying with exponential backoff with jitter', done => { + spans = []; + spans.push(Object.assign({}, mockedReadableSpan)); - let retry = 0; - server.respondWith( - 'http://localhost:4318/v1/traces', - function (xhr: any) { - retry++; - xhr.respond(503); - } - ); + let retry = 0; + server.respondWith('http://localhost:4318/v1/traces', function (xhr: any) { + retry++; + xhr.respond(503); + }); - collectorTraceExporter.export(spans, result => { - assert.strictEqual(result.code, core.ExportResultCode.FAILED); - const error = result.error as OTLPExporterError; - assert.ok(error !== undefined); - assert.strictEqual(error.message, 'Request Timeout'); - assert.strictEqual(retry, 1); - done(); - }); - }).timeout(3000); + collectorTraceExporter.export(spans, result => { + assert.strictEqual(result.code, core.ExportResultCode.FAILED); + const error = result.error as OTLPExporterError; + assert.ok(error !== undefined); + assert.strictEqual(error.message, 'Request Timeout'); + assert.strictEqual(retry, 1); + done(); + }); + }).timeout(3000); - it('should log the timeout request error message when retry-after header is set to 3 seconds', done => { - spans = []; - spans.push(Object.assign({}, mockedReadableSpan)); + it('should log the timeout request error message when retry-after header is set to 3 seconds', done => { + spans = []; + spans.push(Object.assign({}, mockedReadableSpan)); - let retry = 0; - server.respondWith( - 'http://localhost:4318/v1/traces', - function (xhr: any) { - retry++; - xhr.respond(503, { 'Retry-After': 3 }); - } - ); + let retry = 0; + server.respondWith('http://localhost:4318/v1/traces', function (xhr: any) { + retry++; + xhr.respond(503, { 'Retry-After': 3 }); + }); - collectorTraceExporter.export(spans, result => { - assert.strictEqual(result.code, core.ExportResultCode.FAILED); - const error = result.error as OTLPExporterError; - assert.ok(error !== undefined); - assert.strictEqual(error.message, 'Request Timeout'); - assert.strictEqual(retry, 1); - done(); - }); - }).timeout(3000); - it('should log the timeout request error message when retry-after header is a date', done => { - spans = []; - spans.push(Object.assign({}, mockedReadableSpan)); + collectorTraceExporter.export(spans, result => { + assert.strictEqual(result.code, core.ExportResultCode.FAILED); + const error = result.error as OTLPExporterError; + assert.ok(error !== undefined); + assert.strictEqual(error.message, 'Request Timeout'); + assert.strictEqual(retry, 1); + done(); + }); + }).timeout(3000); + it('should log the timeout request error message when retry-after header is a date', done => { + spans = []; + spans.push(Object.assign({}, mockedReadableSpan)); - let retry = 0; - server.respondWith( - 'http://localhost:4318/v1/traces', - function (xhr: any) { - retry++; - const d = new Date(); - d.setSeconds(d.getSeconds() + 1); - xhr.respond(503, { 'Retry-After': d }); - } - ); + let retry = 0; + server.respondWith('http://localhost:4318/v1/traces', function (xhr: any) { + retry++; + const d = new Date(); + d.setSeconds(d.getSeconds() + 1); + xhr.respond(503, { 'Retry-After': d }); + }); - collectorTraceExporter.export(spans, result => { - assert.strictEqual(result.code, core.ExportResultCode.FAILED); - const error = result.error as OTLPExporterError; - assert.ok(error !== undefined); - assert.strictEqual(error.message, 'Request Timeout'); - assert.strictEqual(retry, 2); - done(); - }); - }).timeout(3000); - it('should log the timeout request error message when retry-after header is a date with long delay', done => { - spans = []; - spans.push(Object.assign({}, mockedReadableSpan)); + collectorTraceExporter.export(spans, result => { + assert.strictEqual(result.code, core.ExportResultCode.FAILED); + const error = result.error as OTLPExporterError; + assert.ok(error !== undefined); + assert.strictEqual(error.message, 'Request Timeout'); + assert.strictEqual(retry, 2); + done(); + }); + }).timeout(3000); + it('should log the timeout request error message when retry-after header is a date with long delay', done => { + spans = []; + spans.push(Object.assign({}, mockedReadableSpan)); - let retry = 0; - server.respondWith( - 'http://localhost:4318/v1/traces', - function (xhr: any) { - retry++; - const d = new Date(); - d.setSeconds(d.getSeconds() + 120); - xhr.respond(503, { 'Retry-After': d }); - } - ); + let retry = 0; + server.respondWith('http://localhost:4318/v1/traces', function (xhr: any) { + retry++; + const d = new Date(); + d.setSeconds(d.getSeconds() + 120); + xhr.respond(503, { 'Retry-After': d }); + }); - collectorTraceExporter.export(spans, result => { - assert.strictEqual(result.code, core.ExportResultCode.FAILED); - const error = result.error as OTLPExporterError; - assert.ok(error !== undefined); - assert.strictEqual(error.message, 'Request Timeout'); - assert.strictEqual(retry, 1); - done(); - }); - }).timeout(3000); - }); + collectorTraceExporter.export(spans, result => { + assert.strictEqual(result.code, core.ExportResultCode.FAILED); + const error = result.error as OTLPExporterError; + assert.ok(error !== undefined); + assert.strictEqual(error.message, 'Request Timeout'); + assert.strictEqual(retry, 1); + done(); + }); + }).timeout(3000); }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts index 7dbc7cc889c..953431fc676 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts @@ -51,7 +51,6 @@ import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; describe('OTLPMetricExporter - web', () => { let collectorExporter: OTLPMetricExporter; let stubOpen: sinon.SinonStub; - let stubBeacon: sinon.SinonStub; let metrics: ResourceMetrics; let debugStub: sinon.SinonStub; let errorStub: sinon.SinonStub; @@ -60,7 +59,6 @@ describe('OTLPMetricExporter - web', () => { setUp([HISTOGRAM_AGGREGATION_VIEW]); stubOpen = sinon.stub(XMLHttpRequest.prototype, 'open'); sinon.stub(XMLHttpRequest.prototype, 'send'); - stubBeacon = sinon.stub(navigator, 'sendBeacon'); const counter: Counter = mockCounter(); mockObservableGauge(observableResult => { @@ -98,277 +96,140 @@ describe('OTLPMetricExporter - web', () => { }); describe('export', () => { - describe('when "sendBeacon" is available', () => { - beforeEach(() => { - collectorExporter = new OTLPMetricExporter({ - url: 'http://foo.bar.com', - temporalityPreference: AggregationTemporality.CUMULATIVE, - }); - }); - - it('should successfully send metrics using sendBeacon', done => { - collectorExporter.export(metrics, () => {}); - - setTimeout(async () => { - const args = stubBeacon.args[0]; - const url = args[0]; - const blob: Blob = args[1]; - const body = await blob.text(); - const json = JSON.parse(body) as IExportMetricsServiceRequest; - - // The order of the metrics is not guaranteed. - const counterIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'int-counter' - ); - const observableIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'double-observable-gauge2' - ); - const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'int-histogram' - ); - - const metric1 = - json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex]; - const metric2 = - json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex]; - const metric3 = - json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex]; - - assert.ok(typeof metric1 !== 'undefined', "metric doesn't exist"); - - ensureCounterIsCorrect( - metric1, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0] - .startTime - ) - ); - - assert.ok( - typeof metric2 !== 'undefined', - "second metric doesn't exist" - ); - ensureObservableGaugeIsCorrect( - metric2, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] - .startTime - ), - 6, - 'double-observable-gauge2' - ); - - assert.ok( - typeof metric3 !== 'undefined', - "third metric doesn't exist" - ); - ensureHistogramIsCorrect( - metric3, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] - .startTime - ), - [0, 100], - [0, 2, 0] - ); - - const resource = json.resourceMetrics[0].resource; - assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); - ensureWebResourceIsCorrect(resource); - - assert.strictEqual(url, 'http://foo.bar.com'); - - assert.strictEqual(stubBeacon.callCount, 1); - assert.strictEqual(stubOpen.callCount, 0); - - ensureExportMetricsServiceRequestIsSet(json); - - done(); - }); - }); - - it('should log the successful message', done => { - stubBeacon.returns(true); - - collectorExporter.export(metrics, () => {}); - - setTimeout(() => { - const response: any = debugStub.args[2][0]; - assert.strictEqual(response, 'sendBeacon - can send'); - assert.strictEqual(errorStub.args.length, 0); - - done(); - }); + let server: any; + beforeEach(() => { + collectorExporter = new OTLPMetricExporter({ + url: 'http://foo.bar.com', + temporalityPreference: AggregationTemporality.CUMULATIVE, }); - - it('should log the error message', done => { - stubBeacon.returns(false); - - collectorExporter.export(metrics, result => { - assert.deepStrictEqual(result.code, ExportResultCode.FAILED); - assert.ok(result.error?.message.includes('cannot send')); - done(); - }); + // Overwrites the start time to make tests consistent + Object.defineProperty(collectorExporter, '_startTime', { + value: 1592602232694000000, }); + server = sinon.fakeServer.create(); + }); + afterEach(() => { + server.restore(); }); - describe('when "sendBeacon" is NOT available', () => { - let server: any; - beforeEach(() => { - (window.navigator as any).sendBeacon = false; - collectorExporter = new OTLPMetricExporter({ - url: 'http://foo.bar.com', - temporalityPreference: AggregationTemporality.CUMULATIVE, - }); - // Overwrites the start time to make tests consistent - Object.defineProperty(collectorExporter, '_startTime', { - value: 1592602232694000000, - }); - server = sinon.fakeServer.create(); - }); - afterEach(() => { - server.restore(); + it('should successfully send the metrics using XMLHttpRequest', done => { + collectorExporter.export(metrics, () => {}); + + setTimeout(() => { + const request = server.requests[0]; + assert.strictEqual(request.method, 'POST'); + assert.strictEqual(request.url, 'http://foo.bar.com'); + + const body = request.requestBody; + const json = JSON.parse(body) as IExportMetricsServiceRequest; + // The order of the metrics is not guaranteed. + const counterIndex = metrics.scopeMetrics[0].metrics.findIndex( + it => it.descriptor.name === 'int-counter' + ); + const observableIndex = metrics.scopeMetrics[0].metrics.findIndex( + it => it.descriptor.name === 'double-observable-gauge2' + ); + const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex( + it => it.descriptor.name === 'int-histogram' + ); + + const metric1 = + json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex]; + const metric2 = + json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex]; + const metric3 = + json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex]; + + assert.ok(typeof metric1 !== 'undefined', "metric doesn't exist"); + ensureCounterIsCorrect( + metric1, + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0].endTime + ), + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0] + .startTime + ) + ); + + assert.ok( + typeof metric2 !== 'undefined', + "second metric doesn't exist" + ); + ensureObservableGaugeIsCorrect( + metric2, + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] + .endTime + ), + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] + .startTime + ), + 6, + 'double-observable-gauge2' + ); + + assert.ok(typeof metric3 !== 'undefined', "third metric doesn't exist"); + ensureHistogramIsCorrect( + metric3, + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] + .endTime + ), + hrTimeToNanoseconds( + metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] + .startTime + ), + [0, 100], + [0, 2, 0] + ); + + const resource = json.resourceMetrics[0].resource; + assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); + ensureWebResourceIsCorrect(resource); + + ensureExportMetricsServiceRequestIsSet(json); + + done(); }); + }); - it('should successfully send the metrics using XMLHttpRequest', done => { - collectorExporter.export(metrics, () => {}); - - setTimeout(() => { - const request = server.requests[0]; - assert.strictEqual(request.method, 'POST'); - assert.strictEqual(request.url, 'http://foo.bar.com'); - - const body = request.requestBody; - const json = JSON.parse(body) as IExportMetricsServiceRequest; - // The order of the metrics is not guaranteed. - const counterIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'int-counter' - ); - const observableIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'double-observable-gauge2' - ); - const histogramIndex = metrics.scopeMetrics[0].metrics.findIndex( - it => it.descriptor.name === 'int-histogram' - ); - - const metric1 = - json.resourceMetrics[0].scopeMetrics[0].metrics[counterIndex]; - const metric2 = - json.resourceMetrics[0].scopeMetrics[0].metrics[observableIndex]; - const metric3 = - json.resourceMetrics[0].scopeMetrics[0].metrics[histogramIndex]; - - assert.ok(typeof metric1 !== 'undefined', "metric doesn't exist"); - ensureCounterIsCorrect( - metric1, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[counterIndex].dataPoints[0] - .startTime - ) - ); - - assert.ok( - typeof metric2 !== 'undefined', - "second metric doesn't exist" - ); - ensureObservableGaugeIsCorrect( - metric2, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[observableIndex].dataPoints[0] - .startTime - ), - 6, - 'double-observable-gauge2' - ); - - assert.ok( - typeof metric3 !== 'undefined', - "third metric doesn't exist" - ); - ensureHistogramIsCorrect( - metric3, - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] - .endTime - ), - hrTimeToNanoseconds( - metrics.scopeMetrics[0].metrics[histogramIndex].dataPoints[0] - .startTime - ), - [0, 100], - [0, 2, 0] - ); - - const resource = json.resourceMetrics[0].resource; - assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); - ensureWebResourceIsCorrect(resource); - - assert.strictEqual(stubBeacon.callCount, 0); - ensureExportMetricsServiceRequestIsSet(json); - - done(); - }); - }); + it('should log the successful message', done => { + collectorExporter.export(metrics, () => {}); - it('should log the successful message', done => { - collectorExporter.export(metrics, () => {}); + setTimeout(() => { + const request = server.requests[0]; + request.respond(200); - setTimeout(() => { - const request = server.requests[0]; - request.respond(200); + const response: any = debugStub.args[2][0]; + assert.strictEqual(response, 'xhr success'); + assert.strictEqual(errorStub.args.length, 0); - const response: any = debugStub.args[2][0]; - assert.strictEqual(response, 'xhr success'); - assert.strictEqual(errorStub.args.length, 0); + done(); + }); + }); - assert.strictEqual(stubBeacon.callCount, 0); - done(); - }); + it('should log the error message', done => { + collectorExporter.export(metrics, result => { + assert.deepStrictEqual(result.code, ExportResultCode.FAILED); + assert.ok(result.error?.message.includes('Failed to export')); + done(); }); - it('should log the error message', done => { - collectorExporter.export(metrics, result => { - assert.deepStrictEqual(result.code, ExportResultCode.FAILED); - assert.ok(result.error?.message.includes('Failed to export')); - assert.strictEqual(stubBeacon.callCount, 0); - done(); - }); - - setTimeout(() => { - const request = server.requests[0]; - request.respond(400); - }); + setTimeout(() => { + const request = server.requests[0]; + request.respond(400); }); - it('should send custom headers', done => { - collectorExporter.export(metrics, () => {}); + }); + it('should send custom headers', done => { + collectorExporter.export(metrics, () => {}); - setTimeout(() => { - const request = server.requests[0]; - request.respond(200); + setTimeout(() => { + const request = server.requests[0]; + request.respond(200); - assert.strictEqual(stubBeacon.callCount, 0); - done(); - }); + done(); }); }); }); @@ -389,49 +250,23 @@ describe('OTLPMetricExporter - web', () => { temporalityPreference: AggregationTemporality.CUMULATIVE, }; server = sinon.fakeServer.create(); + collectorExporter = new OTLPMetricExporter(collectorExporterConfig); }); afterEach(() => { server.restore(); }); - describe('when "sendBeacon" is available', () => { - beforeEach(() => { - collectorExporter = new OTLPMetricExporter(collectorExporterConfig); - }); - it('should successfully send custom headers using XMLHTTPRequest', done => { - collectorExporter.export(metrics, () => {}); - - setTimeout(() => { - const [{ requestHeaders }] = server.requests; - - ensureHeadersContain(requestHeaders, customHeaders); - assert.strictEqual(stubBeacon.callCount, 0); - assert.strictEqual(stubOpen.callCount, 0); - - done(); - }); - }); - }); - - describe('when "sendBeacon" is NOT available', () => { - beforeEach(() => { - (window.navigator as any).sendBeacon = false; - collectorExporter = new OTLPMetricExporter(collectorExporterConfig); - }); - - it('should successfully send metrics using XMLHttpRequest', done => { - collectorExporter.export(metrics, () => {}); + it('should successfully send metrics using XMLHttpRequest', done => { + collectorExporter.export(metrics, () => {}); - setTimeout(() => { - const [{ requestHeaders }] = server.requests; + setTimeout(() => { + const [{ requestHeaders }] = server.requests; - ensureHeadersContain(requestHeaders, customHeaders); - assert.strictEqual(stubBeacon.callCount, 0); - assert.strictEqual(stubOpen.callCount, 0); + ensureHeadersContain(requestHeaders, customHeaders); + assert.strictEqual(stubOpen.callCount, 0); - done(); - }); + done(); }); }); }); From 5230b05bfcff308a3aae84244d58c801df915ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 17:33:15 +0800 Subject: [PATCH 05/12] feat(otlp-grpc-exporter): set metadata in correct order --- .../exporter-logs-otlp-grpc/src/OTLPLogExporter.ts | 14 +++++++++++--- .../src/OTLPTraceExporter.ts | 14 +++++++++++--- .../src/OTLPMetricExporter.ts | 14 +++++++++++--- .../src/OTLPGRPCExporterNodeBase.ts | 7 ++++++- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts b/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts index 675ce83db0a..176c37ca4b4 100644 --- a/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts +++ b/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts @@ -37,14 +37,22 @@ export class OTLPLogExporter implements LogRecordExporter { constructor(config: OTLPGRPCExporterConfigNode = {}) { - super(config); const headers = baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS ); - this.metadata ||= new Metadata(); + const metadata = new Metadata(); for (const [k, v] of Object.entries(headers)) { - this.metadata.set(k, v); + metadata.set(k, v); } + if (config.metadata) { + for (const [k, v] of Object.entries(config.metadata.getMap())) { + metadata.set(k, v); + } + } + super({ + ...config, + metadata, + }); } convert(logRecords: ReadableLogRecord[]): IExportLogsServiceRequest { diff --git a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts index 2cc5abcb2e8..36cce9a40d1 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts @@ -37,14 +37,22 @@ export class OTLPTraceExporter implements SpanExporter { constructor(config: OTLPGRPCExporterConfigNode = {}) { - super(config); const headers = baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS ); - this.metadata ||= new Metadata(); + const metadata = new Metadata(); for (const [k, v] of Object.entries(headers)) { - this.metadata.set(k, v); + metadata.set(k, v); } + if (config.metadata) { + for (const [k, v] of Object.entries(config.metadata.getMap())) { + metadata.set(k, v); + } + } + super({ + ...config, + metadata, + }); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts index 20f917e5439..2146764e95f 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts @@ -38,14 +38,22 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase< IExportMetricsServiceRequest > { constructor(config?: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions) { - super(config); const headers = baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS ); - this.metadata ||= new Metadata(); + const metadata = new Metadata(); for (const [k, v] of Object.entries(headers)) { - this.metadata.set(k, v); + metadata.set(k, v); } + if (config?.metadata) { + for (const [k, v] of Object.entries(config.metadata.getMap())) { + metadata.set(k, v); + } + } + super({ + ...config, + metadata, + }); } getServiceProtoPath(): string { diff --git a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts index 87964e56320..42cea575f9d 100644 --- a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts +++ b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts @@ -58,10 +58,15 @@ export abstract class OTLPGRPCExporterNodeBase< const headers = baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_HEADERS ); - this.metadata = config.metadata || new Metadata(); + this.metadata = new Metadata(); for (const [k, v] of Object.entries(headers)) { this.metadata.set(k, v); } + if (config.metadata) { + for (const [k, v] of Object.entries(config.metadata.getMap())) { + this.metadata.set(k, v); + } + } if (this.metadata.get('user-agent')) { diag.warn('User-Agent header should not be set via config.'); } From bc67f4633d862565228e983d88c551ac37d2b76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 17:51:46 +0800 Subject: [PATCH 06/12] feat(otlp-http-exporter): set headers in correct order --- .../src/platform/browser/OTLPTraceExporter.ts | 16 +++++++++------- .../src/platform/node/OTLPTraceExporter.ts | 16 +++++++++------- .../src/platform/browser/OTLPMetricExporter.ts | 16 +++++++++------- .../src/platform/node/OTLPMetricExporter.ts | 16 +++++++++------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/experimental/packages/exporter-trace-otlp-http/src/platform/browser/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-http/src/platform/browser/OTLPTraceExporter.ts index 8a343306c4a..a1fc5336bb9 100644 --- a/experimental/packages/exporter-trace-otlp-http/src/platform/browser/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-http/src/platform/browser/OTLPTraceExporter.ts @@ -38,13 +38,15 @@ export class OTLPTraceExporter implements SpanExporter { constructor(config: OTLPExporterConfigBase = {}) { - super(config); - this._headers = Object.assign( - this._headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS + ), + ...config.headers, + }, + }); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { return createExportTraceServiceRequest(spans, true); diff --git a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts index 8704baf5769..691e39e5267 100644 --- a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts @@ -38,13 +38,15 @@ export class OTLPTraceExporter implements SpanExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { - super(config); - this.headers = Object.assign( - this.headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS + ), + ...config.headers, + }, + }); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts index 73c99a06938..90e6fe281f7 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/browser/OTLPMetricExporter.ts @@ -37,13 +37,15 @@ class OTLPExporterBrowserProxy extends OTLPExporterBrowserBase< IExportMetricsServiceRequest > { constructor(config?: OTLPMetricExporterOptions & OTLPExporterConfigBase) { - super(config); - this._headers = Object.assign( - this._headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS + ), + ...config?.headers, + }, + }); } getDefaultUrl(config: OTLPExporterConfigBase): string { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts index 980931a6cb0..867f4fef8a6 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts @@ -37,13 +37,15 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase< IExportMetricsServiceRequest > { constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) { - super(config); - this.headers = Object.assign( - this.headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS + ), + ...config?.headers, + }, + }); } convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest { From 8f77cd04df861ffacfc644bec62e49ee9ed3598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 18:03:53 +0800 Subject: [PATCH 07/12] feat(otlp-proto-exporter): set headers in correct order --- .../src/platform/browser/OTLPTraceExporter.ts | 17 ++++++++++------- .../src/platform/node/OTLPTraceExporter.ts | 16 +++++++++------- .../src/OTLPMetricExporter.ts | 16 +++++++++------- .../browser/OTLPProtoExporterBrowserBase.ts | 15 +++++++++------ 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/experimental/packages/exporter-trace-otlp-proto/src/platform/browser/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-proto/src/platform/browser/OTLPTraceExporter.ts index 890268333fa..b2a233a7c76 100644 --- a/experimental/packages/exporter-trace-otlp-proto/src/platform/browser/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-proto/src/platform/browser/OTLPTraceExporter.ts @@ -41,14 +41,17 @@ export class OTLPTraceExporter implements SpanExporter { constructor(config: OTLPExporterConfigBase = {}) { - super(config); - this._headers = Object.assign( - this._headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS + ), + ...config.headers, + }, + }); } + convert(spans: ReadableSpan[]): IExportTraceServiceRequest { return createExportTraceServiceRequest(spans); } diff --git a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts index 0634013311e..962d9b0b53c 100644 --- a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts @@ -41,13 +41,15 @@ export class OTLPTraceExporter implements SpanExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { - super(config); - this.headers = Object.assign( - this.headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS + ), + ...config.headers, + }, + }); } convert(spans: ReadableSpan[]): IExportTraceServiceRequest { diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts index c29ae0085ca..c6919cb3c86 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts @@ -40,13 +40,15 @@ class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase< IExportMetricsServiceRequest > { constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) { - super(config); - this.headers = Object.assign( - this.headers, - baggageUtils.parseKeyPairsIntoRecord( - getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS - ) - ); + super({ + ...config, + headers: { + ...baggageUtils.parseKeyPairsIntoRecord( + getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS + ), + ...config?.headers, + }, + }); } convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest { diff --git a/experimental/packages/otlp-proto-exporter-base/src/platform/browser/OTLPProtoExporterBrowserBase.ts b/experimental/packages/otlp-proto-exporter-base/src/platform/browser/OTLPProtoExporterBrowserBase.ts index 4e9f95d5c0d..1d06f8e0a0d 100644 --- a/experimental/packages/otlp-proto-exporter-base/src/platform/browser/OTLPProtoExporterBrowserBase.ts +++ b/experimental/packages/otlp-proto-exporter-base/src/platform/browser/OTLPProtoExporterBrowserBase.ts @@ -38,7 +38,14 @@ export abstract class OTLPProtoExporterBrowserBase< ServiceRequest > extends OTLPExporterBaseMain { constructor(config: OTLPExporterConfigBase = {}) { - super(config); + super({ + ...config, + headers: { + accept: 'application/x-protobuf', + 'content-type': 'application/x-protobuf', + ...config.headers, + }, + }); } private _getExportRequestProto( @@ -75,11 +82,7 @@ export abstract class OTLPProtoExporterBrowserBase< sendWithXhr( new Blob([body], { type: 'application/x-protobuf' }), this.url, - { - ...this._headers, - 'Content-Type': 'application/x-protobuf', - Accept: 'application/x-protobuf', - }, + this._headers, this.timeoutMillis, onSuccess, onError From 96009bd5e3e16c9abbbe6ff4638b365d6a9d4012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 18:26:59 +0800 Subject: [PATCH 08/12] fix(otlp-exporter): normalize http headers to lower case --- .../browser/OTLPExporterBrowserBase.ts | 23 +++++++++---------- .../src/platform/node/OTLPExporterNodeBase.ts | 14 ++++------- .../packages/otlp-exporter-base/src/util.ts | 8 ++++--- .../src/OTLPGRPCExporterNodeBase.ts | 4 ++-- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts b/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts index 6b6de76d2be..c7fba21b058 100644 --- a/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts +++ b/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts @@ -36,21 +36,20 @@ export abstract class OTLPExporterBrowserBase< */ constructor(config: OTLPExporterConfigBase = {}) { super(config); - - const headersBeforeUserAgent = { - Accept: 'application/json', - 'Content-Type': 'application/json', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((config as any).metadata) { + diag.warn('Metadata cannot be set when using http'); + } + const headersBeforeUserAgent = parseHeaders({ + accept: 'application/json', + 'content-type': 'application/json', ...baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_HEADERS ), - ...parseHeaders(config.headers), - }; - if ( - Object.keys(headersBeforeUserAgent) - .map(key => key.toLowerCase()) - .includes('user-agent') - ) { - diag.warn('User-Agent header should not be set via config.'); + ...config.headers, + }); + if (Object.keys(headersBeforeUserAgent).includes('user-agent')) { + diag.warn('Header "user-agent" should not be set by config.'); } this._headers = Object.assign(headersBeforeUserAgent, USER_AGENT); } diff --git a/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts b/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts index 2d19b472bad..7c5f7c55521 100644 --- a/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts +++ b/experimental/packages/otlp-exporter-base/src/platform/node/OTLPExporterNodeBase.ts @@ -47,19 +47,15 @@ export abstract class OTLPExporterNodeBase< if ((config as any).metadata) { diag.warn('Metadata cannot be set when using http'); } - const headersBeforeUserAgent = { + const headersBeforeUserAgent = parseHeaders({ ...this.DEFAULT_HEADERS, ...baggageUtils.parseKeyPairsIntoRecord( getEnv().OTEL_EXPORTER_OTLP_HEADERS ), - ...parseHeaders(config.headers), - }; - if ( - Object.keys(headersBeforeUserAgent) - .map(key => key.toLowerCase()) - .includes('user-agent') - ) { - diag.warn('User-Agent header should not be set via config.'); + ...config.headers, + }); + if (Object.keys(headersBeforeUserAgent).includes('user-agent')) { + diag.warn('Header "user-agent" should not be set by config.'); } this.headers = Object.assign(headersBeforeUserAgent, USER_AGENT); this.agent = createHttpAgent(config); diff --git a/experimental/packages/otlp-exporter-base/src/util.ts b/experimental/packages/otlp-exporter-base/src/util.ts index 1fd226a7603..f53c423832e 100644 --- a/experimental/packages/otlp-exporter-base/src/util.ts +++ b/experimental/packages/otlp-exporter-base/src/util.ts @@ -25,7 +25,7 @@ export const DEFAULT_EXPORT_MAX_BACKOFF = 5000; export const DEFAULT_EXPORT_BACKOFF_MULTIPLIER = 1.5; export const USER_AGENT = { - 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, + 'user-agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`, }; /** @@ -38,9 +38,11 @@ export function parseHeaders( const headers: Record = {}; Object.entries(partialHeaders).forEach(([key, value]) => { if (typeof value !== 'undefined') { - headers[key] = String(value); + headers[key.toLowerCase()] = String(value); } else { - diag.warn(`Header "${key}" has wrong value and will be ignored`); + diag.warn( + `Header "${key.toLowerCase()}" has wrong value and will be ignored` + ); } }); return headers; diff --git a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts index 42cea575f9d..5d4efa37c6b 100644 --- a/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts +++ b/experimental/packages/otlp-grpc-exporter-base/src/OTLPGRPCExporterNodeBase.ts @@ -67,10 +67,10 @@ export abstract class OTLPGRPCExporterNodeBase< this.metadata.set(k, v); } } - if (this.metadata.get('user-agent')) { + if (this.metadata.get('User-Agent')) { diag.warn('User-Agent header should not be set via config.'); } - this.metadata.set('user-agent', USER_AGENT); + this.metadata.set('User-Agent', USER_AGENT); this.compression = configureCompression(config.compression); } From b9abac9777ade35f3d3ca290e294016b83ea4891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 18:34:18 +0800 Subject: [PATCH 09/12] chore: changelog --- experimental/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 1a5a6595cb7..1361506f41f 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -13,10 +13,12 @@ All notable changes to experimental packages in this project will be documented * feat(instrumentation): add ESM support for instrumentation. [#3698](https://github.com/open-telemetry/opentelemetry-js/pull/3698) @JamieDanielson, @pkanal, @vmarchaud, @lizthegrey, @bengl * feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters. [#3790](https://github.com/open-telemetry/opentelemetry-js/pull/3790) @JamieDanielson * feat(otlp-metric-exporters): Add User-Agent header to OTLP metric exporters. [#3806](https://github.com/open-telemetry/opentelemetry-js/pull/3806) @JamieDanielson +* feat(otlp-exporters): Move User-Agent header to OTLP exporter base packages. [#3811](https://github.com/open-telemetry/opentelemetry-js/pull/3811) @llc1123 ### :bug: (Bug Fix) * fix(sdk-node): use resource interface instead of concrete class [#3803](https://github.com/open-telemetry/opentelemetry-js/pull/3803) @blumamir +* fix(otlp-exporters): correct applying order of http headers/gRPC metadata [#3811](https://github.com/open-telemetry/opentelemetry-js/pull/3811) @llc1123 ### :books: (Refine Doc) From 040ac51d57ee8a63cb21cff79ed4d3f71a6a28bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Wed, 17 May 2023 18:54:45 +0800 Subject: [PATCH 10/12] fix(otlp-grpc-exporter): env vars should not override configs from constructor parameter --- .../test/OTLPLogExporter.test.ts | 15 +++++++-------- .../test/OTLPTraceExporter.test.ts | 15 +++++++-------- .../test/browser/CollectorTraceExporter.test.ts | 16 ++++++++++------ .../test/node/CollectorTraceExporter.test.ts | 15 +++++++++------ .../test/node/OTLPTraceExporter.test.ts | 15 +++++++++------ .../test/OTLPMetricExporter.test.ts | 15 +++++++-------- .../test/browser/CollectorMetricExporter.test.ts | 16 ++++++++++------ .../test/node/CollectorMetricExporter.test.ts | 15 +++++++++------ .../test/OTLPMetricExporter.test.ts | 15 +++++++++------ 9 files changed, 77 insertions(+), 60 deletions(-) diff --git a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts index c229d5e5ddd..35fafff96a4 100644 --- a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts +++ b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts @@ -326,16 +326,15 @@ describe('when configuring via environment', () => { assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { + it('should override global headers config with signal headers defined via env but not config from parameters', () => { 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_LOGS_HEADERS = 'foo=boo'; + metadata.set('foo', 'jar'); + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=boo,bar=loo'; const collectorExporter = new OTLPLogExporter({ metadata }); - assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['boo']); - assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['foo']); - assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['lol']); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['jar']); + assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['loo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['loo']); envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts index 29c080b9660..ea0d6ec212e 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts @@ -336,16 +336,15 @@ describe('when configuring via environment', () => { assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { + it('should override global headers config with signal headers defined via env but not config from parameters', () => { 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'; + metadata.set('foo', 'jar'); + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; const collectorExporter = new OTLPTraceExporter({ metadata }); - assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['boo']); - assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['foo']); - assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['lol']); + assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['jar']); + assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['loo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['loo']); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts index 5edc240d00d..fc8aa67d499 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts @@ -453,14 +453,18 @@ describe('when configuring via environment', () => { assert.strictEqual(collectorExporter._headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo'; - const collectorExporter = new OTLPTraceExporter({ headers: {} }); + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + const collectorExporter = new OTLPTraceExporter({ + headers: { foo: 'jar' }, + }); + // @ts-expect-error access internal property for testing + assert.strictEqual(collectorExporter._headers.foo, 'jar'); // @ts-expect-error access internal property for testing - assert.strictEqual(collectorExporter._headers.foo, 'boo'); + assert.strictEqual(collectorExporter._headers.bar, 'loo'); // @ts-expect-error access internal property for testing - assert.strictEqual(collectorExporter._headers.bar, 'foo'); + assert.strictEqual(collectorExporter._headers.goo, 'loo'); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts index 426aed4431f..8f6dc677380 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts @@ -160,12 +160,15 @@ describe('OTLPTraceExporter - node with json over http', () => { assert.strictEqual(collectorExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo'; - const collectorExporter = new OTLPTraceExporter(); - assert.strictEqual(collectorExporter.headers.foo, 'boo'); - assert.strictEqual(collectorExporter.headers.bar, 'foo'); + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + const collectorExporter = new OTLPTraceExporter({ + headers: { foo: 'jar' }, + }); + assert.strictEqual(collectorExporter.headers.foo, 'jar'); + assert.strictEqual(collectorExporter.headers.bar, 'loo'); + assert.strictEqual(collectorExporter.headers.goo, 'loo'); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts index 64f0e40ea0e..c80cdf8ea23 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts @@ -135,12 +135,15 @@ describe('OTLPTraceExporter - node with proto over http', () => { assert.strictEqual(collectorExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo'; - const collectorExporter = new OTLPTraceExporter(); - assert.strictEqual(collectorExporter.headers.foo, 'boo'); - assert.strictEqual(collectorExporter.headers.bar, 'foo'); + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + const collectorExporter = new OTLPTraceExporter({ + headers: { foo: 'jar' }, + }); + assert.strictEqual(collectorExporter.headers.foo, 'jar'); + assert.strictEqual(collectorExporter.headers.bar, 'loo'); + assert.strictEqual(collectorExporter.headers.goo, 'loo'); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts index 4b8d3265459..be17daa09be 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts @@ -314,27 +314,26 @@ describe('when configuring via environment', () => { ); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { + it('should override global headers config with signal headers defined via env but not config from parameters', () => { 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'; + metadata.set('foo', 'jar'); + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; const collectorExporter = new OTLPMetricExporter({ metadata, temporalityPreference: AggregationTemporality.CUMULATIVE, }); assert.deepStrictEqual( collectorExporter._otlpExporter.metadata?.get('foo'), - ['boo'] + ['jar'] ); assert.deepStrictEqual( collectorExporter._otlpExporter.metadata?.get('bar'), - ['foo'] + ['loo'] ); assert.deepStrictEqual( collectorExporter._otlpExporter.metadata?.get('goo'), - ['lol'] + ['loo'] ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts index 953431fc676..6b1f2cc5989 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts @@ -361,20 +361,24 @@ describe('when configuring via environment', () => { ); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; const collectorExporter = new OTLPMetricExporter({ - headers: {}, + headers: { foo: 'jar' }, temporalityPreference: AggregationTemporality.CUMULATIVE, }); assert.strictEqual( collectorExporter['_otlpExporter']['_headers'].foo, - 'boo' + 'jar' ); assert.strictEqual( collectorExporter['_otlpExporter']['_headers'].bar, - 'foo' + 'loo' + ); + assert.strictEqual( + collectorExporter['_otlpExporter']['_headers'].goo, + 'loo' ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts index d23ca628f70..1f972b67969 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -188,12 +188,15 @@ describe('OTLPMetricExporter - node with json over http', () => { assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; - const collectorExporter = new OTLPMetricExporter(); - assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'boo'); - assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'foo'); + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + const collectorExporter = new OTLPMetricExporter({ + headers: { foo: 'jar' }, + }); + assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'jar'); + assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'loo'); + assert.strictEqual(collectorExporter._otlpExporter.headers.goo, 'loo'); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts index 05ca183dcc8..2f98e464924 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts @@ -144,12 +144,15 @@ describe('OTLPMetricExporter - node with proto over http', () => { assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'bar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); - it('should override global headers config with signal headers defined via env', () => { - envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo'; - const collectorExporter = new OTLPMetricExporter(); - assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'boo'); - assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'foo'); + it('should override global headers config with signal headers defined via env but not config from parameters', () => { + envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + const collectorExporter = new OTLPMetricExporter({ + headers: { foo: 'jar' }, + }); + assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'jar'); + assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'loo'); + assert.strictEqual(collectorExporter._otlpExporter.headers.goo, 'loo'); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); From 361c1acab4f70c2829b06b608f902ada182f3026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Thu, 18 May 2023 12:26:26 +0800 Subject: [PATCH 11/12] chore(otlp-exporter): add `user-agent` header/metadata tests --- .../exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts | 7 +++++++ .../test/OTLPTraceExporter.test.ts | 7 +++++++ .../test/node/CollectorTraceExporter.test.ts | 8 ++++++++ .../test/node/OTLPTraceExporter.test.ts | 8 ++++++++ .../test/OTLPMetricExporter.test.ts | 8 ++++++++ .../test/node/CollectorMetricExporter.test.ts | 8 ++++++++ .../test/OTLPMetricExporter.test.ts | 8 ++++++++ 7 files changed, 54 insertions(+) diff --git a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts index 35fafff96a4..7884f47a464 100644 --- a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts +++ b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts @@ -37,6 +37,7 @@ import { IExportLogsServiceRequest, IResourceLogs, } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../src/version'; const logsServiceProtoPath = 'opentelemetry/proto/collector/logs/v1/logs_service.proto'; @@ -320,6 +321,12 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPLogExporter(); + assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ + `OTel-OTLP-Exporter-JavaScript/${VERSION}`, + ]); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPLogExporter(); diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts index ea0d6ec212e..f9cae3ea975 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts @@ -41,6 +41,7 @@ import { IExportTraceServiceRequest, IResourceSpans, } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../src/version'; const traceServiceProtoPath = 'opentelemetry/proto/collector/trace/v1/trace_service.proto'; @@ -330,6 +331,12 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPTraceExporter(); + assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ + `OTel-OTLP-Exporter-JavaScript/${VERSION}`, + ]); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); diff --git a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts index 8f6dc677380..4838f0eca28 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts @@ -36,6 +36,7 @@ import { import { nextTick } from 'process'; import { MockedResponse } from './nodeHelpers'; import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -154,6 +155,13 @@ describe('OTLPTraceExporter - node with json over http', () => { ); envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPTraceExporter(); + assert.deepStrictEqual( + collectorExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); diff --git a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts index c80cdf8ea23..7ccbe18f106 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts @@ -39,6 +39,7 @@ import { ServiceClientType, } from '@opentelemetry/otlp-proto-exporter-base'; import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -129,6 +130,13 @@ describe('OTLPTraceExporter - node with proto over http', () => { ); envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPTraceExporter(); + assert.deepStrictEqual( + collectorExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts index be17daa09be..b81bffb8d99 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts @@ -43,6 +43,7 @@ import { IExportMetricsServiceRequest, IResourceMetrics, } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../src/version'; const metricsServiceProtoPath = 'opentelemetry/proto/collector/metrics/v1/metrics_service.proto'; @@ -305,6 +306,13 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPMetricExporter(); + assert.deepStrictEqual( + collectorExporter._otlpExporter.metadata?.get('User-Agent'), + [`OTel-OTLP-Exporter-JavaScript/${VERSION}`] + ); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts index 1f972b67969..196eae4c1ad 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -50,6 +50,7 @@ import { OTLPExporterNodeConfigBase, } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../../src/version'; let fakeRequest: PassThrough; @@ -182,6 +183,13 @@ describe('OTLPMetricExporter - node with json over http', () => { ); envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPMetricExporter(); + assert.deepStrictEqual( + collectorExporter._otlpExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts index 2f98e464924..9b9c61e4c3f 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts @@ -46,6 +46,7 @@ import { OTLPMetricExporterOptions } from '@opentelemetry/exporter-metrics-otlp- import { Stream, PassThrough } from 'stream'; import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../src/version'; let fakeRequest: PassThrough; @@ -138,6 +139,13 @@ describe('OTLPMetricExporter - node with proto over http', () => { ); envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); + it('should have user-agent header', () => { + const collectorExporter = new OTLPMetricExporter(); + assert.deepStrictEqual( + collectorExporter._otlpExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); + }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); From a0bbdceccfbb5278fdf062a8a4286cdfca31da79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B2=92=E7=B2=92=E6=A9=99?= Date: Fri, 26 May 2023 19:04:06 +0000 Subject: [PATCH 12/12] fix: refine tests --- .../test/OTLPLogExporter.test.ts | 12 +++++------- .../test/OTLPTraceExporter.test.ts | 12 +++++------- .../test/browser/CollectorTraceExporter.test.ts | 9 ++++++++- .../test/node/CollectorTraceExporter.test.ts | 14 ++++++-------- .../test/node/OTLPTraceExporter.test.ts | 14 ++++++-------- .../test/OTLPMetricExporter.test.ts | 14 ++++++-------- .../test/browser/CollectorMetricExporter.test.ts | 8 +++++++- .../test/node/CollectorMetricExporter.test.ts | 14 ++++++-------- .../test/OTLPMetricExporter.test.ts | 14 ++++++-------- 9 files changed, 55 insertions(+), 56 deletions(-) diff --git a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts index 7884f47a464..1c8cf96943f 100644 --- a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts +++ b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts @@ -321,12 +321,6 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPLogExporter(); - assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ - `OTel-OTLP-Exporter-JavaScript/${VERSION}`, - ]); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPLogExporter(); @@ -337,11 +331,15 @@ describe('when configuring via environment', () => { const metadata = new grpc.Metadata(); metadata.set('foo', 'jar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = + 'foo=boo,bar=loo,User-Agent=baz'; const collectorExporter = new OTLPLogExporter({ metadata }); assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['jar']); assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['loo']); assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['loo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ + `OTel-OTLP-Exporter-JavaScript/${VERSION}`, + ]); envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts index f9cae3ea975..e3f036b248f 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts @@ -331,12 +331,6 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPTraceExporter(); - assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ - `OTel-OTLP-Exporter-JavaScript/${VERSION}`, - ]); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); @@ -347,11 +341,15 @@ describe('when configuring via environment', () => { const metadata = new grpc.Metadata(); metadata.set('foo', 'jar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = + 'foo=boo,bar=loo,User-Agent=baz'; const collectorExporter = new OTLPTraceExporter({ metadata }); assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['jar']); assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['loo']); assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['loo']); + assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [ + `OTel-OTLP-Exporter-JavaScript/${VERSION}`, + ]); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts index fc8aa67d499..863da40eeac 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/browser/CollectorTraceExporter.test.ts @@ -33,6 +33,7 @@ import { OTLPExporterError, } from '@opentelemetry/otlp-exporter-base'; import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../../src/version'; describe('OTLPTraceExporter - web', () => { let collectorTraceExporter: OTLPTraceExporter; @@ -455,7 +456,8 @@ describe('when configuring via environment', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPTraceExporter({ headers: { foo: 'jar' }, }); @@ -465,6 +467,11 @@ describe('when configuring via environment', () => { assert.strictEqual(collectorExporter._headers.bar, 'loo'); // @ts-expect-error access internal property for testing assert.strictEqual(collectorExporter._headers.goo, 'loo'); + assert.strictEqual( + // @ts-expect-error access internal property for testing + collectorExporter._headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts index 4838f0eca28..3f6679db87b 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts @@ -155,13 +155,6 @@ describe('OTLPTraceExporter - node with json over http', () => { ); envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPTraceExporter(); - assert.deepStrictEqual( - collectorExporter.headers['user-agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); @@ -170,13 +163,18 @@ describe('OTLPTraceExporter - node with json over http', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPTraceExporter({ headers: { foo: 'jar' }, }); assert.strictEqual(collectorExporter.headers.foo, 'jar'); assert.strictEqual(collectorExporter.headers.bar, 'loo'); assert.strictEqual(collectorExporter.headers.goo, 'loo'); + assert.strictEqual( + collectorExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts index 7ccbe18f106..0213e0986d7 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts @@ -130,13 +130,6 @@ describe('OTLPTraceExporter - node with proto over http', () => { ); envSource.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPTraceExporter(); - assert.deepStrictEqual( - collectorExporter.headers['user-agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPTraceExporter(); @@ -145,13 +138,18 @@ describe('OTLPTraceExporter - node with proto over http', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPTraceExporter({ headers: { foo: 'jar' }, }); assert.strictEqual(collectorExporter.headers.foo, 'jar'); assert.strictEqual(collectorExporter.headers.bar, 'loo'); assert.strictEqual(collectorExporter.headers.goo, 'loo'); + assert.strictEqual( + collectorExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts index b81bffb8d99..25b26ef39ef 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts @@ -306,13 +306,6 @@ describe('when configuring via environment', () => { envSource.OTEL_EXPORTER_OTLP_ENDPOINT = ''; envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPMetricExporter(); - assert.deepStrictEqual( - collectorExporter._otlpExporter.metadata?.get('User-Agent'), - [`OTel-OTLP-Exporter-JavaScript/${VERSION}`] - ); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); @@ -326,7 +319,8 @@ describe('when configuring via environment', () => { const metadata = new grpc.Metadata(); metadata.set('foo', 'jar'); envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = + 'foo=boo,bar=loo,User-Agent=baz'; const collectorExporter = new OTLPMetricExporter({ metadata, temporalityPreference: AggregationTemporality.CUMULATIVE, @@ -343,6 +337,10 @@ describe('when configuring via environment', () => { collectorExporter._otlpExporter.metadata?.get('goo'), ['loo'] ); + assert.deepStrictEqual( + collectorExporter._otlpExporter.metadata?.get('User-Agent'), + [`OTel-OTLP-Exporter-JavaScript/${VERSION}`] + ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts index 6b1f2cc5989..2a0b10c4301 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/browser/CollectorMetricExporter.test.ts @@ -47,6 +47,7 @@ import { import { OTLPMetricExporterOptions } from '../../src'; import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer'; +import { VERSION } from '../../src/version'; describe('OTLPMetricExporter - web', () => { let collectorExporter: OTLPMetricExporter; @@ -363,7 +364,8 @@ describe('when configuring via environment', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPMetricExporter({ headers: { foo: 'jar' }, temporalityPreference: AggregationTemporality.CUMULATIVE, @@ -380,6 +382,10 @@ describe('when configuring via environment', () => { collectorExporter['_otlpExporter']['_headers'].goo, 'loo' ); + assert.strictEqual( + collectorExporter['_otlpExporter']['_headers']['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts index 196eae4c1ad..573cf3a8370 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -183,13 +183,6 @@ describe('OTLPMetricExporter - node with json over http', () => { ); envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPMetricExporter(); - assert.deepStrictEqual( - collectorExporter._otlpExporter.headers['user-agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); @@ -198,13 +191,18 @@ describe('OTLPMetricExporter - node with json over http', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPMetricExporter({ headers: { foo: 'jar' }, }); assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'jar'); assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'loo'); assert.strictEqual(collectorExporter._otlpExporter.headers.goo, 'loo'); + assert.strictEqual( + collectorExporter._otlpExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts index 9b9c61e4c3f..8a3f76b8844 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts @@ -139,13 +139,6 @@ describe('OTLPMetricExporter - node with proto over http', () => { ); envSource.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = ''; }); - it('should have user-agent header', () => { - const collectorExporter = new OTLPMetricExporter(); - assert.deepStrictEqual( - collectorExporter._otlpExporter.headers['user-agent'], - `OTel-OTLP-Exporter-JavaScript/${VERSION}` - ); - }); it('should use headers defined via env', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar'; const collectorExporter = new OTLPMetricExporter(); @@ -154,13 +147,18 @@ describe('OTLPMetricExporter - node with proto over http', () => { }); it('should override global headers config with signal headers defined via env but not config from parameters', () => { envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo,goo=loo'; - envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo,bar=loo'; + envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = + 'foo=boo,bar=loo,user-agent=baz'; const collectorExporter = new OTLPMetricExporter({ headers: { foo: 'jar' }, }); assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'jar'); assert.strictEqual(collectorExporter._otlpExporter.headers.bar, 'loo'); assert.strictEqual(collectorExporter._otlpExporter.headers.goo, 'loo'); + assert.strictEqual( + collectorExporter._otlpExporter.headers['user-agent'], + `OTel-OTLP-Exporter-JavaScript/${VERSION}` + ); envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = ''; envSource.OTEL_EXPORTER_OTLP_HEADERS = ''; });