diff --git a/CHANGELOG.md b/CHANGELOG.md index c17bee0a87..1cd66a1f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/ * perf(propagator-jaeger): improve deserializeSpanContext performance [#3541](https://github.com/open-telemetry/opentelemetry-js/pull/3541) @doochik * feat: support TraceState in SamplingResult [#3530](https://github.com/open-telemetry/opentelemetry-js/pull/3530) @raphael-theriault-swi * feat(sdk-trace-base): add diagnostic logging when spans are dropped [#3610](https://github.com/open-telemetry/opentelemetry-js/pull/3610) @neoeinstein +* feat: add unit to view instrument selection criteria [#3647](https://github.com/open-telemetry/opentelemetry-js/pull/3647) @jlabatut +* feat(tracing): expose dropped counts for attributes, events and links on span [#3576](https://github.com/open-telemetry/opentelemetry-js/pull/3576) @mohitk05 ### :bug: (Bug Fix) @@ -40,6 +42,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/ ### :house: (Internal) +* chore(exporter-jaeger): deprecate jaeger exporter [#3585](https://github.com/open-telemetry/opentelemetry-js/pull/3585) @pichlermarc * fix(sdk-metrics): fix flaky LastValueAggregator test by using fake timer [#3587](https://github.com/open-telemetry/opentelemetry-js/pull/3587) @pichlermarc * fix(test): fix failing tests by preventing source-map generation [#3642](https://github.com/open-telemetry/opentelemetry-js/pull/3642) @pichlermarc diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index f935d3471c..5b52050074 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. ### :rocket: (Enhancement) * feat(api): add `getActiveBaggage` API [#3385](https://github.com/open-telemetry/opentelemetry-js/pull/3385) +* feat(api): add optional `droppedAttributesCount` property in the `Link` interface [#3576](https://github.com/open-telemetry/opentelemetry-js/pull/3576) @mohitk05 ### :bug: (Bug Fix) diff --git a/api/src/trace/link.ts b/api/src/trace/link.ts index 1d81d38d69..2b7ed19dd7 100644 --- a/api/src/trace/link.ts +++ b/api/src/trace/link.ts @@ -37,4 +37,6 @@ export interface Link { context: SpanContext; /** A set of {@link SpanAttributes} on the link. */ attributes?: SpanAttributes; + /** Count of attributes of the link that were dropped due to collection limits */ + droppedAttributesCount?: number; } diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index e309a0f94a..ddf59a324b 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -28,6 +28,7 @@ All notable changes to experimental packages in this project will be documented * feat(sdk-node): install diag logger with OTEL_LOG_LEVEL [#3627](https://github.com/open-telemetry/opentelemetry-js/pull/3627) @legendecas * feat(otlp-exporter-base): add retries [#3207](https://github.com/open-telemetry/opentelemetry-js/pull/3207) @svetlanabrennan * feat(sdk-node): override IdGenerator when using NodeSDK [#3645](https://github.com/open-telemetry/opentelemetry-js/pull/3645) @haddasbronfman +* feat(otlp-transformer): expose dropped attributes, events and links counts on the transformed otlp span [#3576](https://github.com/open-telemetry/opentelemetry-js/pull/3576) @mohitk05 ### :bug: (Bug Fix) diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts index e95868f305..6ce80bf2c2 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-grpc/test/traceHelper.ts @@ -61,22 +61,34 @@ export const mockedReadableSpan: ReadableSpan = { }, ], events: [ - { name: 'fetchStart', time: [1574120165, 429803070] }, + { + name: 'fetchStart', + time: [1574120165, 429803070], + }, { name: 'domainLookupStart', time: [1574120165, 429803070], }, - { name: 'domainLookupEnd', time: [1574120165, 429803070] }, + { + name: 'domainLookupEnd', + time: [1574120165, 429803070], + }, { name: 'connectStart', time: [1574120165, 429803070], }, - { name: 'connectEnd', time: [1574120165, 429803070] }, + { + name: 'connectEnd', + time: [1574120165, 429803070], + }, { name: 'requestStart', time: [1574120165, 435513070], }, - { name: 'responseStart', time: [1574120165, 436923070] }, + { + name: 'responseStart', + time: [1574120165, 436923070], + }, { name: 'responseEnd', time: [1574120165, 438688070], @@ -91,6 +103,9 @@ export const mockedReadableSpan: ReadableSpan = { }) ), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; export function ensureExportedEventsAreCorrect(events: IEvent[]) { diff --git a/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts index feab35b55e..06e256d253 100644 --- a/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-http/test/traceHelper.ts @@ -72,22 +72,34 @@ export const mockedReadableSpan: ReadableSpan = { }, ], events: [ - { name: 'fetchStart', time: [1574120165, 429803070] }, + { + name: 'fetchStart', + time: [1574120165, 429803070], + }, { name: 'domainLookupStart', time: [1574120165, 429803070], }, - { name: 'domainLookupEnd', time: [1574120165, 429803070] }, + { + name: 'domainLookupEnd', + time: [1574120165, 429803070], + }, { name: 'connectStart', time: [1574120165, 429803070], }, - { name: 'connectEnd', time: [1574120165, 429803070] }, + { + name: 'connectEnd', + time: [1574120165, 429803070], + }, { name: 'requestStart', time: [1574120165, 435513070], }, - { name: 'responseStart', time: [1574120165, 436923070] }, + { + name: 'responseStart', + time: [1574120165, 436923070], + }, { name: 'responseEnd', time: [1574120165, 438688070], @@ -102,6 +114,9 @@ export const mockedReadableSpan: ReadableSpan = { }) ), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; export const mockedResources: Resource[] = [ @@ -142,6 +157,9 @@ export const basicTrace: ReadableSpan[] = [ duration: [0, 8885000], resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }, { name: 'span2', @@ -164,6 +182,9 @@ export const basicTrace: ReadableSpan[] = [ duration: [0, 8775000], resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }, { name: 'span3', @@ -186,6 +207,9 @@ export const basicTrace: ReadableSpan[] = [ duration: [0, 8775000], resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[0], + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }, ]; diff --git a/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts b/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts index 67ea6593bc..5e2b71c573 100644 --- a/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts +++ b/experimental/packages/exporter-trace-otlp-proto/test/traceHelper.ts @@ -59,22 +59,34 @@ export const mockedReadableSpan: ReadableSpan = { }, ], events: [ - { name: 'fetchStart', time: [1574120165, 429803070] }, + { + name: 'fetchStart', + time: [1574120165, 429803070], + }, { name: 'domainLookupStart', time: [1574120165, 429803070], }, - { name: 'domainLookupEnd', time: [1574120165, 429803070] }, + { + name: 'domainLookupEnd', + time: [1574120165, 429803070], + }, { name: 'connectStart', time: [1574120165, 429803070], }, - { name: 'connectEnd', time: [1574120165, 429803070] }, + { + name: 'connectEnd', + time: [1574120165, 429803070], + }, { name: 'requestStart', time: [1574120165, 435513070], }, - { name: 'responseStart', time: [1574120165, 436923070] }, + { + name: 'responseStart', + time: [1574120165, 436923070], + }, { name: 'responseEnd', time: [1574120165, 438688070], @@ -87,6 +99,9 @@ export const mockedReadableSpan: ReadableSpan = { cost: 112.12, }), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; export function ensureProtoEventsAreCorrect(events: IEvent[]) { diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts b/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts index 75aa38c921..d02269c440 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts +++ b/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts @@ -301,7 +301,7 @@ export class FetchInstrumentation extends InstrumentationBase< ): Promise { const self = this; const url = web.parseUrl( - args[0] instanceof Request ? args[0].url : args[0] + args[0] instanceof Request ? args[0].url : String(args[0]) ).href; const options = args[0] instanceof Request ? args[0] : args[1] || {}; diff --git a/experimental/packages/otlp-grpc-exporter-base/test/traceHelper.ts b/experimental/packages/otlp-grpc-exporter-base/test/traceHelper.ts index 8aef302d05..13103b405b 100644 --- a/experimental/packages/otlp-grpc-exporter-base/test/traceHelper.ts +++ b/experimental/packages/otlp-grpc-exporter-base/test/traceHelper.ts @@ -61,22 +61,34 @@ export const mockedReadableSpan: ReadableSpan = { }, ], events: [ - { name: 'fetchStart', time: [1574120165, 429803070] }, + { + name: 'fetchStart', + time: [1574120165, 429803070], + }, { name: 'domainLookupStart', time: [1574120165, 429803070], }, - { name: 'domainLookupEnd', time: [1574120165, 429803070] }, + { + name: 'domainLookupEnd', + time: [1574120165, 429803070], + }, { name: 'connectStart', time: [1574120165, 429803070], }, - { name: 'connectEnd', time: [1574120165, 429803070] }, + { + name: 'connectEnd', + time: [1574120165, 429803070], + }, { name: 'requestStart', time: [1574120165, 435513070], }, - { name: 'responseStart', time: [1574120165, 436923070] }, + { + name: 'responseStart', + time: [1574120165, 436923070], + }, { name: 'responseEnd', time: [1574120165, 438688070], @@ -91,6 +103,9 @@ export const mockedReadableSpan: ReadableSpan = { }) ), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; export function ensureExportedEventsAreCorrect(events: IEvent[]) { diff --git a/experimental/packages/otlp-transformer/src/trace/internal.ts b/experimental/packages/otlp-transformer/src/trace/internal.ts index e4d787349e..6811a8182f 100644 --- a/experimental/packages/otlp-transformer/src/trace/internal.ts +++ b/experimental/packages/otlp-transformer/src/trace/internal.ts @@ -39,16 +39,16 @@ export function sdkSpanToOtlpSpan(span: ReadableSpan, useHex?: boolean): ISpan { startTimeUnixNano: hrTimeToNanoseconds(span.startTime), endTimeUnixNano: hrTimeToNanoseconds(span.endTime), attributes: toAttributes(span.attributes), - droppedAttributesCount: 0, + droppedAttributesCount: span.droppedAttributesCount, events: span.events.map(toOtlpSpanEvent), - droppedEventsCount: 0, + droppedEventsCount: span.droppedEventsCount, status: { // API and proto enums share the same values code: status.code as unknown as EStatusCode, message: status.message, }, links: span.links.map(link => toOtlpLink(link, useHex)), - droppedLinksCount: 0, + droppedLinksCount: span.droppedLinksCount, }; } @@ -62,7 +62,7 @@ export function toOtlpLink(link: Link, useHex?: boolean): ILink { ? link.context.traceId : core.hexToBase64(link.context.traceId), traceState: link.context.traceState?.serialize(), - droppedAttributesCount: 0, + droppedAttributesCount: link.droppedAttributesCount || 0, }; } @@ -73,6 +73,6 @@ export function toOtlpSpanEvent(timedEvent: TimedEvent): IEvent { : [], name: timedEvent.name, timeUnixNano: hrTimeToNanoseconds(timedEvent.time), - droppedAttributesCount: 0, + droppedAttributesCount: timedEvent.droppedAttributesCount || 0, }; } diff --git a/experimental/packages/otlp-transformer/test/trace.test.ts b/experimental/packages/otlp-transformer/test/trace.test.ts index 7308139004..da3e1d0c7d 100644 --- a/experimental/packages/otlp-transformer/test/trace.test.ts +++ b/experimental/packages/otlp-transformer/test/trace.test.ts @@ -178,6 +178,9 @@ describe('Trace', () => { status: { code: SpanStatusCode.OK, }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; }); diff --git a/packages/opentelemetry-context-zone-peer-dep/src/util.ts b/packages/opentelemetry-context-zone-peer-dep/src/util.ts index 2d5e87996f..7c4ac5f68d 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/util.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/util.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import { TargetWithEvents } from './types'; - /** - * check if an object has addEventListener and removeEventListener functions then it will return true - * @param obj + * check if an object has addEventListener and removeEventListener functions then it will return true. + * Generally only called with a `TargetWithEvents` but may be called with an unknown / any. + * @param obj - The object to check. */ -export function isListenerObject(obj: TargetWithEvents = {}): boolean { +export function isListenerObject(obj: any = {}): boolean { return ( typeof obj.addEventListener === 'function' && typeof obj.removeEventListener === 'function' diff --git a/packages/opentelemetry-core/src/utils/environment.ts b/packages/opentelemetry-core/src/utils/environment.ts index 5d529d08a9..57983cdeef 100644 --- a/packages/opentelemetry-core/src/utils/environment.ts +++ b/packages/opentelemetry-core/src/utils/environment.ts @@ -47,6 +47,8 @@ const ENVIRONMENT_NUMBERS_KEYS = [ 'OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT', 'OTEL_SPAN_EVENT_COUNT_LIMIT', 'OTEL_SPAN_LINK_COUNT_LIMIT', + 'OTEL_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT', + 'OTEL_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT', 'OTEL_EXPORTER_OTLP_TIMEOUT', 'OTEL_EXPORTER_OTLP_TRACES_TIMEOUT', 'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT', @@ -131,6 +133,9 @@ export const DEFAULT_ATTRIBUTE_VALUE_LENGTH_LIMIT = Infinity; export const DEFAULT_ATTRIBUTE_COUNT_LIMIT = 128; +export const DEFAULT_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT = 128; +export const DEFAULT_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT = 128; + /** * Default environment variables */ @@ -172,6 +177,10 @@ export const DEFAULT_ENVIRONMENT: Required = { OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: DEFAULT_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT: 128, OTEL_SPAN_LINK_COUNT_LIMIT: 128, + OTEL_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT: + DEFAULT_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT, + OTEL_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT: + DEFAULT_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT, OTEL_TRACES_EXPORTER: '', OTEL_TRACES_SAMPLER: TracesSamplerValues.ParentBasedAlwaysOn, OTEL_TRACES_SAMPLER_ARG: '', diff --git a/packages/opentelemetry-exporter-jaeger/README.md b/packages/opentelemetry-exporter-jaeger/README.md index 802debb99d..4adceb9b74 100644 --- a/packages/opentelemetry-exporter-jaeger/README.md +++ b/packages/opentelemetry-exporter-jaeger/README.md @@ -1,8 +1,14 @@ -# OpenTelemetry Jaeger Trace Exporter for Node.js +# (Deprecated) OpenTelemetry Jaeger Trace Exporter for Node.js [![NPM Published Version][npm-img]][npm-url] [![Apache License][license-image]][license-image] +**NOTE: Support for `@opentelemetry/exporter-jaeger` will end March 2024, please use any of the following packages instead:** + +- `@opentelemetry/exporter-trace-otlp-proto` +- `@opentelemetry/exporter-trace-otlp-grpc` +- `@opentelemetry/exporter-trace-otlp-http` + OpenTelemetry Jaeger Trace Exporter allows the user to send collected traces to Jaeger. [Jaeger](https://jaeger.readthedocs.io/en/latest/), inspired by [Dapper](https://research.google.com/pubs/pub36356.html) and [OpenZipkin](http://zipkin.io/), is a distributed tracing system released as open source by [Uber Technologies](http://uber.github.io/). It is used for monitoring and troubleshooting microservices-based distributed systems, including: diff --git a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts index 2f7acabe76..28d3ccb337 100644 --- a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts +++ b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts @@ -29,6 +29,16 @@ import * as jaegerTypes from './types'; /** * Format and sends span information to Jaeger Exporter. + * + * @deprecated Jaeger supports the OpenTelemetry protocol natively + * (see https://www.jaegertracing.io/docs/1.41/apis/#opentelemetry-protocol-stable). + * This exporter will not be required by the OpenTelemetry specification starting July 2023, and + * will not receive any security fixes past March 2024. + * + * Please migrate to any of the following packages: + * - `@opentelemetry/exporter-trace-otlp-proto` + * - `@opentelemetry/exporter-trace-otlp-grpc` + * - `@opentelemetry/exporter-trace-otlp-http` */ export class JaegerExporter implements SpanExporter { private readonly _onShutdownFlushTimeout: number; diff --git a/packages/opentelemetry-exporter-jaeger/src/transform.ts b/packages/opentelemetry-exporter-jaeger/src/transform.ts index 61321e78aa..b91e0c2929 100644 --- a/packages/opentelemetry-exporter-jaeger/src/transform.ts +++ b/packages/opentelemetry-exporter-jaeger/src/transform.ts @@ -86,6 +86,30 @@ export function spanToThrift(span: ReadableSpan): ThriftSpan { }); } + /* Add droppedAttributesCount as a tag */ + if (span.droppedAttributesCount) { + tags.push({ + key: 'otel.dropped_attributes_count', + value: toTagValue(span.droppedAttributesCount), + }); + } + + /* Add droppedEventsCount as a tag */ + if (span.droppedEventsCount) { + tags.push({ + key: 'otel.dropped_events_count', + value: toTagValue(span.droppedEventsCount), + }); + } + + /* Add droppedLinksCount as a tag */ + if (span.droppedLinksCount) { + tags.push({ + key: 'otel.dropped_links_count', + value: toTagValue(span.droppedLinksCount), + }); + } + const spanTags: ThriftTag[] = ThriftUtils.getThriftTags(tags); const logs = span.events.map((event): Log => { @@ -96,6 +120,12 @@ export function spanToThrift(span: ReadableSpan): ThriftSpan { fields.push({ key: attr, value: toTagValue(attrs[attr]) }) ); } + if (event.droppedAttributesCount) { + fields.push({ + key: 'otel.event.dropped_attributes_count', + value: event.droppedAttributesCount, + }); + } return { timestamp: hrTimeToMilliseconds(event.time), fields }; }); const spanLogs: ThriftLog[] = ThriftUtils.getThriftLogs(logs); diff --git a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts index 7a6130322b..bcfdbf051f 100644 --- a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts @@ -53,6 +53,9 @@ describe('JaegerExporter', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; describe('constructor', () => { afterEach(() => { diff --git a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts index 5b9de96aa5..35a11c7ffd 100644 --- a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts @@ -82,6 +82,9 @@ describe('transform', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const thriftSpan = spanToThrift(readableSpan); @@ -179,6 +182,9 @@ describe('transform', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const thriftSpan = spanToThrift(readableSpan); @@ -246,6 +252,9 @@ describe('transform', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const thriftSpan = spanToThrift(readableSpan); @@ -291,6 +300,9 @@ describe('transform', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const thriftSpan = spanToThrift(readableSpan); @@ -353,6 +365,9 @@ describe('transform', () => { name: 'default', version: '0.0.1', }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; let thriftSpan = spanToThrift(readableSpan); assert.strictEqual( diff --git a/packages/opentelemetry-exporter-zipkin/src/transform.ts b/packages/opentelemetry-exporter-zipkin/src/transform.ts index c3c1887616..94983057f6 100644 --- a/packages/opentelemetry-exporter-zipkin/src/transform.ts +++ b/packages/opentelemetry-exporter-zipkin/src/transform.ts @@ -18,7 +18,6 @@ import * as api from '@opentelemetry/api'; import { ReadableSpan, TimedEvent } from '@opentelemetry/sdk-trace-base'; import { hrTimeToMicroseconds } from '@opentelemetry/core'; import * as zipkinTypes from './types'; -import { IResource } from '@opentelemetry/resources'; const ZIPKIN_SPAN_KIND_MAPPING = { [api.SpanKind.CLIENT]: zipkinTypes.SpanKind.CLIENT, @@ -51,13 +50,7 @@ export function toZipkinSpan( timestamp: hrTimeToMicroseconds(span.startTime), duration: hrTimeToMicroseconds(span.duration), localEndpoint: { serviceName }, - tags: _toZipkinTags( - span.attributes, - span.status, - statusCodeTagName, - statusErrorTagName, - span.resource - ), + tags: _toZipkinTags(span, statusCodeTagName, statusErrorTagName), annotations: span.events.length ? _toZipkinAnnotations(span.events) : undefined, @@ -66,13 +59,18 @@ export function toZipkinSpan( return zipkinSpan; } -/** Converts OpenTelemetry SpanAttributes and SpanStatus to Zipkin Tags format. */ +/** Converts OpenTelemetry Span properties to Zipkin Tags format. */ export function _toZipkinTags( - attributes: api.SpanAttributes, - status: api.SpanStatus, + { + attributes, + resource, + status, + droppedAttributesCount, + droppedEventsCount, + droppedLinksCount, + }: ReadableSpan, statusCodeTagName: string, - statusErrorTagName: string, - resource: IResource + statusErrorTagName: string ): zipkinTypes.Tags { const tags: { [key: string]: string } = {}; for (const key of Object.keys(attributes)) { @@ -84,6 +82,20 @@ export function _toZipkinTags( if (status.code === api.SpanStatusCode.ERROR && status.message) { tags[statusErrorTagName] = status.message; } + /* Add droppedAttributesCount as a tag */ + if (droppedAttributesCount) { + tags['otel.dropped_attributes_count'] = String(droppedAttributesCount); + } + + /* Add droppedEventsCount as a tag */ + if (droppedEventsCount) { + tags['otel.dropped_events_count'] = String(droppedEventsCount); + } + + /* Add droppedLinksCount as a tag */ + if (droppedLinksCount) { + tags['otel.dropped_links_count'] = String(droppedLinksCount); + } Object.keys(resource.attributes).forEach( name => (tags[name] = String(resource.attributes[name])) diff --git a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts index 3c7b5a5ddb..65a06922af 100644 --- a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts @@ -36,6 +36,9 @@ const tracer = new BasicTracerProvider({ resource: Resource.default().merge( new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + cost: '112.12', + service: 'ui', + version: '1', }) ), }).getTracer('default'); @@ -50,13 +53,6 @@ const spanContext: api.SpanContext = { traceFlags: api.TraceFlags.SAMPLED, }; -const DUMMY_RESOURCE = new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', -}); - describe('transform', () => { describe('toZipkinSpan', () => { it('should convert an OpenTelemetry span to a Zipkin span', () => { @@ -102,6 +98,9 @@ describe('transform', () => { key1: 'value1', key2: 'value2', [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + cost: '112.12', + service: 'ui', + version: '1', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -140,6 +139,9 @@ describe('transform', () => { parentId: undefined, tags: { [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + cost: '112.12', + service: 'ui', + version: '1', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -188,6 +190,9 @@ describe('transform', () => { parentId: undefined, tags: { [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + cost: '112.12', + service: 'ui', + version: '1', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -214,20 +219,21 @@ describe('transform', () => { key2: 'value2', }); const tags: zipkinTypes.Tags = _toZipkinTags( - span.attributes, - span.status, + span, defaultStatusCodeTagName, - defaultStatusErrorTagName, - DUMMY_RESOURCE + defaultStatusErrorTagName ); assert.deepStrictEqual(tags, { key1: 'value1', key2: 'value2', + [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + 'telemetry.sdk.language': language, + 'telemetry.sdk.name': 'opentelemetry', + 'telemetry.sdk.version': VERSION, cost: '112.12', service: 'ui', version: '1', - [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); }); it('should map OpenTelemetry SpanStatus.code to a Zipkin tag', () => { @@ -248,15 +254,9 @@ describe('transform', () => { key2: 'value2', }); const tags: zipkinTypes.Tags = _toZipkinTags( - span.attributes, - span.status, + span, defaultStatusCodeTagName, - defaultStatusErrorTagName, - Resource.empty().merge( - new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', - }) - ) + defaultStatusErrorTagName ); assert.deepStrictEqual(tags, { @@ -264,6 +264,12 @@ describe('transform', () => { key2: 'value2', [defaultStatusCodeTagName]: 'ERROR', [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + 'telemetry.sdk.language': language, + 'telemetry.sdk.name': 'opentelemetry', + 'telemetry.sdk.version': VERSION, + cost: '112.12', + service: 'ui', + version: '1', }); }); it('should map OpenTelemetry SpanStatus.message to a Zipkin tag', () => { @@ -285,15 +291,9 @@ describe('transform', () => { key2: 'value2', }); const tags: zipkinTypes.Tags = _toZipkinTags( - span.attributes, - span.status, + span, defaultStatusCodeTagName, - defaultStatusErrorTagName, - Resource.empty().merge( - new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', - }) - ) + defaultStatusErrorTagName ); assert.deepStrictEqual(tags, { @@ -302,6 +302,12 @@ describe('transform', () => { [defaultStatusCodeTagName]: 'ERROR', [defaultStatusErrorTagName]: status.message, [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', + 'telemetry.sdk.language': language, + 'telemetry.sdk.name': 'opentelemetry', + 'telemetry.sdk.version': VERSION, + cost: '112.12', + service: 'ui', + version: '1', }); }); }); diff --git a/packages/opentelemetry-exporter-zipkin/test/helper.ts b/packages/opentelemetry-exporter-zipkin/test/helper.ts index 3cfd694e2b..bd4d300a1e 100644 --- a/packages/opentelemetry-exporter-zipkin/test/helper.ts +++ b/packages/opentelemetry-exporter-zipkin/test/helper.ts @@ -45,6 +45,9 @@ export const mockedReadableSpan: ReadableSpan = { cost: 112.12, }), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; export function ensureHeadersContain( diff --git a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts index d1aa4e8888..eeab75348e 100644 --- a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts @@ -56,6 +56,9 @@ function getReadableSpan() { events: [], resource: Resource.empty(), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; return readableSpan; } @@ -164,6 +167,9 @@ describe('Zipkin Exporter - node', () => { ], resource: Resource.empty(), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const span2: ReadableSpan = { name: 'my-span', @@ -187,6 +193,9 @@ describe('Zipkin Exporter - node', () => { events: [], resource: Resource.empty(), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const exporter = new ZipkinExporter({ @@ -379,6 +388,9 @@ describe('Zipkin Exporter - node', () => { [SemanticResourceAttributes.SERVICE_NAME]: resource_service_name, }), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const span2: ReadableSpan = { name: 'my-span', @@ -402,6 +414,9 @@ describe('Zipkin Exporter - node', () => { [SemanticResourceAttributes.SERVICE_NAME]: resource_service_name_prime, }), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const exporter = new ZipkinExporter({}); @@ -467,6 +482,9 @@ describe('Zipkin Exporter - node', () => { ], resource: Resource.empty(), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const span2: ReadableSpan = { name: 'my-span', @@ -490,6 +508,9 @@ describe('Zipkin Exporter - node', () => { events: [], resource: Resource.empty(), instrumentationLibrary: { name: 'default', version: '0.0.1' }, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, }; const exporter = new ZipkinExporter({}); diff --git a/packages/opentelemetry-sdk-trace-base/src/Span.ts b/packages/opentelemetry-sdk-trace-base/src/Span.ts index fb2b717d48..0f742855d1 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Span.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Span.ts @@ -66,6 +66,11 @@ export class Span implements APISpan, ReadableSpan { readonly startTime: HrTime; readonly resource: IResource; readonly instrumentationLibrary: InstrumentationLibrary; + + private _droppedAttributesCount = 0; + private _droppedEventsCount: number = 0; + private _droppedLinksCount: number = 0; + name: string; status: SpanStatus = { code: SpanStatusCode.UNSET, @@ -141,6 +146,7 @@ export class Span implements APISpan, ReadableSpan { this._spanLimits.attributeCountLimit! && !Object.prototype.hasOwnProperty.call(this.attributes, key) ) { + this._droppedAttributesCount++; return this; } this.attributes[key] = this._truncateToSize(value); @@ -169,11 +175,13 @@ export class Span implements APISpan, ReadableSpan { if (this._isSpanEnded()) return this; if (this._spanLimits.eventCountLimit === 0) { diag.warn('No events allowed.'); + this._droppedEventsCount++; return this; } if (this.events.length >= this._spanLimits.eventCountLimit!) { diag.warn('Dropping extra events.'); this.events.shift(); + this._droppedEventsCount++; } if (isTimeInput(attributesOrStartTime)) { @@ -184,10 +192,12 @@ export class Span implements APISpan, ReadableSpan { } const attributes = sanitizeAttributes(attributesOrStartTime); + this.events.push({ name, attributes, time: this._getTime(timeStamp), + droppedAttributesCount: 0, }); return this; } @@ -298,6 +308,18 @@ export class Span implements APISpan, ReadableSpan { return this._ended; } + get droppedAttributesCount(): number { + return this._droppedAttributesCount; + } + + get droppedEventsCount(): number { + return this._droppedEventsCount; + } + + get droppedLinksCount(): number { + return this._droppedLinksCount; + } + private _isSpanEnded(): boolean { if (this._ended) { diag.warn( diff --git a/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts b/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts index 93cb9b47f3..1f835ba710 100644 --- a/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts +++ b/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts @@ -26,4 +26,6 @@ export interface TimedEvent { name: string; /** The attributes of the event. */ attributes?: SpanAttributes; + /** Count of attributes of the event that were dropped due to collection limits */ + droppedAttributesCount?: number; } diff --git a/packages/opentelemetry-sdk-trace-base/src/config.ts b/packages/opentelemetry-sdk-trace-base/src/config.ts index 18753ea70e..3448b793da 100644 --- a/packages/opentelemetry-sdk-trace-base/src/config.ts +++ b/packages/opentelemetry-sdk-trace-base/src/config.ts @@ -49,6 +49,10 @@ export function loadDefaultConfig() { attributeCountLimit: getEnv().OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, linkCountLimit: getEnv().OTEL_SPAN_LINK_COUNT_LIMIT, eventCountLimit: getEnv().OTEL_SPAN_EVENT_COUNT_LIMIT, + attributePerEventCountLimit: + getEnv().OTEL_SPAN_ATTRIBUTE_PER_EVENT_COUNT_LIMIT, + attributePerLinkCountLimit: + getEnv().OTEL_SPAN_ATTRIBUTE_PER_LINK_COUNT_LIMIT, }, }; } diff --git a/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts b/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts index aa19891099..20ffea4c56 100644 --- a/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts +++ b/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts @@ -41,4 +41,7 @@ export interface ReadableSpan { readonly ended: boolean; readonly resource: IResource; readonly instrumentationLibrary: InstrumentationLibrary; + readonly droppedAttributesCount: number; + readonly droppedEventsCount: number; + readonly droppedLinksCount: number; } diff --git a/packages/opentelemetry-sdk-trace-base/src/types.ts b/packages/opentelemetry-sdk-trace-base/src/types.ts index 6854f0315a..99eeedbe81 100644 --- a/packages/opentelemetry-sdk-trace-base/src/types.ts +++ b/packages/opentelemetry-sdk-trace-base/src/types.ts @@ -81,6 +81,10 @@ export interface SpanLimits { linkCountLimit?: number; /** eventCountLimit is number of message events per span */ eventCountLimit?: number; + /** attributePerEventCountLimit is the maximum number of attributes allowed per span event */ + attributePerEventCountLimit?: number; + /** attributePerLinkCountLimit is the maximum number of attributes allowed per span link */ + attributePerLinkCountLimit?: number; } /** Interface configuration for a buffer. */ diff --git a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts index d7a900cf9f..7a0483ffa9 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts @@ -179,6 +179,8 @@ describe('BasicTracerProvider', () => { attributeCountLimit: 128, eventCountLimit: 128, linkCountLimit: 128, + attributePerEventCountLimit: 128, + attributePerLinkCountLimit: 128, }); }); }); diff --git a/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts index dac8728138..11a94ffc7c 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts @@ -312,6 +312,10 @@ describe('Span', () => { assert.strictEqual(span.attributes['foo99'], 'bar99'); assert.strictEqual(span.attributes['foo149'], undefined); }); + + it('should store the count of dropped attributes in droppedAttributesCount', () => { + assert.strictEqual(span.droppedAttributesCount, 50); + }); }); describe('when "attributeValueLengthLimit" option defined', () => { @@ -791,6 +795,22 @@ describe('Span', () => { assert.strictEqual(span.events[span.events.length - 1].name, 'sent149'); }); + it('should store the count of dropped events in droppedEventsCount', () => { + const span = new Span( + tracer, + ROOT_CONTEXT, + name, + spanContext, + SpanKind.CLIENT + ); + for (let i = 0; i < 150; i++) { + span.addEvent('sent' + i); + } + span.end(); + + assert.strictEqual(span.droppedEventsCount, 50); + }); + it('should add no event', () => { const tracer = new BasicTracerProvider({ spanLimits: { diff --git a/packages/opentelemetry-sdk-trace-web/src/utils.ts b/packages/opentelemetry-sdk-trace-web/src/utils.ts index 30031e0623..e8abd29274 100644 --- a/packages/opentelemetry-sdk-trace-web/src/utils.ts +++ b/packages/opentelemetry-sdk-trace-web/src/utils.ts @@ -44,7 +44,10 @@ function getUrlNormalizingAnchor(): HTMLAnchorElement { * @param key */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export function hasKey(obj: O, key: keyof any): key is keyof O { +export function hasKey( + obj: O, + key: keyof any +): key is keyof O { return key in obj; } diff --git a/packages/sdk-metrics/src/view/InstrumentSelector.ts b/packages/sdk-metrics/src/view/InstrumentSelector.ts index e7bec3a44a..9b8006267f 100644 --- a/packages/sdk-metrics/src/view/InstrumentSelector.ts +++ b/packages/sdk-metrics/src/view/InstrumentSelector.ts @@ -15,20 +15,23 @@ */ import { InstrumentType } from '../InstrumentDescriptor'; -import { PatternPredicate, Predicate } from './Predicate'; +import { ExactPredicate, PatternPredicate, Predicate } from './Predicate'; export interface InstrumentSelectorCriteria { name?: string; type?: InstrumentType; + unit?: string; } export class InstrumentSelector { private _nameFilter: Predicate; private _type?: InstrumentType; + private _unitFilter: Predicate; constructor(criteria?: InstrumentSelectorCriteria) { this._nameFilter = new PatternPredicate(criteria?.name ?? '*'); this._type = criteria?.type; + this._unitFilter = new ExactPredicate(criteria?.unit); } getType() { @@ -38,4 +41,8 @@ export class InstrumentSelector { getNameFilter() { return this._nameFilter; } + + getUnitFilter() { + return this._unitFilter; + } } diff --git a/packages/sdk-metrics/src/view/RegistrationConflicts.ts b/packages/sdk-metrics/src/view/RegistrationConflicts.ts index e74add7334..dbb8073c8b 100644 --- a/packages/sdk-metrics/src/view/RegistrationConflicts.ts +++ b/packages/sdk-metrics/src/view/RegistrationConflicts.ts @@ -59,6 +59,7 @@ export function getTypeConflictResolutionRecipe( const selector: InstrumentSelectorCriteria = { name: otherDescriptor.name, type: otherDescriptor.type, + unit: otherDescriptor.unit, }; const selectorString = JSON.stringify(selector); @@ -73,6 +74,7 @@ export function getDescriptionResolutionRecipe( const selector: InstrumentSelectorCriteria = { name: otherDescriptor.name, type: otherDescriptor.type, + unit: otherDescriptor.unit, }; const selectorString = JSON.stringify(selector); diff --git a/packages/sdk-metrics/src/view/View.ts b/packages/sdk-metrics/src/view/View.ts index 398f936536..1e8d4fb0e0 100644 --- a/packages/sdk-metrics/src/view/View.ts +++ b/packages/sdk-metrics/src/view/View.ts @@ -83,6 +83,14 @@ export type ViewOptions = { * instrumentName: 'my.instruments.requests' */ instrumentName?: string; + /** + * Instrument selection criteria: + * The unit of the Instrument(s). + * + * @example select all instruments with unit 'ms' + * instrumentUnit: 'ms' + */ + instrumentUnit?: string; /** * Instrument selection criteria: * The name of the Meter. No wildcard support, name must match the meter exactly. @@ -113,6 +121,7 @@ function isSelectorNotProvided(options: ViewOptions): boolean { return ( options.instrumentName == null && options.instrumentType == null && + options.instrumentUnit == null && options.meterName == null && options.meterVersion == null && options.meterSchemaUrl == null @@ -161,6 +170,9 @@ export class View { * @param viewOptions.instrumentType * Instrument selection criteria: * The original type of the Instrument(s). + * @param viewOptions.instrumentUnit + * Instrument selection criteria: + * The unit of the Instrument(s). * @param viewOptions.meterName * Instrument selection criteria: * The name of the Meter. No wildcard support, name must match the meter exactly. @@ -213,6 +225,7 @@ export class View { this.instrumentSelector = new InstrumentSelector({ name: viewOptions.instrumentName, type: viewOptions.instrumentType, + unit: viewOptions.instrumentUnit, }); this.meterSelector = new MeterSelector({ name: viewOptions.meterName, diff --git a/packages/sdk-metrics/src/view/ViewRegistry.ts b/packages/sdk-metrics/src/view/ViewRegistry.ts index 265f699bf9..5f4f367e92 100644 --- a/packages/sdk-metrics/src/view/ViewRegistry.ts +++ b/packages/sdk-metrics/src/view/ViewRegistry.ts @@ -48,7 +48,8 @@ export class ViewRegistry { return ( (selector.getType() === undefined || instrument.type === selector.getType()) && - selector.getNameFilter().match(instrument.name) + selector.getNameFilter().match(instrument.name) && + selector.getUnitFilter().match(instrument.unit) ); } diff --git a/packages/sdk-metrics/test/MeterProvider.test.ts b/packages/sdk-metrics/test/MeterProvider.test.ts index 48055695ed..a9f8361b81 100644 --- a/packages/sdk-metrics/test/MeterProvider.test.ts +++ b/packages/sdk-metrics/test/MeterProvider.test.ts @@ -15,7 +15,13 @@ */ import * as assert from 'assert'; -import { MeterProvider, InstrumentType, DataPointType } from '../src'; +import { + MeterProvider, + InstrumentType, + DataPointType, + ExplicitBucketHistogramAggregation, + HistogramMetricData, +} from '../src'; import { assertScopeMetrics, assertMetricData, @@ -463,6 +469,70 @@ describe('MeterProvider', () => { } ); }); + + it('with instrument unit should apply view to only the selected instrument unit', async () => { + // Add views with different boundaries for each unit. + const msBoundaries = [0, 1, 2, 3, 4, 5]; + const sBoundaries = [10, 50, 250, 1000]; + + const meterProvider = new MeterProvider({ + resource: defaultResource, + views: [ + new View({ + instrumentUnit: 'ms', + aggregation: new ExplicitBucketHistogramAggregation(msBoundaries), + }), + new View({ + instrumentUnit: 's', + aggregation: new ExplicitBucketHistogramAggregation(sBoundaries), + }), + ], + }); + + const reader = new TestMetricReader(); + meterProvider.addMetricReader(reader); + + // Create meter and histograms, with different units. + const meter = meterProvider.getMeter('meter1', 'v1.0.0'); + const histogram1 = meter.createHistogram('test-histogram-ms', { + unit: 'ms', + }); + const histogram2 = meter.createHistogram('test-histogram-s', { + unit: 's', + }); + + // Record values for both. + histogram1.record(1); + histogram2.record(1); + + // Perform collection. + const { resourceMetrics, errors } = await reader.collect(); + + assert.strictEqual(errors.length, 0); + // Results came only from one Meter + assert.strictEqual(resourceMetrics.scopeMetrics.length, 1); + + // InstrumentationScope matches the only created Meter. + assertScopeMetrics(resourceMetrics.scopeMetrics[0], { + name: 'meter1', + version: 'v1.0.0', + }); + + // Two metrics are collected ('test-histogram-ms' and 'test-histogram-s') + assert.strictEqual(resourceMetrics.scopeMetrics[0].metrics.length, 2); + + // Check if the boundaries are applied to the correct instrument. + assert.deepStrictEqual( + (resourceMetrics.scopeMetrics[0].metrics[0] as HistogramMetricData) + .dataPoints[0].value.buckets.boundaries, + msBoundaries + ); + assert.deepStrictEqual( + (resourceMetrics.scopeMetrics[0].metrics[1] as HistogramMetricData) + .dataPoints[0].value.buckets.boundaries, + sBoundaries + ); + }); }); describe('shutdown', () => { diff --git a/packages/sdk-metrics/test/view/ViewRegistry.test.ts b/packages/sdk-metrics/test/view/ViewRegistry.test.ts index aea2ebe3cf..b766c0fda5 100644 --- a/packages/sdk-metrics/test/view/ViewRegistry.test.ts +++ b/packages/sdk-metrics/test/view/ViewRegistry.test.ts @@ -101,6 +101,50 @@ describe('ViewRegistry', () => { assert.strictEqual(views[0].name, 'histogram'); } }); + + it('should match view with instrument unit', () => { + const registry = new ViewRegistry(); + registry.addView( + new View({ + name: 'ms_view', + instrumentName: 'default_metric', + instrumentUnit: 'ms', + }) + ); + registry.addView( + new View({ + name: 's_view', + instrumentName: 'default_metric', + instrumentUnit: 's', + }) + ); + + { + const views = registry.findViews( + { + ...defaultInstrumentDescriptor, + unit: 'ms', + }, + defaultInstrumentationScope + ); + + assert.strictEqual(views.length, 1); + assert.strictEqual(views[0].name, 'ms_view'); + } + + { + const views = registry.findViews( + { + ...defaultInstrumentDescriptor, + unit: 's', + }, + defaultInstrumentationScope + ); + + assert.strictEqual(views.length, 1); + assert.strictEqual(views[0].name, 's_view'); + } + }); }); describe('MeterSelector', () => { diff --git a/scripts/update-ts-configs.js b/scripts/update-ts-configs.js index 0242a54668..283811997b 100644 --- a/scripts/update-ts-configs.js +++ b/scripts/update-ts-configs.js @@ -50,6 +50,7 @@ const ignoredLernaProjects = [ 'selenium-tests', 'examples/otlp-exporter-node', 'examples/opentelemetry-web', + 'examples/http', 'examples/https', ];