From dd69e8e038f62aaac9d261a54740868ca59fabf0 Mon Sep 17 00:00:00 2001 From: "marc.pichler" Date: Tue, 26 Apr 2022 20:32:39 +0200 Subject: [PATCH] feat(otlp-trace-exporter): update to newest proto versions. --- .../exporter-trace-otlp-grpc/package.json | 2 +- .../src/OTLPTraceExporter.ts | 11 +- .../test/OTLPTraceExporter.test.ts | 59 +-- .../test/traceHelper.ts | 13 +- .../exporter-trace-otlp-grpc/tsconfig.json | 6 +- .../exporter-trace-otlp-http/package.json | 3 +- .../exporter-trace-otlp-http/src/index.ts | 2 - .../src/platform/browser/OTLPTraceExporter.ts | 9 +- .../src/platform/node/OTLPTraceExporter.ts | 9 +- .../exporter-trace-otlp-http/src/transform.ts | 367 ------------------ .../exporter-trace-otlp-http/src/types.ts | 326 ---------------- .../browser/CollectorTraceExporter.test.ts | 14 +- .../test/browser/index-webpack.ts | 3 - .../test/common/transform.test.ts | 218 ----------- .../test/node/CollectorTraceExporter.test.ts | 10 +- .../test/traceHelper.ts | 33 +- .../exporter-trace-otlp-http/tsconfig.json | 3 + .../exporter-trace-otlp-proto/package.json | 3 +- .../src/OTLPTraceExporter.ts | 11 +- .../test/OTLPTraceExporter.test.ts | 12 +- .../test/traceHelper.ts | 20 +- .../exporter-trace-otlp-proto/tsconfig.json | 3 + .../otlp-transformer/src/trace/index.ts | 4 +- .../otlp-transformer/src/trace/internal.ts | 17 +- .../otlp-transformer/test/trace.test.ts | 22 +- 25 files changed, 136 insertions(+), 1044 deletions(-) delete mode 100644 experimental/packages/exporter-trace-otlp-http/src/transform.ts delete mode 100644 experimental/packages/exporter-trace-otlp-http/src/types.ts delete mode 100644 experimental/packages/exporter-trace-otlp-http/test/common/transform.test.ts diff --git a/experimental/packages/exporter-trace-otlp-grpc/package.json b/experimental/packages/exporter-trace-otlp-grpc/package.json index 74ddcb2f5ef..419e78ef7a8 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/package.json +++ b/experimental/packages/exporter-trace-otlp-grpc/package.json @@ -70,7 +70,7 @@ "@opentelemetry/core": "1.2.0", "@grpc/grpc-js": "^1.5.9", "@grpc/proto-loader": "^0.6.9", - "@opentelemetry/exporter-trace-otlp-http": "0.28.0", + "@opentelemetry/otlp-transformer": "0.28.0", "@opentelemetry/otlp-grpc-exporter-base": "0.28.0", "@opentelemetry/resources": "1.2.0", "@opentelemetry/sdk-trace-base": "1.2.0" diff --git a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts index d08e679e990..0acd3ecc94d 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts @@ -15,10 +15,6 @@ */ import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'; -import { - otlpTypes, - toOTLPExportTraceServiceRequest, -} from '@opentelemetry/exporter-trace-otlp-http'; import { baggageUtils, getEnv } from '@opentelemetry/core'; import { Metadata } from '@grpc/grpc-js'; import { @@ -27,6 +23,7 @@ import { ServiceClientType, validateAndNormalizeUrl } from '@opentelemetry/otlp-grpc-exporter-base'; +import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; const DEFAULT_COLLECTOR_URL = 'localhost:4317'; @@ -35,7 +32,7 @@ const DEFAULT_COLLECTOR_URL = 'localhost:4317'; */ export class OTLPTraceExporter extends OTLPGRPCExporterNodeBase + IExportTraceServiceRequest> implements SpanExporter { constructor(config: OTLPGRPCExporterConfigNode = {}) { @@ -49,8 +46,8 @@ export class OTLPTraceExporter convert( spans: ReadableSpan[] - ): otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { - return toOTLPExportTraceServiceRequest(spans, this); + ): IExportTraceServiceRequest { + return createExportTraceServiceRequest(spans); } getDefaultUrl(config: OTLPGRPCExporterConfigNode) { 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 7d44d4938ee..dfb01074ba1 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts @@ -15,7 +15,6 @@ */ import * as protoLoader from '@grpc/proto-loader'; -import { otlpTypes } from '@opentelemetry/exporter-trace-otlp-http'; import { diag } from '@opentelemetry/api'; import { BasicTracerProvider, @@ -37,6 +36,7 @@ import { } from './traceHelper'; import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'; import { GrpcCompressionAlgorithm } from '@opentelemetry/otlp-grpc-exporter-base'; +import { IExportTraceServiceRequest, IResourceSpans } from '@opentelemetry/otlp-transformer'; const traceServiceProtoPath = 'opentelemetry/proto/collector/trace/v1/trace_service.proto'; @@ -59,7 +59,7 @@ const testCollectorExporter = (params: TestParams) => let collectorExporter: OTLPTraceExporter; let server: grpc.Server; let exportedData: - | otlpTypes.opentelemetryProto.trace.v1.ResourceSpans + | IResourceSpans | undefined; let reqMetadata: grpc.Metadata | undefined; @@ -83,28 +83,26 @@ const testCollectorExporter = (params: TestParams) => .service, { Export: (data: { - request: otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + request: IExportTraceServiceRequest; metadata: grpc.Metadata; }) => { - try { + if (data.request.resourceSpans != null) { exportedData = data.request.resourceSpans[0]; - reqMetadata = data.metadata; - } catch (e) { - exportedData = undefined; } + reqMetadata = data.metadata; }, } ); const credentials = params.useTLS ? grpc.ServerCredentials.createSsl( - fs.readFileSync('./test/certs/ca.crt'), - [ - { - cert_chain: fs.readFileSync('./test/certs/server.crt'), - private_key: fs.readFileSync('./test/certs/server.key'), - }, - ] - ) + fs.readFileSync('./test/certs/ca.crt'), + [ + { + cert_chain: fs.readFileSync('./test/certs/server.crt'), + private_key: fs.readFileSync('./test/certs/server.key'), + }, + ] + ) : grpc.ServerCredentials.createInsecure(); server.bindAsync(address, credentials, () => { server.start(); @@ -120,10 +118,10 @@ const testCollectorExporter = (params: TestParams) => beforeEach(done => { const credentials = params.useTLS ? grpc.credentials.createSsl( - fs.readFileSync('./test/certs/ca.crt'), - fs.readFileSync('./test/certs/client.key'), - fs.readFileSync('./test/certs/client.crt') - ) + fs.readFileSync('./test/certs/ca.crt'), + fs.readFileSync('./test/certs/client.key'), + fs.readFileSync('./test/certs/client.crt') + ) : undefined; collectorExporter = new OTLPTraceExporter({ url: 'grpcs://' + address, @@ -180,8 +178,9 @@ const testCollectorExporter = (params: TestParams) => ); let spans; let resource; - if (exportedData) { + if (exportedData && exportedData.instrumentationLibrarySpans[0].spans) { spans = exportedData.instrumentationLibrarySpans[0].spans; + resource = exportedData.resource; ensureExportedSpanIsCorrect(spans[0]); @@ -203,12 +202,12 @@ const testCollectorExporter = (params: TestParams) => describe('export - with gzip compression', () => { beforeEach(() => { const credentials = params.useTLS - ? grpc.credentials.createSsl( + ? grpc.credentials.createSsl( fs.readFileSync('./test/certs/ca.crt'), fs.readFileSync('./test/certs/client.key'), fs.readFileSync('./test/certs/client.crt') ) - : undefined; + : undefined; collectorExporter = new OTLPTraceExporter({ url: 'grpcs://' + address, credentials, @@ -230,7 +229,7 @@ const testCollectorExporter = (params: TestParams) => ); let spans; let resource; - if (exportedData) { + if (exportedData && exportedData.instrumentationLibrarySpans[0].spans) { spans = exportedData.instrumentationLibrarySpans[0].spans; resource = exportedData.resource; ensureExportedSpanIsCorrect(spans[0]); @@ -254,14 +253,14 @@ const testCollectorExporter = (params: TestParams) => const envSource = process.env; it('should return gzip compression algorithm on exporter', () => { const credentials = params.useTLS - ? grpc.credentials.createSsl( + ? grpc.credentials.createSsl( fs.readFileSync('./test/certs/ca.crt'), fs.readFileSync('./test/certs/client.key'), fs.readFileSync('./test/certs/client.crt') ) - : undefined; + : undefined; - envSource.OTEL_EXPORTER_OTLP_COMPRESSION='gzip'; + envSource.OTEL_EXPORTER_OTLP_COMPRESSION = 'gzip'; collectorExporter = new OTLPTraceExporter({ url: 'grpcs://' + address, credentials, @@ -334,8 +333,10 @@ describe('when configuring via environment', () => { }); }); -testCollectorExporter({ useTLS: true }); -testCollectorExporter({ useTLS: false }); -testCollectorExporter({ metadata }); +describe('', () => { + testCollectorExporter({ useTLS: true }); + testCollectorExporter({ useTLS: false }); + testCollectorExporter({ metadata }); +}); diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts index 83578d3c128..b7476f45f05 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts @@ -15,12 +15,12 @@ */ import { SpanStatusCode, TraceFlags } from '@opentelemetry/api'; -import { otlpTypes } from '@opentelemetry/exporter-trace-otlp-http'; import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import * as grpc from '@grpc/grpc-js'; import { VERSION } from '@opentelemetry/core'; +import { IEvent, IKeyValue, ILink, IResource, ISpan } from '@opentelemetry/otlp-transformer'; const traceIdArr = [ 31, @@ -101,7 +101,7 @@ export const mockedReadableSpan: ReadableSpan = { }; export function ensureExportedEventsAreCorrect( - events: otlpTypes.opentelemetryProto.trace.v1.Span.Event[] + events: IEvent[] ) { assert.deepStrictEqual( events, @@ -160,7 +160,7 @@ export function ensureExportedEventsAreCorrect( } export function ensureExportedAttributesAreCorrect( - attributes: otlpTypes.opentelemetryProto.common.v1.KeyValue[] + attributes: IKeyValue[] ) { assert.deepStrictEqual( attributes, @@ -178,7 +178,7 @@ export function ensureExportedAttributesAreCorrect( } export function ensureExportedLinksAreCorrect( - attributes: otlpTypes.opentelemetryProto.trace.v1.Span.Link[] + attributes: ILink[] ) { assert.deepStrictEqual( attributes, @@ -204,7 +204,7 @@ export function ensureExportedLinksAreCorrect( } export function ensureExportedSpanIsCorrect( - span: otlpTypes.opentelemetryProto.trace.v1.Span + span: ISpan ) { if (span.attributes) { ensureExportedAttributesAreCorrect(span.attributes); @@ -254,7 +254,6 @@ export function ensureExportedSpanIsCorrect( span.status, { code: 'STATUS_CODE_OK', - deprecatedCode: 'DEPRECATED_STATUS_CODE_OK', message: '', }, 'status is wrong' @@ -262,7 +261,7 @@ export function ensureExportedSpanIsCorrect( } export function ensureResourceIsCorrect( - resource: otlpTypes.opentelemetryProto.resource.v1.Resource + resource: IResource ) { assert.deepStrictEqual(resource, { attributes: [ diff --git a/experimental/packages/exporter-trace-otlp-grpc/tsconfig.json b/experimental/packages/exporter-trace-otlp-grpc/tsconfig.json index 4a71bbfef6a..94d47b6e191 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/tsconfig.json +++ b/experimental/packages/exporter-trace-otlp-grpc/tsconfig.json @@ -18,14 +18,14 @@ { "path": "../../../packages/opentelemetry-sdk-trace-base" }, - { - "path": "../exporter-trace-otlp-http" - }, { "path": "../otlp-exporter-base" }, { "path": "../otlp-grpc-exporter-base" + }, + { + "path": "../otlp-transformer" } ] } diff --git a/experimental/packages/exporter-trace-otlp-http/package.json b/experimental/packages/exporter-trace-otlp-http/package.json index c4e631b0b82..5d0fadbc02b 100644 --- a/experimental/packages/exporter-trace-otlp-http/package.json +++ b/experimental/packages/exporter-trace-otlp-http/package.json @@ -97,6 +97,7 @@ "@opentelemetry/core": "1.2.0", "@opentelemetry/resources": "1.2.0", "@opentelemetry/sdk-trace-base": "1.2.0", - "@opentelemetry/otlp-exporter-base": "0.28.0" + "@opentelemetry/otlp-exporter-base": "0.28.0", + "@opentelemetry/otlp-transformer": "0.28.0" } } diff --git a/experimental/packages/exporter-trace-otlp-http/src/index.ts b/experimental/packages/exporter-trace-otlp-http/src/index.ts index d22bb9029d6..52ec5f71f5e 100644 --- a/experimental/packages/exporter-trace-otlp-http/src/index.ts +++ b/experimental/packages/exporter-trace-otlp-http/src/index.ts @@ -15,5 +15,3 @@ */ export * from './platform'; -export * as otlpTypes from './types'; -export { toCollectorResource, toOTLPExportTraceServiceRequest } from './transform'; 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 28411089f6c..d066f0a4597 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 @@ -16,10 +16,9 @@ import { appendResourcePathToUrlIfNotPresent, OTLPExporterBrowserBase } from '@opentelemetry/otlp-exporter-base'; import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'; -import { toOTLPExportTraceServiceRequest } from '../../transform'; -import * as otlpTypes from '../../types'; import { getEnv, baggageUtils } from '@opentelemetry/core'; import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; +import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/traces'; const DEFAULT_COLLECTOR_URL=`http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`; @@ -30,7 +29,7 @@ const DEFAULT_COLLECTOR_URL=`http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_P export class OTLPTraceExporter extends OTLPExporterBrowserBase< ReadableSpan, - otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest + IExportTraceServiceRequest > implements SpanExporter { constructor(config: OTLPExporterConfigBase = {}) { @@ -44,8 +43,8 @@ export class OTLPTraceExporter } convert( spans: ReadableSpan[] - ): otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { - return toOTLPExportTraceServiceRequest(spans, this, true); + ): IExportTraceServiceRequest { + return createExportTraceServiceRequest(spans); } getDefaultUrl(config: OTLPExporterConfigBase): string { 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 d4a6e21a937..1b2cd892199 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 @@ -15,14 +15,13 @@ */ import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'; -import * as otlpTypes from '../../types'; -import { toOTLPExportTraceServiceRequest } from '../../transform'; import { getEnv, baggageUtils } from '@opentelemetry/core'; import { OTLPExporterNodeBase } from '@opentelemetry/otlp-exporter-base'; import { OTLPExporterNodeConfigBase, appendResourcePathToUrlIfNotPresent } from '@opentelemetry/otlp-exporter-base'; +import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/traces'; const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`; @@ -32,7 +31,7 @@ const DEFAULT_COLLECTOR_URL = `http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE */ export class OTLPTraceExporter extends OTLPExporterNodeBase + IExportTraceServiceRequest> implements SpanExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { super(config); @@ -46,8 +45,8 @@ export class OTLPTraceExporter convert( spans: ReadableSpan[] - ): otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { - return toOTLPExportTraceServiceRequest(spans, this, true); + ): IExportTraceServiceRequest { + return createExportTraceServiceRequest(spans, true); } getDefaultUrl(config: OTLPExporterNodeConfigBase): string { diff --git a/experimental/packages/exporter-trace-otlp-http/src/transform.ts b/experimental/packages/exporter-trace-otlp-http/src/transform.ts deleted file mode 100644 index 5224c527fa6..00000000000 --- a/experimental/packages/exporter-trace-otlp-http/src/transform.ts +++ /dev/null @@ -1,367 +0,0 @@ -/* - * 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 { - SpanAttributes, - Link, - SpanKind, - SpanStatus, - TraceState, -} from '@opentelemetry/api'; -import * as core from '@opentelemetry/core'; -import { Resource } from '@opentelemetry/resources'; -import { ReadableSpan, TimedEvent } from '@opentelemetry/sdk-trace-base'; -import { - OTLP_SPAN_KIND_MAPPING, - opentelemetryProto, -} from './types'; -import { OTLPExporterBase, OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; - -const MAX_INTEGER_VALUE = 2147483647; -const MIN_INTEGER_VALUE = -2147483648; - -/** - * Converts attributes to KeyValue array - * @param attributes - */ -export function toCollectorAttributes( - attributes: SpanAttributes -): opentelemetryProto.common.v1.KeyValue[] { - return Object.keys(attributes).map(key => { - return toCollectorAttributeKeyValue(key, attributes[key]); - }); -} - -/** - * Converts array of unknown value to ArrayValue - * @param values - */ -export function toCollectorArrayValue( - values: unknown[] -): opentelemetryProto.common.v1.ArrayValue { - return { - values: values.map(value => toCollectorAnyValue(value)), - }; -} - -/** - * Converts attributes to KeyValueList - * @param attributes - */ -export function toCollectorKeyValueList( - attributes: SpanAttributes -): opentelemetryProto.common.v1.KeyValueList { - return { - values: toCollectorAttributes(attributes), - }; -} - -/** - * Converts key and unknown value to KeyValue - * @param value event value - */ -export function toCollectorAttributeKeyValue( - key: string, - value: unknown -): opentelemetryProto.common.v1.KeyValue { - const anyValue = toCollectorAnyValue(value); - return { - key, - value: anyValue, - }; -} - -/** - * Converts unknown value to AnyValue - * @param value - */ -export function toCollectorAnyValue( - value: unknown -): opentelemetryProto.common.v1.AnyValue { - const anyValue: opentelemetryProto.common.v1.AnyValue = {}; - if (typeof value === 'string') { - anyValue.stringValue = value; - } else if (typeof value === 'boolean') { - anyValue.boolValue = value; - } else if ( - typeof value === 'number' && - value <= MAX_INTEGER_VALUE && - value >= MIN_INTEGER_VALUE && - Number.isInteger(value) - ) { - anyValue.intValue = value; - } else if (typeof value === 'number') { - anyValue.doubleValue = value; - } else if (Array.isArray(value)) { - anyValue.arrayValue = toCollectorArrayValue(value); - } else if (value) { - anyValue.kvlistValue = toCollectorKeyValueList(value as SpanAttributes); - } - return anyValue; -} - -/** - * - * Converts events - * @param events array of events - */ -export function toCollectorEvents( - timedEvents: TimedEvent[] -): opentelemetryProto.trace.v1.Span.Event[] { - return timedEvents.map(timedEvent => { - const timeUnixNano = core.hrTimeToNanoseconds(timedEvent.time); - const name = timedEvent.name; - const attributes = toCollectorAttributes(timedEvent.attributes || {}); - const droppedAttributesCount = 0; - - const protoEvent: opentelemetryProto.trace.v1.Span.Event = { - timeUnixNano, - name, - attributes, - droppedAttributesCount, - }; - - return protoEvent; - }); -} - -/** - * Converts links - * @param span - * @param useHex - if ids should be kept as hex without converting to base64 - */ -function toCollectorLinks( - span: ReadableSpan, - useHex?: boolean -): opentelemetryProto.trace.v1.Span.Link[] { - return span.links.map((link: Link) => { - const protoLink: opentelemetryProto.trace.v1.Span.Link = { - traceId: useHex - ? link.context.traceId - : core.hexToBase64(link.context.traceId), - spanId: useHex - ? link.context.spanId - : core.hexToBase64(link.context.spanId), - attributes: toCollectorAttributes(link.attributes || {}), - droppedAttributesCount: 0, - }; - return protoLink; - }); -} - -/** - * Converts span - * @param span - * @param useHex - if ids should be kept as hex without converting to base64 - */ -export function toCollectorSpan( - span: ReadableSpan, - useHex?: boolean -): opentelemetryProto.trace.v1.Span { - return { - traceId: useHex - ? span.spanContext().traceId - : core.hexToBase64(span.spanContext().traceId), - spanId: useHex - ? span.spanContext().spanId - : core.hexToBase64(span.spanContext().spanId), - parentSpanId: span.parentSpanId - ? useHex - ? span.parentSpanId - : core.hexToBase64(span.parentSpanId) - : undefined, - traceState: toCollectorTraceState(span.spanContext().traceState), - name: span.name, - kind: toCollectorKind(span.kind), - startTimeUnixNano: core.hrTimeToNanoseconds(span.startTime), - endTimeUnixNano: core.hrTimeToNanoseconds(span.endTime), - attributes: toCollectorAttributes(span.attributes), - droppedAttributesCount: 0, - events: toCollectorEvents(span.events), - droppedEventsCount: 0, - status: toCollectorStatus(span.status), - links: toCollectorLinks(span, useHex), - droppedLinksCount: 0, - }; -} - -/** - * Converts status - * @param status - */ -export function toCollectorStatus( - status: SpanStatus -): opentelemetryProto.trace.v1.SpanStatus { - const spanStatus: opentelemetryProto.trace.v1.SpanStatus = { - code: status.code, - }; - if (typeof status.message !== 'undefined') { - spanStatus.message = status.message; - } - return spanStatus; -} - -/** - * Converts resource - * @param resource - * @param additionalAttributes - */ -export function toCollectorResource( - resource?: Resource, - additionalAttributes: { [key: string]: unknown } = {} -): opentelemetryProto.resource.v1.Resource { - const attr = Object.assign( - {}, - additionalAttributes, - resource ? resource.attributes : {} - ); - const resourceProto: opentelemetryProto.resource.v1.Resource = { - attributes: toCollectorAttributes(attr), - droppedAttributesCount: 0, - }; - - return resourceProto; -} - -/** - * Converts span kind - * @param kind - */ -export function toCollectorKind( - kind: SpanKind -): opentelemetryProto.trace.v1.Span.SpanKind { - const collectorKind = OTLP_SPAN_KIND_MAPPING[kind]; - return typeof collectorKind === 'number' - ? collectorKind - : opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_UNSPECIFIED; -} - -/** - * Converts traceState - * @param traceState - */ -export function toCollectorTraceState( - traceState?: TraceState -): opentelemetryProto.trace.v1.Span.TraceState | undefined { - if (!traceState) return undefined; - return traceState.serialize(); -} - -/** - * Prepares trace service request to be sent to collector - * @param spans spans - * @param collectorExporterBase - * @param useHex - if ids should be kept as hex without converting to base64 - */ -export function toOTLPExportTraceServiceRequest< - T extends OTLPExporterConfigBase ->( - spans: ReadableSpan[], - collectorTraceExporterBase: OTLPExporterBase< - T, - ReadableSpan, - opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest - >, - useHex?: boolean -): opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { - const groupedSpans: Map< - Resource, - Map - > = groupSpansByResourceAndLibrary(spans); - - const additionalAttributes = Object.assign( - {}, - collectorTraceExporterBase.attributes - ); - - return { - resourceSpans: toCollectorResourceSpans( - groupedSpans, - additionalAttributes, - useHex - ), - }; -} - -/** - * Takes an array of spans and groups them by resource and instrumentation - * library - * @param spans spans - */ -export function groupSpansByResourceAndLibrary( - spans: ReadableSpan[] -): Map> { - return spans.reduce((spanMap, span) => { - //group by resource - let resourceSpans = spanMap.get(span.resource); - if (!resourceSpans) { - resourceSpans = new Map(); - spanMap.set(span.resource, resourceSpans); - } - //group by instrumentation library - let libSpans = resourceSpans.get(span.instrumentationLibrary); - if (!libSpans) { - libSpans = new Array(); - resourceSpans.set(span.instrumentationLibrary, libSpans); - } - libSpans.push(span); - return spanMap; - }, new Map>()); -} - -/** - * Convert to InstrumentationLibrarySpans - * @param instrumentationLibrary - * @param spans - * @param useHex - if ids should be kept as hex without converting to base64 - */ -function toCollectorInstrumentationLibrarySpans( - instrumentationLibrary: core.InstrumentationLibrary, - spans: ReadableSpan[], - useHex?: boolean -): opentelemetryProto.trace.v1.InstrumentationLibrarySpans { - return { - spans: spans.map(span => toCollectorSpan(span, useHex)), - instrumentationLibrary, - }; -} - -/** - * Returns a list of resource spans which will be exported to the collector - * @param groupedSpans - * @param baseAttributes - * @param useHex - if ids should be kept as hex without converting to base64 - */ -function toCollectorResourceSpans( - groupedSpans: Map>, - baseAttributes: SpanAttributes, - useHex?: boolean -): opentelemetryProto.trace.v1.ResourceSpans[] { - return Array.from(groupedSpans, ([resource, libSpans]) => { - return { - resource: toCollectorResource(resource, baseAttributes), - instrumentationLibrarySpans: Array.from( - libSpans, - ([instrumentationLibrary, spans]) => - toCollectorInstrumentationLibrarySpans( - instrumentationLibrary, - spans, - useHex - ) - ), - }; - }); -} diff --git a/experimental/packages/exporter-trace-otlp-http/src/types.ts b/experimental/packages/exporter-trace-otlp-http/src/types.ts deleted file mode 100644 index 02be0ed2e44..00000000000 --- a/experimental/packages/exporter-trace-otlp-http/src/types.ts +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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 { SpanKind, SpanStatusCode } from '@opentelemetry/api'; - -/* eslint-disable @typescript-eslint/no-namespace */ -/* eslint-disable @typescript-eslint/no-unused-vars */ - -export namespace opentelemetryProto { - export namespace collector { - export namespace trace.v1 { - export interface TraceService { - service: opentelemetryProto.collector.trace.v1.TraceService; - } - - export interface ExportTraceServiceRequest { - resourceSpans: opentelemetryProto.trace.v1.ResourceSpans[]; - } - } - export namespace metrics.v1 { - export interface ExportMetricsServiceRequest { - resourceMetrics: opentelemetryProto.metrics.v1.ResourceMetrics[]; - } - } - } - - export namespace resource.v1 { - export interface Resource { - attributes: opentelemetryProto.common.v1.KeyValue[]; - droppedAttributesCount: number; - } - } - - export namespace metrics.v1 { - export interface Metric { - name: string; - description: string; - unit: string; - // data: - intGauge?: opentelemetryProto.metrics.v1.Gauge; - doubleGauge?: opentelemetryProto.metrics.v1.Gauge; - intSum?: opentelemetryProto.metrics.v1.Sum; - doubleSum?: opentelemetryProto.metrics.v1.Sum; - intHistogram?: opentelemetryProto.metrics.v1.Histogram; - doubleHistogram?: opentelemetryProto.metrics.v1.Histogram; - } - - export interface Gauge { - dataPoints: opentelemetryProto.metrics.v1.DataPoint[]; - } - - export interface Sum { - dataPoints: opentelemetryProto.metrics.v1.DataPoint[]; - aggregationTemporality: opentelemetryProto.metrics.v1.AggregationTemporality; - isMonotonic: boolean; - } - - export interface Histogram { - dataPoints: opentelemetryProto.metrics.v1.HistogramDataPoint[]; - aggregationTemporality: opentelemetryProto.metrics.v1.AggregationTemporality; - } - - export interface DataPoint { - labels: opentelemetryProto.common.v1.StringKeyValue[]; - startTimeUnixNano: number; - timeUnixNano: number; - value: number; - exemplars?: opentelemetryProto.metrics.v1.Exemplar[]; - } - - export interface Exemplar { - filteredLabels: opentelemetryProto.common.v1.StringKeyValue[]; - timeUnixNano: number; - value: number; - spanId: Uint8Array; - traceId: Uint8Array; - } - - export interface HistogramDataPoint { - labels: opentelemetryProto.common.v1.StringKeyValue[]; - startTimeUnixNano: number; - timeUnixNano: number; - count: number; - sum: number; - bucketCounts?: number[]; - explicitBounds?: number[]; - exemplars?: opentelemetryProto.metrics.v1.Exemplar[][]; - } - - export interface InstrumentationLibraryMetrics { - instrumentationLibrary?: opentelemetryProto.common.v1.InstrumentationLibrary; - metrics: opentelemetryProto.metrics.v1.Metric[]; - } - - export interface ResourceMetrics { - resource?: opentelemetryProto.resource.v1.Resource; - instrumentationLibraryMetrics: opentelemetryProto.metrics.v1.InstrumentationLibraryMetrics[]; - } - - export enum AggregationTemporality { - // UNSPECIFIED is the default AggregationTemporality, it MUST not be used. - AGGREGATION_TEMPORALITY_UNSPECIFIED = 0, - - // DELTA is an AggregationTemporality for a metric aggregator which reports - // changes since last report time. Successive metrics contain aggregation of - // values from continuous and non-overlapping intervals. - // - // The values for a DELTA metric are based only on the time interval - // associated with one measurement cycle. There is no dependency on - // previous measurements like is the case for CUMULATIVE metrics. - // - // For example, consider a system measuring the number of requests that - // it receives and reports the sum of these requests every second as a - // DELTA metric: - // - // 1. The system starts receiving at time=t_0. - // 2. A request is received, the system measures 1 request. - // 3. A request is received, the system measures 1 request. - // 4. A request is received, the system measures 1 request. - // 5. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+1 with a value of 3. - // 6. A request is received, the system measures 1 request. - // 7. A request is received, the system measures 1 request. - // 8. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0+1 to - // t_0+2 with a value of 2. - AGGREGATION_TEMPORALITY_DELTA = 1, - - // CUMULATIVE is an AggregationTemporality for a metric aggregator which - // reports changes since a fixed start time. This means that current values - // of a CUMULATIVE metric depend on all previous measurements since the - // start time. Because of this, the sender is required to retain this state - // in some form. If this state is lost or invalidated, the CUMULATIVE metric - // values MUST be reset and a new fixed start time following the last - // reported measurement time sent MUST be used. - // - // For example, consider a system measuring the number of requests that - // it receives and reports the sum of these requests every second as a - // CUMULATIVE metric: - // - // 1. The system starts receiving at time=t_0. - // 2. A request is received, the system measures 1 request. - // 3. A request is received, the system measures 1 request. - // 4. A request is received, the system measures 1 request. - // 5. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+1 with a value of 3. - // 6. A request is received, the system measures 1 request. - // 7. A request is received, the system measures 1 request. - // 8. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_0 to - // t_0+2 with a value of 5. - // 9. The system experiences a fault and loses state. - // 10. The system recovers and resumes receiving at time=t_1. - // 11. A request is received, the system measures 1 request. - // 12. The 1 second collection cycle ends. A metric is exported for the - // number of requests received over the interval of time t_1 to - // t_0+1 with a value of 1. - // - // Note: Even though, when reporting changes since last report time, using - // CUMULATIVE is valid, it is not recommended. This may cause problems for - // systems that do not use start_time to determine when the aggregation - // value was reset (e.g. Prometheus). - AGGREGATION_TEMPORALITY_CUMULATIVE = 2, - } - } - - export namespace trace.v1 { - export namespace ConstantSampler { - export enum ConstantDecision { - ALWAYS_OFF = 0, - ALWAYS_ON = 1, - ALWAYS_PARENT = 2, - } - } - export namespace Span { - export interface Event { - timeUnixNano: number; - name: string; - attributes?: opentelemetryProto.common.v1.KeyValue[]; - droppedAttributesCount: number; - } - - export interface Link { - traceId: string; - spanId: string; - traceState?: opentelemetryProto.trace.v1.Span.TraceState; - attributes?: opentelemetryProto.common.v1.KeyValue[]; - droppedAttributesCount: number; - } - - // eslint-disable-next-line @typescript-eslint/no-shadow - export enum SpanKind { - SPAN_KIND_UNSPECIFIED, - SPAN_KIND_INTERNAL, - SPAN_KIND_SERVER, - SPAN_KIND_CLIENT, - SPAN_KIND_PRODUCER, - SPAN_KIND_CONSUMER, - } - - export type TraceState = string | undefined; - } - - export interface ConstantSampler { - decision?: opentelemetryProto.trace.v1.ConstantSampler.ConstantDecision; - } - - export interface InstrumentationLibrarySpans { - instrumentationLibrary?: opentelemetryProto.common.v1.InstrumentationLibrary; - spans: opentelemetryProto.trace.v1.Span[]; - } - - export interface ProbabilitySampler { - samplingProbability?: number | null; - } - - export interface RateLimitingSampler { - qps?: number | null; - } - - export interface ResourceSpans { - resource?: opentelemetryProto.resource.v1.Resource; - instrumentationLibrarySpans: opentelemetryProto.trace.v1.InstrumentationLibrarySpans[]; - } - - export interface Span { - traceId: string; - spanId: string; - traceState: opentelemetryProto.trace.v1.Span.TraceState; - parentSpanId?: string; - name?: string; - kind?: opentelemetryProto.trace.v1.Span.SpanKind; - startTimeUnixNano?: number; - endTimeUnixNano?: number; - attributes?: opentelemetryProto.common.v1.KeyValue[]; - droppedAttributesCount: number; - events?: opentelemetryProto.trace.v1.Span.Event[]; - droppedEventsCount: number; - links?: opentelemetryProto.trace.v1.Span.Link[]; - droppedLinksCount: number; - status?: SpanStatus; - } - - export interface SpanStatus { - /** The status code of this message. */ - code: SpanStatusCode; - /** A developer-facing error message. */ - message?: string; - } - - export interface TraceConfig { - constantSampler?: ConstantSampler | null; - probabilitySampler?: ProbabilitySampler | null; - rateLimitingSampler?: RateLimitingSampler | null; - } - } - export namespace common.v1 { - export interface KeyValue { - key: string; - value: AnyValue; - } - - export type ArrayValue = { - values: AnyValue[]; - }; - - export interface KeyValueList { - values: KeyValue[]; - } - - export type AnyValue = { - stringValue?: string; - boolValue?: boolean; - intValue?: number; - doubleValue?: number; - arrayValue?: ArrayValue; - kvlistValue?: KeyValueList; - }; - - export interface InstrumentationLibrary { - name: string; - version?: string; - } - - export interface StringKeyValue { - key: string; - value: string; - } - - export enum ValueType { - STRING, - INT, - DOUBLE, - BOOL, - } - } -} - -/** - * Mapping between api SpanKind and proto SpanKind - */ -export const OTLP_SPAN_KIND_MAPPING = { - [SpanKind.INTERNAL]: - opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_INTERNAL, - [SpanKind.SERVER]: opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_SERVER, - [SpanKind.CLIENT]: opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_CLIENT, - [SpanKind.PRODUCER]: - opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_PRODUCER, - [SpanKind.CONSUMER]: - opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_CONSUMER, -}; 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 1f57a5e959a..ba08f359c08 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 @@ -20,7 +20,6 @@ import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import * as sinon from 'sinon'; import { OTLPTraceExporter } from '../../src/platform/browser/index'; -import * as otlpTypes from '../../src/types'; import { ensureSpanIsCorrect, @@ -30,6 +29,7 @@ import { mockedReadableSpan, } from '../traceHelper'; import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base'; +import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; describe('OTLPTraceExporter - web', () => { let collectorTraceExporter: OTLPTraceExporter; @@ -109,16 +109,16 @@ describe('OTLPTraceExporter - web', () => { const body = await blob.text(); const json = JSON.parse( body - ) as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + ) as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureSpanIsCorrect(span1); } - const resource = json.resourceSpans[0].resource; + const resource = json.resourceSpans?.[0].resource; assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); if (resource) { ensureWebResourceIsCorrect(resource); @@ -200,16 +200,16 @@ describe('OTLPTraceExporter - web', () => { const body = request.requestBody; const json = JSON.parse( body - ) as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + ) as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureSpanIsCorrect(span1); } - const resource = json.resourceSpans[0].resource; + const resource = json.resourceSpans?.[0].resource; assert.ok(typeof resource !== 'undefined', "resource doesn't exist"); if (resource) { ensureWebResourceIsCorrect(resource); diff --git a/experimental/packages/exporter-trace-otlp-http/test/browser/index-webpack.ts b/experimental/packages/exporter-trace-otlp-http/test/browser/index-webpack.ts index 99100a0f6ee..ae7d4b5a9dd 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/browser/index-webpack.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/browser/index-webpack.ts @@ -16,8 +16,5 @@ const testsContext = require.context('../browser', true, /test$/); testsContext.keys().forEach(testsContext); -const testsContextCommon = require.context('../common', true, /test$/); -testsContextCommon.keys().forEach(testsContextCommon); - const srcContext = require.context('.', true, /src$/); srcContext.keys().forEach(srcContext); diff --git a/experimental/packages/exporter-trace-otlp-http/test/common/transform.test.ts b/experimental/packages/exporter-trace-otlp-http/test/common/transform.test.ts deleted file mode 100644 index 94932201b74..00000000000 --- a/experimental/packages/exporter-trace-otlp-http/test/common/transform.test.ts +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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 { SpanAttributes, SpanStatusCode } from '@opentelemetry/api'; -import { TimedEvent } from '@opentelemetry/sdk-trace-base'; -import * as assert from 'assert'; -import * as transform from '../../src/transform'; -import { - ensureSpanIsCorrect, - mockedReadableSpan, - mockedResources, - mockedInstrumentationLibraries, - multiResourceTrace, - multiInstrumentationLibraryTrace, -} from '../traceHelper'; -import { Resource } from '@opentelemetry/resources'; - -describe('transform', () => { - describe('toCollectorAttributes', () => { - it('should convert attribute string', () => { - const attributes: SpanAttributes = { - foo: 'bar', - }; - assert.deepStrictEqual(transform.toCollectorAttributes(attributes), [ - { key: 'foo', value: { stringValue: 'bar' } }, - ]); - }); - - it('should convert attribute integer to integer', () => { - const attributes: SpanAttributes = { - foo: 13, - }; - assert.deepStrictEqual(transform.toCollectorAttributes(attributes), [ - { key: 'foo', value: { intValue: 13 } }, - ]); - }); - - it('should convert attribute integer to double', () => { - const attributes: SpanAttributes = { - foo: 2247483647, - }; - assert.deepStrictEqual(transform.toCollectorAttributes(attributes), [ - { key: 'foo', value: { doubleValue: 2247483647 } }, - ]); - }); - - it('should convert attribute boolean', () => { - const attributes: SpanAttributes = { - foo: true, - }; - assert.deepStrictEqual(transform.toCollectorAttributes(attributes), [ - { key: 'foo', value: { boolValue: true } }, - ]); - }); - - it('should convert attribute double', () => { - const attributes: SpanAttributes = { - foo: 1.34, - }; - assert.deepStrictEqual(transform.toCollectorAttributes(attributes), [ - { key: 'foo', value: { doubleValue: 1.34 } }, - ]); - }); - }); - - describe('toCollectorEvents', () => { - it('should convert events to otc events', () => { - const events: TimedEvent[] = [ - { name: 'foo', time: [123, 123], attributes: { a: 'b' } }, - { - name: 'foo2', - time: [321, 321], - attributes: { c: 'd' }, - }, - ]; - assert.deepStrictEqual(transform.toCollectorEvents(events), [ - { - timeUnixNano: 123000000123, - name: 'foo', - attributes: [{ key: 'a', value: { stringValue: 'b' } }], - droppedAttributesCount: 0, - }, - { - timeUnixNano: 321000000321, - name: 'foo2', - attributes: [{ key: 'c', value: { stringValue: 'd' } }], - droppedAttributesCount: 0, - }, - ]); - }); - }); - - describe('toCollectorAnyValue', () => { - it('should use correct type on array', () => { - assert.deepStrictEqual(transform.toCollectorAnyValue(['string', true, 1]), { - arrayValue: { - values: - [ - { stringValue: 'string' }, - { boolValue: true }, - { intValue: 1 } - ] - } - }); - }); - - it('should use correct type on kvlist', () => { - assert.deepStrictEqual(transform.toCollectorAnyValue({ string: 'string', boolean: true, integer: 1 }), { - kvlistValue: { - values: - [ - { key: 'string', value: { stringValue: 'string' } }, - { key: 'boolean', value: { boolValue: true } }, - { key: 'integer', value: { intValue: 1 } } - ] - } - }); - }); - }); - - describe('toCollectorStatus', () => { - it('should set message if status is not undefined', () => { - const result = transform.toCollectorStatus({ - code: SpanStatusCode.OK, - message: 'message' - }); - assert.deepStrictEqual(result.message, 'message'); - }); - }); - - describe('toCollectorSpan', () => { - it('should convert span using hex', () => { - ensureSpanIsCorrect(transform.toCollectorSpan(mockedReadableSpan, true)); - }); - it('should convert span using base64', () => { - ensureSpanIsCorrect(transform.toCollectorSpan(mockedReadableSpan), false); - }); - }); - - describe('toCollectorResource', () => { - it('should convert resource', () => { - const resource = transform.toCollectorResource( - new Resource({ - service: 'ui', - version: 1.0, - success: true, - }) - ); - assert.deepStrictEqual(resource, { - attributes: [ - { - key: 'service', - value: { stringValue: 'ui' }, - }, - { - key: 'version', - value: { intValue: 1 }, - }, - { key: 'success', value: { boolValue: true } }, - ], - droppedAttributesCount: 0, - }); - }); - }); - describe('groupSpansByResourceAndLibrary', () => { - it('should group by resource', () => { - const [resource1, resource2] = mockedResources; - const [instrumentationLibrary] = mockedInstrumentationLibraries; - const [span1, span2, span3] = multiResourceTrace; - - const expected = new Map([ - [resource1, new Map([[instrumentationLibrary, [span1]]])], - [resource2, new Map([[instrumentationLibrary, [span2, span3]]])], - ]); - - const result = transform.groupSpansByResourceAndLibrary( - multiResourceTrace - ); - - assert.deepStrictEqual(result, expected); - }); - - it('should group by instrumentation library', () => { - const [resource] = mockedResources; - const [lib1, lib2] = mockedInstrumentationLibraries; - const [span1, span2, span3] = multiInstrumentationLibraryTrace; - - const expected = new Map([ - [ - resource, - new Map([ - [lib1, [span1, span2]], - [lib2, [span3]], - ]), - ], - ]); - - const result = transform.groupSpansByResourceAndLibrary( - multiInstrumentationLibraryTrace - ); - - assert.deepStrictEqual(result, expected); - }); - }); -}); 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 6ddd63a0fcb..f4f18251a6c 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 @@ -30,13 +30,13 @@ import * as zlib from 'zlib'; import { OTLPTraceExporter } from '../../src/platform/node'; -import * as otlpTypes from '../../src/types'; import { ensureExportTraceServiceRequestIsSet, ensureSpanIsCorrect, mockedReadableSpan } from '../traceHelper'; import { MockedResponse } from './nodeHelpers'; +import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; let fakeRequest: PassThrough; @@ -229,9 +229,9 @@ describe('OTLPTraceExporter - node with json over http', () => { const json = JSON.parse( responseBody - ) as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + ) as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureSpanIsCorrect(span1); @@ -325,9 +325,9 @@ describe('OTLPTraceExporter - node with json over http', () => { const json = JSON.parse( responseBody - ) as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + ) as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureSpanIsCorrect(span1); diff --git a/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts index 1ad9e891a7d..85ba76b9e65 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts @@ -19,8 +19,15 @@ import { hexToBase64, InstrumentationLibrary, VERSION } from '@opentelemetry/cor import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; -import * as otlpTypes from '../src/types'; -import { opentelemetryProto } from '../src/types'; +import { + ESpanKind, + IEvent, + IExportTraceServiceRequest, + IKeyValue, + ILink, + IResource, + ISpan +} from '@opentelemetry/otlp-transformer'; if (typeof Buffer === 'undefined') { (window as any).Buffer = { @@ -208,7 +215,7 @@ export const multiInstrumentationLibraryTrace: ReadableSpan[] = [ ]; export function ensureEventsAreCorrect( - events: opentelemetryProto.trace.v1.Span.Event[] + events: IEvent[] ) { assert.deepStrictEqual( events, @@ -267,7 +274,7 @@ export function ensureEventsAreCorrect( } export function ensureAttributesAreCorrect( - attributes: opentelemetryProto.common.v1.KeyValue[] + attributes: IKeyValue[] ) { assert.deepStrictEqual( attributes, @@ -284,7 +291,7 @@ export function ensureAttributesAreCorrect( } export function ensureLinksAreCorrect( - attributes: opentelemetryProto.trace.v1.Span.Link[], + attributes: ILink[], useHex?: boolean ) { assert.deepStrictEqual( @@ -309,7 +316,7 @@ export function ensureLinksAreCorrect( } export function ensureSpanIsCorrect( - span: otlpTypes.opentelemetryProto.trace.v1.Span, + span: ISpan, useHex = true ) { if (span.attributes) { @@ -339,7 +346,7 @@ export function ensureSpanIsCorrect( assert.strictEqual(span.name, 'documentFetch', 'name is wrong'); assert.strictEqual( span.kind, - opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_INTERNAL, + ESpanKind.SPAN_KIND_INTERNAL, 'kind is wrong' ); assert.strictEqual( @@ -367,7 +374,7 @@ export function ensureSpanIsCorrect( } export function ensureWebResourceIsCorrect( - resource: otlpTypes.opentelemetryProto.resource.v1.Resource + resource: IResource ) { assert.strictEqual(resource.attributes.length, 7); assert.strictEqual(resource.attributes[0].key, 'service.name'); @@ -388,7 +395,7 @@ export function ensureWebResourceIsCorrect( } export function ensureExportTraceServiceRequestIsSet( - json: otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest + json: IExportTraceServiceRequest ) { const resourceSpans = json.resourceSpans; assert.strictEqual( @@ -397,11 +404,11 @@ export function ensureExportTraceServiceRequestIsSet( 'resourceSpans is missing' ); - const resource = resourceSpans[0].resource; + const resource = resourceSpans?.[0].resource; assert.strictEqual(!!resource, true, 'resource is missing'); const instrumentationLibrarySpans = - resourceSpans[0].instrumentationLibrarySpans; + resourceSpans?.[0].instrumentationLibrarySpans; assert.strictEqual( instrumentationLibrarySpans && instrumentationLibrarySpans.length, 1, @@ -409,14 +416,14 @@ export function ensureExportTraceServiceRequestIsSet( ); const instrumentationLibrary = - instrumentationLibrarySpans[0].instrumentationLibrary; + instrumentationLibrarySpans?.[0].instrumentationLibrary; assert.strictEqual( !!instrumentationLibrary, true, 'instrumentationLibrary is missing' ); - const spans = instrumentationLibrarySpans[0].spans; + const spans = instrumentationLibrarySpans?.[0].spans; assert.strictEqual(spans && spans.length, 1, 'spans are missing'); } diff --git a/experimental/packages/exporter-trace-otlp-http/tsconfig.json b/experimental/packages/exporter-trace-otlp-http/tsconfig.json index 82df98e67bc..087c804079c 100644 --- a/experimental/packages/exporter-trace-otlp-http/tsconfig.json +++ b/experimental/packages/exporter-trace-otlp-http/tsconfig.json @@ -20,6 +20,9 @@ }, { "path": "../otlp-exporter-base" + }, + { + "path": "../otlp-transformer" } ] } diff --git a/experimental/packages/exporter-trace-otlp-proto/package.json b/experimental/packages/exporter-trace-otlp-proto/package.json index f1c7071e65a..5b5405d91c4 100644 --- a/experimental/packages/exporter-trace-otlp-proto/package.json +++ b/experimental/packages/exporter-trace-otlp-proto/package.json @@ -73,6 +73,7 @@ "@opentelemetry/sdk-trace-base": "1.2.0", "@opentelemetry/otlp-exporter-base": "0.28.0", "@opentelemetry/otlp-proto-exporter-base": "0.28.0", - "protobufjs": "^6.9.0" + "protobufjs": "^6.9.0", + "@opentelemetry/otlp-transformer": "0.28.0" } } diff --git a/experimental/packages/exporter-trace-otlp-proto/src/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-proto/src/OTLPTraceExporter.ts index bb26b949bcc..1dafd5b8e8d 100644 --- a/experimental/packages/exporter-trace-otlp-proto/src/OTLPTraceExporter.ts +++ b/experimental/packages/exporter-trace-otlp-proto/src/OTLPTraceExporter.ts @@ -15,13 +15,10 @@ */ import { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base'; -import { - otlpTypes, - toOTLPExportTraceServiceRequest -} from '@opentelemetry/exporter-trace-otlp-http'; import { getEnv, baggageUtils } from '@opentelemetry/core'; import { appendResourcePathToUrlIfNotPresent, OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base'; import { OTLPProtoExporterNodeBase, ServiceClientType } from '@opentelemetry/otlp-proto-exporter-base'; +import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; const DEFAULT_COLLECTOR_RESOURCE_PATH = '/v1/traces'; const DEFAULT_COLLECTOR_URL=`http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_PATH}`; @@ -32,7 +29,7 @@ const DEFAULT_COLLECTOR_URL=`http://localhost:4318${DEFAULT_COLLECTOR_RESOURCE_P export class OTLPTraceExporter extends OTLPProtoExporterNodeBase< ReadableSpan, - otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest + IExportTraceServiceRequest > implements SpanExporter { constructor(config: OTLPExporterNodeConfigBase = {}) { @@ -47,8 +44,8 @@ export class OTLPTraceExporter convert( spans: ReadableSpan[] - ): otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest { - return toOTLPExportTraceServiceRequest(spans, this); + ): IExportTraceServiceRequest { + return createExportTraceServiceRequest(spans); } getDefaultUrl(config: OTLPExporterNodeConfigBase) { diff --git a/experimental/packages/exporter-trace-otlp-proto/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/OTLPTraceExporter.test.ts index 9554fea1d84..1cd8121c6ec 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/OTLPTraceExporter.test.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/OTLPTraceExporter.test.ts @@ -16,9 +16,6 @@ import { diag } from '@opentelemetry/api'; import { ExportResultCode } from '@opentelemetry/core'; -import { - otlpTypes -} from '@opentelemetry/exporter-trace-otlp-http'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import * as http from 'http'; @@ -34,6 +31,7 @@ import { } from './traceHelper'; import { CompressionAlgorithm, OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base'; import { getExportRequestProto } from '@opentelemetry/otlp-proto-exporter-base'; +import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer'; const fakeRequest = { end: function () { }, @@ -155,9 +153,9 @@ describe('OTLPTraceExporter - node with proto over http', () => { fakeRequest.on('end', () => { const ExportTraceServiceRequestProto = getExportRequestProto(); const data = ExportTraceServiceRequestProto?.decode(buff); - const json = data?.toJSON() as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + const json = data?.toJSON() as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureProtoSpanIsCorrect(span1); @@ -242,9 +240,9 @@ describe('OTLPTraceExporter - node with proto over http', () => { const unzippedBuff = zlib.gunzipSync(buff); const ExportTraceServiceRequestProto = getExportRequestProto(); const data = ExportTraceServiceRequestProto?.decode(unzippedBuff); - const json = data?.toJSON() as otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + const json = data?.toJSON() as IExportTraceServiceRequest; const span1 = - json.resourceSpans[0].instrumentationLibrarySpans[0].spans[0]; + json.resourceSpans?.[0].instrumentationLibrarySpans?.[0].spans?.[0]; assert.ok(typeof span1 !== 'undefined', "span doesn't exist"); if (span1) { ensureProtoSpanIsCorrect(span1); diff --git a/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts index 86ff5dc32c0..9c8e7216ea9 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts @@ -16,11 +16,11 @@ import { SpanStatusCode, TraceFlags } from '@opentelemetry/api'; import { hexToBase64 } from '@opentelemetry/core'; -import { otlpTypes } from '@opentelemetry/exporter-trace-otlp-http'; import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import { Stream } from 'stream'; +import { IEvent, IExportTraceServiceRequest, IKeyValue, ILink, ISpan } from '@opentelemetry/otlp-transformer'; const traceIdHex = '1f1008dc8e270e85c40a0d7c3939b278'; const spanIdHex = '5e107261f64fa53e'; @@ -84,7 +84,7 @@ export const mockedReadableSpan: ReadableSpan = { }; export function ensureProtoEventsAreCorrect( - events: otlpTypes.opentelemetryProto.trace.v1.Span.Event[] + events: IEvent[] ) { assert.deepStrictEqual( events, @@ -135,7 +135,7 @@ export function ensureProtoEventsAreCorrect( } export function ensureProtoAttributesAreCorrect( - attributes: otlpTypes.opentelemetryProto.common.v1.KeyValue[] + attributes: IKeyValue[] ) { assert.deepStrictEqual( attributes, @@ -152,7 +152,7 @@ export function ensureProtoAttributesAreCorrect( } export function ensureProtoLinksAreCorrect( - attributes: otlpTypes.opentelemetryProto.trace.v1.Span.Link[] + attributes: ILink[] ) { assert.deepStrictEqual( attributes, @@ -176,7 +176,7 @@ export function ensureProtoLinksAreCorrect( } export function ensureProtoSpanIsCorrect( - span: otlpTypes.opentelemetryProto.trace.v1.Span + span: ISpan ) { if (span.attributes) { ensureProtoAttributesAreCorrect(span.attributes); @@ -229,7 +229,7 @@ export function ensureProtoSpanIsCorrect( } export function ensureExportTraceServiceRequestIsSet( - json: otlpTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest + json: IExportTraceServiceRequest ) { const resourceSpans = json.resourceSpans; assert.strictEqual( @@ -238,11 +238,11 @@ export function ensureExportTraceServiceRequestIsSet( 'resourceSpans is missing' ); - const resource = resourceSpans[0].resource; + const resource = resourceSpans?.[0].resource; assert.strictEqual(!!resource, true, 'resource is missing'); const instrumentationLibrarySpans = - resourceSpans[0].instrumentationLibrarySpans; + resourceSpans?.[0].instrumentationLibrarySpans; assert.strictEqual( instrumentationLibrarySpans && instrumentationLibrarySpans.length, 1, @@ -250,14 +250,14 @@ export function ensureExportTraceServiceRequestIsSet( ); const instrumentationLibrary = - instrumentationLibrarySpans[0].instrumentationLibrary; + instrumentationLibrarySpans?.[0].instrumentationLibrary; assert.strictEqual( !!instrumentationLibrary, true, 'instrumentationLibrary is missing' ); - const spans = instrumentationLibrarySpans[0].spans; + const spans = instrumentationLibrarySpans?.[0].spans; assert.strictEqual(spans && spans.length, 1, 'spans are missing'); } diff --git a/experimental/packages/exporter-trace-otlp-proto/tsconfig.json b/experimental/packages/exporter-trace-otlp-proto/tsconfig.json index 69212c48784..6ba9e30e473 100644 --- a/experimental/packages/exporter-trace-otlp-proto/tsconfig.json +++ b/experimental/packages/exporter-trace-otlp-proto/tsconfig.json @@ -26,6 +26,9 @@ }, { "path": "../otlp-proto-exporter-base" + }, + { + "path": "../otlp-transformer" } ] } diff --git a/experimental/packages/otlp-transformer/src/trace/index.ts b/experimental/packages/otlp-transformer/src/trace/index.ts index 1329fe7f031..95495dd67ae 100644 --- a/experimental/packages/otlp-transformer/src/trace/index.ts +++ b/experimental/packages/otlp-transformer/src/trace/index.ts @@ -20,7 +20,7 @@ import { toAttributes } from '../common/internal'; import { sdkSpanToOtlpSpan } from './internal'; import { IExportTraceServiceRequest } from './types'; -export function createExportTraceServiceRequest(spans: ReadableSpan[]): IExportTraceServiceRequest | null { +export function createExportTraceServiceRequest(spans: ReadableSpan[], useHex?: boolean): IExportTraceServiceRequest { return { resourceSpans: spanRecordsToResourceSpans(spans).map(({ resource, resourceSpans, resourceSchemaUrl }) => ({ resource: { @@ -29,7 +29,7 @@ export function createExportTraceServiceRequest(spans: ReadableSpan[]): IExportT }, instrumentationLibrarySpans: resourceSpans.map(({ instrumentationLibrary, instrumentationLibrarySpans, librarySchemaUrl }) => ({ instrumentationLibrary, - spans: instrumentationLibrarySpans.map(sdkSpanToOtlpSpan), + spans: instrumentationLibrarySpans.map(span => sdkSpanToOtlpSpan(span, useHex)), schemaUrl: librarySchemaUrl, })), schemaUrl: resourceSchemaUrl, diff --git a/experimental/packages/otlp-transformer/src/trace/internal.ts b/experimental/packages/otlp-transformer/src/trace/internal.ts index 02fe74af96b..87a8182c3f5 100644 --- a/experimental/packages/otlp-transformer/src/trace/internal.ts +++ b/experimental/packages/otlp-transformer/src/trace/internal.ts @@ -18,16 +18,19 @@ import { hrTimeToNanoseconds } from '@opentelemetry/core'; import type { ReadableSpan, TimedEvent } from '@opentelemetry/sdk-trace-base'; import { toAttributes } from '../common/internal'; import { EStatusCode, IEvent, ILink, ISpan } from './types'; +import * as core from '@opentelemetry/core'; export function sdkSpanToOtlpSpan( span: ReadableSpan, + useHex?: boolean ): ISpan { const ctx = span.spanContext(); const status = span.status; + const parentSpanId = useHex? span.parentSpanId : span.parentSpanId != null? core.hexToBase64(span.parentSpanId): undefined; return { - traceId: ctx.traceId, - spanId: ctx.spanId, - parentSpanId: span.parentSpanId, + traceId: useHex? ctx.traceId : core.hexToBase64(ctx.traceId), + spanId: useHex? ctx.spanId : core.hexToBase64(ctx.spanId), + parentSpanId: parentSpanId, name: span.name, // Span kind is offset by 1 because the API does not define a value for unset kind: span.kind == null ? 0 : span.kind + 1, @@ -42,16 +45,16 @@ export function sdkSpanToOtlpSpan( code: status.code as unknown as EStatusCode, message: status.message, }, - links: span.links.map(toOtlpLink), + links: span.links.map(link => toOtlpLink(link, useHex)), droppedLinksCount: 0, }; } -export function toOtlpLink(link: Link): ILink { +export function toOtlpLink(link: Link, useHex?: boolean): ILink { return { attributes: link.attributes ? toAttributes(link.attributes) : [], - spanId: link.context.spanId, - traceId: link.context.traceId, + spanId: useHex? link.context.spanId : core.hexToBase64(link.context.spanId), + traceId: useHex? link.context.traceId : core.hexToBase64(link.context.traceId), droppedAttributesCount: 0, }; } diff --git a/experimental/packages/otlp-transformer/test/trace.test.ts b/experimental/packages/otlp-transformer/test/trace.test.ts index 3bd7be6b4c7..830674ee389 100644 --- a/experimental/packages/otlp-transformer/test/trace.test.ts +++ b/experimental/packages/otlp-transformer/test/trace.test.ts @@ -161,24 +161,24 @@ describe('Trace', () => { }); it('returns null on an empty list', () => { - assert.deepStrictEqual(createExportTraceServiceRequest([]), { resourceSpans: [] }); + assert.deepStrictEqual(createExportTraceServiceRequest([], true), { resourceSpans: [] }); }); it('serializes a span', () => { - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.deepStrictEqual(exportRequest, expectedSpanJson); }); it('serializes a span', () => { - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.deepStrictEqual(exportRequest, expectedSpanJson); }); it('serializes a span without a parent', () => { (span as any).parentSpanId = undefined; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].parentSpanId, undefined); @@ -188,7 +188,7 @@ describe('Trace', () => { it('error', () => { span.status.code = SpanStatusCode.ERROR; span.status.message = 'error message'; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); const spanStatus = exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].status; assert.strictEqual(spanStatus?.code, EStatusCode.STATUS_CODE_ERROR); @@ -197,7 +197,7 @@ describe('Trace', () => { it('unset', () => { span.status.code = SpanStatusCode.UNSET; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].status.code, EStatusCode.STATUS_CODE_UNSET); }); @@ -206,31 +206,31 @@ describe('Trace', () => { describe('span kind', () => { it('consumer', () => { (span as any).kind = SpanKind.CONSUMER; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].kind, ESpanKind.SPAN_KIND_CONSUMER); }); it('internal', () => { (span as any).kind = SpanKind.INTERNAL; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].kind, ESpanKind.SPAN_KIND_INTERNAL); }); it('producer', () => { (span as any).kind = SpanKind.PRODUCER; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].kind, ESpanKind.SPAN_KIND_PRODUCER); }); it('server', () => { (span as any).kind = SpanKind.SERVER; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].kind, ESpanKind.SPAN_KIND_SERVER); }); it('unspecified', () => { (span as any).kind = undefined; - const exportRequest = createExportTraceServiceRequest([span]); + const exportRequest = createExportTraceServiceRequest([span], true); assert.ok(exportRequest); assert.strictEqual(exportRequest.resourceSpans?.[0].instrumentationLibrarySpans[0].spans?.[0].kind, ESpanKind.SPAN_KIND_UNSPECIFIED); });