From 46ce5357528694c5fefa07680eef883257538e21 Mon Sep 17 00:00:00 2001 From: David W Date: Mon, 6 Jul 2020 10:56:00 -0400 Subject: [PATCH] feat: Collector Metric Exporter[2/x] Create CollectorMetricExporterBase (#1258) Co-authored-by: Daniel Dyla --- .../package.json | 1 + .../src/CollectorMetricExporterBase.ts | 119 ++++++++++ .../src/CollectorTraceExporterBase.ts | 30 ++- .../platform/node/CollectorTraceExporter.ts | 4 +- .../src/platform/node/protos | 2 +- .../src/types.ts | 21 +- .../browser/CollectorTraceExporter.test.ts | 6 +- .../common/CollectorMetricExporter.test.ts | 220 ++++++++++++++++++ .../common/CollectorTraceExporter.test.ts | 59 ++++- .../test/helper.ts | 44 +++- .../test/node/CollectorTraceExporter.test.ts | 4 +- 11 files changed, 469 insertions(+), 41 deletions(-) create mode 100644 packages/opentelemetry-exporter-collector/src/CollectorMetricExporterBase.ts create mode 100644 packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-collector/package.json b/packages/opentelemetry-exporter-collector/package.json index 8ca9a93c69a..d25876c93b8 100644 --- a/packages/opentelemetry-exporter-collector/package.json +++ b/packages/opentelemetry-exporter-collector/package.json @@ -87,6 +87,7 @@ "@opentelemetry/api": "^0.9.0", "@opentelemetry/core": "^0.9.0", "@opentelemetry/resources": "^0.9.0", + "@opentelemetry/metrics": "^0.9.0", "@opentelemetry/tracing": "^0.9.0", "google-protobuf": "^3.11.4", "grpc": "^1.24.2" diff --git a/packages/opentelemetry-exporter-collector/src/CollectorMetricExporterBase.ts b/packages/opentelemetry-exporter-collector/src/CollectorMetricExporterBase.ts new file mode 100644 index 00000000000..7580e5f8a73 --- /dev/null +++ b/packages/opentelemetry-exporter-collector/src/CollectorMetricExporterBase.ts @@ -0,0 +1,119 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MetricExporter, MetricRecord } from '@opentelemetry/metrics'; +import { Attributes, Logger } from '@opentelemetry/api'; +import { CollectorExporterConfigBase } from './types'; +import { NoopLogger, ExportResult } from '@opentelemetry/core'; +import * as collectorTypes from './types'; + +const DEFAULT_SERVICE_NAME = 'collector-metric-exporter'; + +/** + * Collector Metric Exporter abstract base class + */ +export abstract class CollectorMetricExporterBase< + T extends CollectorExporterConfigBase +> implements MetricExporter { + public readonly serviceName: string; + public readonly url: string; + public readonly logger: Logger; + public readonly hostname: string | undefined; + public readonly attributes?: Attributes; + protected readonly _startTime = new Date().getTime() * 1000000; + private _isShutdown: boolean = false; + + /** + * @param config + */ + constructor(config: T = {} as T) { + this.logger = config.logger || new NoopLogger(); + this.serviceName = config.serviceName || DEFAULT_SERVICE_NAME; + this.url = this.getDefaultUrl(config.url); + this.attributes = config.attributes; + if (typeof config.hostname === 'string') { + this.hostname = config.hostname; + } + this.onInit(); + } + + /** + * Export metrics + * @param metrics + * @param resultCallback + */ + export( + metrics: MetricRecord[], + resultCallback: (result: ExportResult) => void + ) { + if (this._isShutdown) { + resultCallback(ExportResult.FAILED_NOT_RETRYABLE); + return; + } + + this._exportMetrics(metrics) + .then(() => { + resultCallback(ExportResult.SUCCESS); + }) + .catch((error: collectorTypes.ExportServiceError) => { + if (error.message) { + this.logger.error(error.message); + } + if (error.code && error.code < 500) { + resultCallback(ExportResult.FAILED_NOT_RETRYABLE); + } else { + resultCallback(ExportResult.FAILED_RETRYABLE); + } + }); + } + + private _exportMetrics(metrics: MetricRecord[]): Promise { + return new Promise((resolve, reject) => { + try { + this.logger.debug('metrics to be sent', metrics); + // Send metrics to [opentelemetry collector]{@link https://github.com/open-telemetry/opentelemetry-collector} + // it will use the appropriate transport layer automatically depends on platform + this.sendMetrics(metrics, resolve, reject); + } catch (e) { + reject(e); + } + }); + } + + /** + * Shutdown the exporter. + */ + shutdown(): void { + if (this._isShutdown) { + this.logger.debug('shutdown already started'); + return; + } + this._isShutdown = true; + this.logger.debug('shutdown started'); + + // platform dependent + this.onShutdown(); + } + + abstract getDefaultUrl(url: string | undefined): string; + abstract onInit(): void; + abstract onShutdown(): void; + abstract sendMetrics( + metrics: MetricRecord[], + onSuccess: () => void, + onError: (error: collectorTypes.CollectorExporterError) => void + ): void; +} diff --git a/packages/opentelemetry-exporter-collector/src/CollectorTraceExporterBase.ts b/packages/opentelemetry-exporter-collector/src/CollectorTraceExporterBase.ts index 93ab2330db3..4695c439940 100644 --- a/packages/opentelemetry-exporter-collector/src/CollectorTraceExporterBase.ts +++ b/packages/opentelemetry-exporter-collector/src/CollectorTraceExporterBase.ts @@ -18,9 +18,9 @@ import { Attributes, Logger } from '@opentelemetry/api'; import { ExportResult, NoopLogger } from '@opentelemetry/core'; import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing'; import { - opentelemetryProto, CollectorExporterError, CollectorExporterConfigBase, + ExportServiceError, } from './types'; const DEFAULT_SERVICE_NAME = 'collector-exporter'; @@ -34,7 +34,7 @@ export abstract class CollectorTraceExporterBase< public readonly serviceName: string; public readonly url: string; public readonly logger: Logger; - public readonly hostName: string | undefined; + public readonly hostname: string | undefined; public readonly attributes?: Attributes; private _isShutdown: boolean = false; @@ -44,8 +44,8 @@ export abstract class CollectorTraceExporterBase< constructor(config: T = {} as T) { this.serviceName = config.serviceName || DEFAULT_SERVICE_NAME; this.url = this.getDefaultUrl(config.url); - if (typeof config.hostName === 'string') { - this.hostName = config.hostName; + if (typeof config.hostname === 'string') { + this.hostname = config.hostname; } this.attributes = config.attributes; @@ -76,20 +76,16 @@ export abstract class CollectorTraceExporterBase< .then(() => { resultCallback(ExportResult.SUCCESS); }) - .catch( - ( - error: opentelemetryProto.collector.trace.v1.ExportTraceServiceError - ) => { - if (error.message) { - this.logger.error(error.message); - } - if (error.code && error.code < 500) { - resultCallback(ExportResult.FAILED_NOT_RETRYABLE); - } else { - resultCallback(ExportResult.FAILED_RETRYABLE); - } + .catch((error: ExportServiceError) => { + if (error.message) { + this.logger.error(error.message); } - ); + if (error.code && error.code < 500) { + resultCallback(ExportResult.FAILED_NOT_RETRYABLE); + } else { + resultCallback(ExportResult.FAILED_RETRYABLE); + } + }); } private _exportSpans(spans: ReadableSpan[]): Promise { diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts index 38953899810..c5d88ad9b52 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts @@ -112,9 +112,7 @@ export class CollectorTraceExporter extends CollectorTraceExporterBase< this.traceServiceClient.export( exportTraceServiceRequest, this.metadata, - ( - err: collectorTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceError - ) => { + (err: collectorTypes.ExportServiceError) => { if (err) { this.logger.error( 'exportTraceServiceRequest', diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/protos b/packages/opentelemetry-exporter-collector/src/platform/node/protos index e6c3c4a74d5..b5468856918 160000 --- a/packages/opentelemetry-exporter-collector/src/platform/node/protos +++ b/packages/opentelemetry-exporter-collector/src/platform/node/protos @@ -1 +1 @@ -Subproject commit e6c3c4a74d57f870a0d781bada02cb2b2c497d14 +Subproject commit b54688569186e0b862bf7462a983ccf2c50c0547 diff --git a/packages/opentelemetry-exporter-collector/src/types.ts b/packages/opentelemetry-exporter-collector/src/types.ts index aca9f6dfb34..627cb736a84 100644 --- a/packages/opentelemetry-exporter-collector/src/types.ts +++ b/packages/opentelemetry-exporter-collector/src/types.ts @@ -32,14 +32,6 @@ export namespace opentelemetryProto { export interface ExportTraceServiceRequest { resourceSpans: opentelemetryProto.trace.v1.ResourceSpans[]; } - - export interface ExportTraceServiceError { - code: number; - details: string; - metadata: { [key: string]: unknown }; - message: string; - stack: string; - } } } @@ -171,11 +163,22 @@ export interface CollectorExporterError { stack?: string; } +/** + * Interface for handling export service errors + */ +export interface ExportServiceError { + code: number; + details: string; + metadata: { [key: string]: unknown }; + message: string; + stack: string; +} + /** * Collector Exporter base config */ export interface CollectorExporterConfigBase { - hostName?: string; + hostname?: string; logger?: Logger; serviceName?: string; attributes?: Attributes; diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts index 58a778547bb..2386b63ab5e 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts @@ -30,7 +30,7 @@ import { } from '../helper'; const sendBeacon = navigator.sendBeacon; -describe('CollectorExporter - web', () => { +describe('CollectorTraceExporter - web', () => { let collectorTraceExporter: CollectorTraceExporter; let collectorExporterConfig: collectorTypes.CollectorExporterConfigBrowser; let spyOpen: any; @@ -56,7 +56,7 @@ describe('CollectorExporter - web', () => { describe('export', () => { beforeEach(() => { collectorExporterConfig = { - hostName: 'foo', + hostname: 'foo', logger: new NoopLogger(), serviceName: 'bar', attributes: {}, @@ -326,7 +326,7 @@ describe('CollectorExporter - web', () => { }); }); -describe('CollectorExporter - browser (getDefaultUrl)', () => { +describe('CollectorTraceExporter - browser (getDefaultUrl)', () => { it('should default to v1/trace', done => { const collectorExporter = new CollectorTraceExporter({}); setTimeout(() => { diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts new file mode 100644 index 00000000000..73e9ddc40eb --- /dev/null +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts @@ -0,0 +1,220 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ExportResult, NoopLogger } from '@opentelemetry/core'; +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import { CollectorMetricExporterBase } from '../../src/CollectorMetricExporterBase'; +import { CollectorExporterConfigBase } from '../../src/types'; +import { MetricRecord } from '@opentelemetry/metrics'; +import { mockCounter, mockObserver } from '../helper'; + +type CollectorExporterConfig = CollectorExporterConfigBase; +class CollectorMetricExporter extends CollectorMetricExporterBase< + CollectorExporterConfig +> { + onInit() {} + onShutdown() {} + sendMetrics() {} + getDefaultUrl(url: string) { + return url || ''; + } +} + +describe('CollectorMetricExporter - common', () => { + let collectorExporter: CollectorMetricExporter; + let collectorExporterConfig: CollectorExporterConfig; + let metrics: MetricRecord[]; + describe('constructor', () => { + let onInitSpy: any; + + beforeEach(() => { + onInitSpy = sinon.stub(CollectorMetricExporter.prototype, 'onInit'); + collectorExporterConfig = { + hostname: 'foo', + logger: new NoopLogger(), + serviceName: 'bar', + attributes: {}, + url: 'http://foo.bar.com', + }; + collectorExporter = new CollectorMetricExporter(collectorExporterConfig); + metrics = []; + metrics.push(Object.assign({}, mockCounter)); + metrics.push(Object.assign({}, mockObserver)); + }); + + afterEach(() => { + onInitSpy.restore(); + }); + + it('should create an instance', () => { + assert.ok(typeof collectorExporter !== 'undefined'); + }); + + it('should call onInit', () => { + assert.strictEqual(onInitSpy.callCount, 1); + }); + + describe('when config contains certain params', () => { + it('should set hostname', () => { + assert.strictEqual(collectorExporter.hostname, 'foo'); + }); + + it('should set serviceName', () => { + assert.strictEqual(collectorExporter.serviceName, 'bar'); + }); + + it('should set url', () => { + assert.strictEqual(collectorExporter.url, 'http://foo.bar.com'); + }); + + it('should set logger', () => { + assert.ok(collectorExporter.logger === collectorExporterConfig.logger); + }); + }); + + describe('when config is missing certain params', () => { + beforeEach(() => { + collectorExporter = new CollectorMetricExporter(); + }); + + it('should set default serviceName', () => { + assert.strictEqual( + collectorExporter.serviceName, + 'collector-metric-exporter' + ); + }); + + it('should set default logger', () => { + assert.ok(collectorExporter.logger instanceof NoopLogger); + }); + }); + }); + + describe('export', () => { + let spySend: any; + beforeEach(() => { + spySend = sinon.stub(CollectorMetricExporter.prototype, 'sendMetrics'); + collectorExporter = new CollectorMetricExporter(collectorExporterConfig); + }); + afterEach(() => { + spySend.restore(); + }); + + it('should export metrics as collectorTypes.Metrics', done => { + collectorExporter.export(metrics, () => {}); + setTimeout(() => { + const metric1 = spySend.args[0][0][0] as MetricRecord; + assert.deepStrictEqual(metrics[0], metric1); + const metric2 = spySend.args[0][0][1] as MetricRecord; + assert.deepStrictEqual(metrics[1], metric2); + done(); + }); + assert.strictEqual(spySend.callCount, 1); + }); + + describe('when exporter is shutdown', () => { + it('should not export anything but return callback with code "FailedNotRetryable"', () => { + collectorExporter.shutdown(); + spySend.resetHistory(); + + const callbackSpy = sinon.spy(); + collectorExporter.export(metrics, callbackSpy); + const returnCode = callbackSpy.args[0][0]; + assert.strictEqual( + returnCode, + ExportResult.FAILED_NOT_RETRYABLE, + 'return value is wrong' + ); + assert.strictEqual(spySend.callCount, 0, 'should not call send'); + }); + }); + describe('when an error occurs', () => { + it('should return a Not Retryable Error', done => { + spySend.throws({ + code: 100, + details: 'Test error', + metadata: {}, + message: 'Non-retryable', + stack: 'Stack', + }); + const callbackSpy = sinon.spy(); + collectorExporter.export(metrics, callbackSpy); + setTimeout(() => { + const returnCode = callbackSpy.args[0][0]; + assert.strictEqual( + returnCode, + ExportResult.FAILED_NOT_RETRYABLE, + 'return value is wrong' + ); + assert.strictEqual(spySend.callCount, 1, 'should call send'); + done(); + }, 500); + }); + + it('should return a Retryable Error', done => { + spySend.throws({ + code: 600, + details: 'Test error', + metadata: {}, + message: 'Retryable', + stack: 'Stack', + }); + const callbackSpy = sinon.spy(); + collectorExporter.export(metrics, callbackSpy); + setTimeout(() => { + const returnCode = callbackSpy.args[0][0]; + assert.strictEqual( + returnCode, + ExportResult.FAILED_RETRYABLE, + 'return value is wrong' + ); + assert.strictEqual(spySend.callCount, 1, 'should call send'); + done(); + }, 500); + }); + }); + }); + + describe('shutdown', () => { + let onShutdownSpy: any; + beforeEach(() => { + onShutdownSpy = sinon.stub( + CollectorMetricExporter.prototype, + 'onShutdown' + ); + collectorExporterConfig = { + hostname: 'foo', + logger: new NoopLogger(), + serviceName: 'bar', + attributes: {}, + url: 'http://foo.bar.com', + }; + collectorExporter = new CollectorMetricExporter(collectorExporterConfig); + }); + afterEach(() => { + onShutdownSpy.restore(); + }); + + it('should call onShutdown', done => { + collectorExporter.shutdown(); + setTimeout(() => { + assert.equal(onShutdownSpy.callCount, 1); + done(); + }); + }); + }); +}); diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts index 71ccee1c1c2..504aff43385 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts @@ -34,7 +34,7 @@ class CollectorTraceExporter extends CollectorTraceExporterBase< } } -describe('CollectorExporter - common', () => { +describe('CollectorTraceExporter - common', () => { let collectorExporter: CollectorTraceExporter; let collectorExporterConfig: CollectorExporterConfig; @@ -44,7 +44,7 @@ describe('CollectorExporter - common', () => { beforeEach(() => { onInitSpy = sinon.stub(CollectorTraceExporter.prototype, 'onInit'); collectorExporterConfig = { - hostName: 'foo', + hostname: 'foo', logger: new NoopLogger(), serviceName: 'bar', attributes: {}, @@ -66,8 +66,8 @@ describe('CollectorExporter - common', () => { }); describe('when config contains certain params', () => { - it('should set hostName', () => { - assert.strictEqual(collectorExporter.hostName, 'foo'); + it('should set hostname', () => { + assert.strictEqual(collectorExporter.hostname, 'foo'); }); it('should set serviceName', () => { @@ -140,6 +140,55 @@ describe('CollectorExporter - common', () => { assert.strictEqual(spySend.callCount, 0, 'should not call send'); }); }); + describe('when an error occurs', () => { + it('should return a Not Retryable Error', done => { + const spans: ReadableSpan[] = []; + spans.push(Object.assign({}, mockedReadableSpan)); + spySend.throws({ + code: 100, + details: 'Test error', + metadata: {}, + message: 'Non-retryable', + stack: 'Stack', + }); + const callbackSpy = sinon.spy(); + collectorExporter.export(spans, callbackSpy); + setTimeout(() => { + const returnCode = callbackSpy.args[0][0]; + assert.strictEqual( + returnCode, + ExportResult.FAILED_NOT_RETRYABLE, + 'return value is wrong' + ); + assert.strictEqual(spySend.callCount, 1, 'should call send'); + done(); + }, 500); + }); + + it('should return a Retryable Error', done => { + const spans: ReadableSpan[] = []; + spans.push(Object.assign({}, mockedReadableSpan)); + spySend.throws({ + code: 600, + details: 'Test error', + metadata: {}, + message: 'Retryable', + stack: 'Stack', + }); + const callbackSpy = sinon.spy(); + collectorExporter.export(spans, callbackSpy); + setTimeout(() => { + const returnCode = callbackSpy.args[0][0]; + assert.strictEqual( + returnCode, + ExportResult.FAILED_RETRYABLE, + 'return value is wrong' + ); + assert.strictEqual(spySend.callCount, 1, 'should call send'); + done(); + }, 500); + }); + }); }); describe('shutdown', () => { @@ -150,7 +199,7 @@ describe('CollectorExporter - common', () => { 'onShutdown' ); collectorExporterConfig = { - hostName: 'foo', + hostname: 'foo', logger: new NoopLogger(), serviceName: 'bar', attributes: {}, diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index 056d95d2a7b..4e57a6edbbf 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { TraceFlags } from '@opentelemetry/api'; +import { TraceFlags, ValueType } from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/tracing'; import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; @@ -22,6 +22,12 @@ import { opentelemetryProto } from '../src/types'; import * as collectorTypes from '../src/types'; import { InstrumentationLibrary } from '@opentelemetry/core'; import * as grpc from 'grpc'; +import { + MetricRecord, + MetricKind, + SumAggregator, + LastValueAggregator, +} from '@opentelemetry/metrics'; if (typeof Buffer === 'undefined') { (window as any).Buffer = { @@ -52,6 +58,42 @@ const traceIdArr = [ const spanIdArr = [94, 16, 114, 97, 246, 79, 165, 62]; const parentIdArr = [120, 168, 145, 80, 152, 134, 67, 136]; +export const mockCounter: MetricRecord = { + descriptor: { + name: 'test-counter', + description: 'sample counter description', + unit: '1', + metricKind: MetricKind.COUNTER, + valueType: ValueType.INT, + }, + labels: {}, + aggregator: new SumAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, +}; + +export const mockObserver: MetricRecord = { + descriptor: { + name: 'test-observer', + description: 'sample observer description', + unit: '2', + metricKind: MetricKind.VALUE_OBSERVER, + valueType: ValueType.DOUBLE, + }, + labels: {}, + aggregator: new LastValueAggregator(), + resource: new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, +}; + const traceIdBase64 = 'HxAI3I4nDoXECg18OTmyeA=='; const spanIdBase64 = 'XhByYfZPpT4='; const parentIdBase64 = 'eKiRUJiGQ4g='; diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts index 537bd8eee49..514125e8822 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts @@ -50,7 +50,7 @@ const metadata = new grpc.Metadata(); metadata.set('k', 'v'); const testCollectorExporter = (params: TestParams) => - describe(`CollectorExporter - node ${ + describe(`CollectorTraceExporter - node ${ params.useTLS ? 'with' : 'without' } TLS, ${params.metadata ? 'with' : 'without'} metadata`, () => { let collectorExporter: CollectorTraceExporter; @@ -172,7 +172,7 @@ const testCollectorExporter = (params: TestParams) => }); }); -describe('CollectorExporter - node (getDefaultUrl)', () => { +describe('CollectorTraceExporter - node (getDefaultUrl)', () => { it('should default to localhost', done => { const collectorExporter = new CollectorTraceExporter({}); setTimeout(() => {