diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 0d8d88ca73..cc2f2582ce 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -1,4 +1,4 @@ -# This action requires that any PR targeting the main branch should touch at +# This action requires that any PR targeting the main and next branch should touch at # least one CHANGELOG file. If a CHANGELOG entry is not required, add the "Skip # Changelog" label to disable this action. @@ -9,6 +9,7 @@ on: types: [opened, synchronize, reopened, labeled, unlabeled] branches: - main + - next jobs: changelog: runs-on: ubuntu-latest diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 32b62cfacf..de5f4e9a4c 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -12,8 +12,6 @@ jobs: fail-fast: false matrix: node_version: - - "14" - - "16" - "18" - "20" - "22" @@ -34,10 +32,6 @@ jobs: - run: npm install -g npm@latest if: ${{ matrix.node_version == '20' || matrix.node_version == '22' }} - # npm@10.0.0 drops support for Node.js v14 and v16 - - run: npm install -g npm@"<10.0.0" - if: ${{ matrix.node_version == '14' || matrix.node_version == '16' }} - # npm@11.0.0 drops support for Node.js v18 - run: npm install -g npm@"<11.0.0" if: ${{ matrix.node_version == '18'}} diff --git a/.github/workflows/w3c-integration-test.yml b/.github/workflows/w3c-integration-test.yml index 723314cb05..bb2be0645e 100644 --- a/.github/workflows/w3c-integration-test.yml +++ b/.github/workflows/w3c-integration-test.yml @@ -19,7 +19,7 @@ jobs: cache: 'npm' cache-dependency-path: | package-lock.json - node-version: '16' + node-version: 18 - name: Install and Bootstrap 🔧 run: npm ci diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cb5db0cd6..305495ddd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,20 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se ### :boom: Breaking Change +* feat(sdk-metrics)!: bump minimum version of `@opentelemetry/api` peer dependency to 1.9.0 [#5254](https://github.com/open-telemetry/opentelemetry-js/pull/5254) @chancancode +* chore(shim-opentracing): replace deprecated SpanAttributes [#4430](https://github.com/open-telemetry/opentelemetry-js/pull/4430) @JamieDanielson +* chore(otel-core): replace deprecated SpanAttributes [#4408](https://github.com/open-telemetry/opentelemetry-js/pull/4408) @JamieDanielson +* feat(sdk-metrics)!: remove MeterProvider.addMetricReader() in favor of constructor option [#4419](https://github.com/open-telemetry/opentelemetry-js/pull/4419) @pichlermarc +* chore(otel-resources): replace deprecated SpanAttributes [#4428](https://github.com/open-telemetry/opentelemetry-js/pull/4428) @JamieDanielson +* feat(sdk-metrics)!: remove MeterProvider.addMetricReader() in favor of constructor option [#4419](https://github.com/open-telemetry/opentelemetry-js/pull/4419) @pichlermarc +* feat(sdk-metrics)!: replace attributeKeys with custom processors option [#4532](https://github.com/open-telemetry/opentelemetry-js/pull/4532) @pichlermarc +* refactor(sdk-trace-base)!: replace `SpanAttributes` with `Attributes` [#5009](https://github.com/open-telemetry/opentelemetry-js/pull/5009) @david-luna +* refactor(resources)!: replace `ResourceAttributes` with `Attributes` [#5016](https://github.com/open-telemetry/opentelemetry-js/pull/5016) @david-luna +* feat(sdk-metrics)!: drop `View` and `Aggregation` in favor of `ViewOptions` and `AggregationOption` [#4931](https://github.com/open-telemetry/opentelemetry-js/pull/4931) @pichlermarc +* refactor(sdk-trace-base)!: remove `new Span` constructor in favor of `Tracer.startSpan` API [#5048](https://github.com/open-telemetry/opentelemetry-js/pull/5048) @david-luna +* refactor(sdk-trace-base)!: remove `BasicTracerProvider.addSpanProcessor` API in favor of constructor options. [#5134](https://github.com/open-telemetry/opentelemetry-js/pull/5134) @david-luna +* refactor(sdk-trace-base)!: make `resource` property private in `BasicTracerProvider` and remove `getActiveSpanProcessor` API. [#5192](https://github.com/open-telemetry/opentelemetry-js/pull/5192) @david-luna + ### :rocket: (Enhancement) ### :bug: (Bug Fix) @@ -19,6 +33,11 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se ### :house: (Internal) +* refactor(sdk-metrics): remove `Gauge` and `MetricAdvice` workaround types in favor of the upstream `@opentelemetry/api` types [#5254](https://github.com/open-telemetry/opentelemetry-js/pull/5254) @chancancode +* chore: remove checks for unsupported node versions [#4341](https://github.com/open-telemetry/opentelemetry-js/pull/4341) @dyladan +* refactor(sdk-trace-base): remove `BasicTracerProvider._registeredSpanProcessors` private property. [#5134](https://github.com/open-telemetry/opentelemetry-js/pull/5134) @david-luna +* refactor(sdk-trace-base): rename `BasicTracerProvider.activeSpanProcessor` private property. [#5211](https://github.com/open-telemetry/opentelemetry-js/pull/5211) @david-luna + ## 1.30.0 ### :rocket: (Enhancement) @@ -69,6 +88,8 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se * `@opentelemetry/propagator-aws-xray` is now located in [open-telemetry/opentelemetry-js-contrib](https://github.com/open-telemetry/opentelemetry-js-contrib) * `@opentelemetry/propagator-aws-xray-lambda` is now located in [open-telemetry/opentelemetry-js-contrib](https://github.com/open-telemetry/opentelemetry-js-contrib) +* docs: [Browser] Define the supported browser runtimes [Issue #4168](https://github.com/open-telemetry/opentelemetry-js/issues/4168) PR:[#5059](https://github.com/open-telemetry/opentelemetry-js/pull/5059) @MSNev + ### :house: (Internal) * deps: set `@opentelemetry/api` dependency min version to 1.3.0 in `examples`, `experimental/packages`, `integration-tests` and `selenium-tests` diff --git a/README.md b/README.md index d20e12ccea..0f92c9ad59 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ --- +> [!WARNING] +> This is the working branch for the work in progress 2.0 SDK, see [this tracking issue](https://github.com/open-telemetry/opentelemetry-js/issues/5148) for details. +> If you are a user looking for the current released state, you are probably looking for the [1.x SDK](https://github.com/open-telemetry/opentelemetry-js/tree/v1.x) on the v1.x branch. + ## About this project This is the JavaScript version of [OpenTelemetry](https://opentelemetry.io/), a framework for collecting traces, metrics, and logs from applications. @@ -135,8 +139,17 @@ Note that versions of Node.JS v8 prior to `v8.12.0` will NOT work, because OpenT > Client instrumentation for the browser is **experimental** and mostly **unspecified**. If you are interested in > helping out, get in touch with the [Client Instrumentation SIG][client-instrumentation-sig]. -There is currently no list of officially supported browsers. OpenTelemetry is developed using standard web -technologies and aims to work in currently supported versions of major browsers. +Rather than define versions of specific browsers / runtimes, OpenTelemetry sets the minimum supported version based on the +underlying language features used. + +The current minumum language feature support is set as [ECMAScript 2020](https://262.ecma-international.org/11.0/) that are available +in all modern browsers / runtimes. + +This means that if you are targeting or your end-users are using a browser / runtime that does not support ES2020, you will need +to transpile the code and provide any necessary polyfills for the missing features to ensure compatibility with your target +environments. Any support issues that arise from using a browser or runtime that does not support ES2020 will be closed as "won't fix". + +This minimum support level is subject to change as the project evolves and as the underlying language features evolve. ## Package Version Compatibility diff --git a/examples/basic-tracer-node/package.json b/examples/basic-tracer-node/package.json index 9fb58cbef5..d379943c7e 100644 --- a/examples/basic-tracer-node/package.json +++ b/examples/basic-tracer-node/package.json @@ -16,7 +16,7 @@ "tracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/esm-http-ts/index.ts b/examples/esm-http-ts/index.ts index 38ea568047..d26738a026 100644 --- a/examples/esm-http-ts/index.ts +++ b/examples/esm-http-ts/index.ts @@ -11,14 +11,15 @@ import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import http from 'http'; diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); +const exporter = new ConsoleSpanExporter(); +const processor = new SimpleSpanProcessor(exporter); + const tracerProvider = new NodeTracerProvider({ resource: new Resource({ [SEMRESATTRS_SERVICE_NAME]: 'esm-http-ts-example', }), + spanProcessors: [processor], }); -const exporter = new ConsoleSpanExporter(); -const processor = new SimpleSpanProcessor(exporter); -tracerProvider.addSpanProcessor(processor); tracerProvider.register(); registerInstrumentations({ diff --git a/examples/esm-http-ts/package.json b/examples/esm-http-ts/package.json index e7618704ab..96c8f6b432 100644 --- a/examples/esm-http-ts/package.json +++ b/examples/esm-http-ts/package.json @@ -22,7 +22,7 @@ "typescript" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/grpc-js/package.json b/examples/grpc-js/package.json index 7a3e1132cd..9ee0482535 100644 --- a/examples/grpc-js/package.json +++ b/examples/grpc-js/package.json @@ -20,7 +20,7 @@ "tracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/http/package.json b/examples/http/package.json index 18a9351bf3..1126b87114 100644 --- a/examples/http/package.json +++ b/examples/http/package.json @@ -21,7 +21,7 @@ "tracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/https/package.json b/examples/https/package.json index 5b8c56043e..8951bed78a 100644 --- a/examples/https/package.json +++ b/examples/https/package.json @@ -25,7 +25,7 @@ "tracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/opentelemetry-web/package.json b/examples/opentelemetry-web/package.json index 578dff597e..167afac037 100644 --- a/examples/opentelemetry-web/package.json +++ b/examples/opentelemetry-web/package.json @@ -25,7 +25,7 @@ "web" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/opentracing-shim/package.json b/examples/opentracing-shim/package.json index 96b87bc0eb..913ae34c71 100644 --- a/examples/opentracing-shim/package.json +++ b/examples/opentracing-shim/package.json @@ -22,7 +22,7 @@ "opentracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/examples/otlp-exporter-node/package.json b/examples/otlp-exporter-node/package.json index 351e1a173e..6fb4d21a3e 100644 --- a/examples/otlp-exporter-node/package.json +++ b/examples/otlp-exporter-node/package.json @@ -21,7 +21,7 @@ "tracing" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/experimental/backwards-compatibility/node14/package.json b/experimental/backwards-compatibility/node14/package.json index c228d6ab7d..bf5dbeadb5 100644 --- a/experimental/backwards-compatibility/node14/package.json +++ b/experimental/backwards-compatibility/node14/package.json @@ -20,6 +20,6 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" } } diff --git a/experimental/backwards-compatibility/node16/package.json b/experimental/backwards-compatibility/node16/package.json index a09f979094..bf2cab4f6d 100644 --- a/experimental/backwards-compatibility/node16/package.json +++ b/experimental/backwards-compatibility/node16/package.json @@ -20,6 +20,6 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" } } diff --git a/experimental/examples/opencensus-shim/package.json b/experimental/examples/opencensus-shim/package.json index 005ae818ed..42e36e8141 100644 --- a/experimental/examples/opencensus-shim/package.json +++ b/experimental/examples/opencensus-shim/package.json @@ -20,7 +20,7 @@ "opencensus" ], "engines": { - "node": ">=14" + "node": ">=18" }, "author": "OpenTelemetry Authors", "license": "Apache-2.0", diff --git a/experimental/packages/api-events/package.json b/experimental/packages/api-events/package.json index 9fa3220f6b..9bf4383a65 100644 --- a/experimental/packages/api-events/package.json +++ b/experimental/packages/api-events/package.json @@ -40,7 +40,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/api-logs/package.json b/experimental/packages/api-logs/package.json index 0c6ddee3f9..a1a5a73155 100644 --- a/experimental/packages/api-logs/package.json +++ b/experimental/packages/api-logs/package.json @@ -40,7 +40,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/exporter-logs-otlp-grpc/package.json b/experimental/packages/exporter-logs-otlp-grpc/package.json index 1e7f1e5afc..2bd6699448 100644 --- a/experimental/packages/exporter-logs-otlp-grpc/package.json +++ b/experimental/packages/exporter-logs-otlp-grpc/package.json @@ -33,7 +33,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/exporter-logs-otlp-http/package.json b/experimental/packages/exporter-logs-otlp-http/package.json index 2027180c27..3dac38ea7e 100644 --- a/experimental/packages/exporter-logs-otlp-http/package.json +++ b/experimental/packages/exporter-logs-otlp-http/package.json @@ -26,7 +26,7 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "engines": { - "node": ">=14" + "node": ">=18" }, "scripts": { "prepublishOnly": "npm run compile", diff --git a/experimental/packages/exporter-logs-otlp-proto/package.json b/experimental/packages/exporter-logs-otlp-proto/package.json index 541e868d64..143944cd87 100644 --- a/experimental/packages/exporter-logs-otlp-proto/package.json +++ b/experimental/packages/exporter-logs-otlp-proto/package.json @@ -42,7 +42,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/exporter-trace-otlp-grpc/package.json b/experimental/packages/exporter-trace-otlp-grpc/package.json index ec40620fcf..17215dc3a0 100644 --- a/experimental/packages/exporter-trace-otlp-grpc/package.json +++ b/experimental/packages/exporter-trace-otlp-grpc/package.json @@ -32,7 +32,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/exporter-trace-otlp-http/package.json b/experimental/packages/exporter-trace-otlp-http/package.json index 3fc0891f14..6716a830bc 100644 --- a/experimental/packages/exporter-trace-otlp-http/package.json +++ b/experimental/packages/exporter-trace-otlp-http/package.json @@ -42,7 +42,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/exporter-trace-otlp-proto/package.json b/experimental/packages/exporter-trace-otlp-proto/package.json index a76fec33fc..f809cd9d9f 100644 --- a/experimental/packages/exporter-trace-otlp-proto/package.json +++ b/experimental/packages/exporter-trace-otlp-proto/package.json @@ -41,7 +41,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-browser-detector/package.json b/experimental/packages/opentelemetry-browser-detector/package.json index 4f4d8290fc..addc8c3c81 100644 --- a/experimental/packages/opentelemetry-browser-detector/package.json +++ b/experimental/packages/opentelemetry-browser-detector/package.json @@ -33,7 +33,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json index 885c7ebd2b..3fba7f61a8 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json @@ -32,7 +32,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json index 8185199d3c..28a5a0910d 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json @@ -42,7 +42,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts index 33880a4fda..aacf2e9bcb 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/OTLPMetricExporterBase.ts @@ -21,8 +21,9 @@ import { InstrumentType, PushMetricExporter, ResourceMetrics, - Aggregation, AggregationSelector, + AggregationOption, + AggregationType, } from '@opentelemetry/sdk-metrics'; import { AggregationTemporalityPreference, @@ -116,7 +117,11 @@ function chooseAggregationSelector( if (config?.aggregationPreference) { return config.aggregationPreference; } else { - return (_instrumentType: any) => Aggregation.Default(); + return (_instrumentType: any) => { + return { + type: AggregationType.DEFAULT, + }; + }; } } @@ -138,7 +143,7 @@ export class OTLPMetricExporterBase ); } - selectAggregation(instrumentType: InstrumentType): Aggregation { + selectAggregation(instrumentType: InstrumentType): AggregationOption { return this._aggregationSelector(instrumentType); } diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/OTLPMetricExporter.test.ts index 04d3228dee..12cef0737e 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/OTLPMetricExporter.test.ts @@ -17,13 +17,13 @@ import * as assert from 'assert'; import * as http from 'http'; import * as sinon from 'sinon'; -import { AggregationTemporalityPreference } from '../../src'; +import { AggregationTemporalityPreference } from '../../src'; import { OTLPMetricExporter } from '../../src/platform/node'; import { - Aggregation, + AggregationOption, AggregationTemporality, - ExplicitBucketHistogramAggregation, + AggregationType, InstrumentType, MeterProvider, PeriodicExportingMetricReader, @@ -150,9 +150,12 @@ describe('OTLPMetricExporter', () => { describe('aggregation', () => { it('aggregationSelector calls the selector supplied to the constructor', () => { - const aggregation = new ExplicitBucketHistogramAggregation([ - 0, 100, 100000, - ]); + const aggregation: AggregationOption = { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { + boundaries: [0, 100, 100000], + }, + }; const exporter = new OTLPMetricExporter({ aggregationPreference: _instrumentType => aggregation, }); @@ -164,11 +167,15 @@ describe('OTLPMetricExporter', () => { it('aggregationSelector returns the default aggregation preference when nothing is supplied', () => { const exporter = new OTLPMetricExporter({ - aggregationPreference: _instrumentType => Aggregation.Default(), + aggregationPreference: _instrumentType => ({ + type: AggregationType.DEFAULT, + }), }); - assert.equal( + assert.deepStrictEqual( exporter.selectAggregation(InstrumentType.COUNTER), - Aggregation.Default() + { + type: AggregationType.DEFAULT, + } ); }); }); diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json index 3573f3b72c..928aa63aab 100644 --- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json +++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-exporter-prometheus/package.json b/experimental/packages/opentelemetry-exporter-prometheus/package.json index 78d51dec0d..898aeaa18c 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/package.json +++ b/experimental/packages/opentelemetry-exporter-prometheus/package.json @@ -29,7 +29,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts index bd763de3f0..e9f95051f8 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusExporter.ts @@ -17,8 +17,8 @@ import { diag } from '@opentelemetry/api'; import { globalErrorHandler } from '@opentelemetry/core'; import { - Aggregation, AggregationTemporality, + AggregationType, MetricReader, } from '@opentelemetry/sdk-metrics'; import { createServer, IncomingMessage, Server, ServerResponse } from 'http'; @@ -60,7 +60,11 @@ export class PrometheusExporter extends MetricReader { callback: (error: Error | void) => void = () => {} ) { super({ - aggregationSelector: _instrumentType => Aggregation.Default(), + aggregationSelector: _instrumentType => { + return { + type: AggregationType.DEFAULT, + }; + }, aggregationTemporalitySelector: _instrumentType => AggregationTemporality.CUMULATIVE, metricProducers: config.metricProducers, diff --git a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts index fd6bac8bd0..d671a9d7f6 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts @@ -17,17 +17,12 @@ import * as assert from 'assert'; import { Attributes, UpDownCounter } from '@opentelemetry/api'; import { - Aggregation, AggregationTemporality, DataPoint, DataPointType, - ExplicitBucketHistogramAggregation, Histogram, - LastValueAggregation, MeterProvider, MetricReader, - SumAggregation, - View, } from '@opentelemetry/sdk-metrics'; import * as sinon from 'sinon'; import { PrometheusSerializer } from '../src'; @@ -40,6 +35,7 @@ import { serviceName, } from './util'; import { Resource } from '@opentelemetry/resources'; +import { AggregationType } from '@opentelemetry/sdk-metrics'; const attributes = { foo1: 'bar1', @@ -56,7 +52,9 @@ class TestMetricReader extends MetricReader { super({ aggregationTemporalitySelector: _instrumentType => AggregationTemporality.CUMULATIVE, - aggregationSelector: _instrumentType => Aggregation.Default(), + aggregationSelector: _instrumentType => { + return { type: AggregationType.DEFAULT }; + }, }); } @@ -86,10 +84,10 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new SumAggregation(), + { + aggregation: { type: AggregationType.SUM }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -136,10 +134,15 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]), + { + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { + boundaries: [1, 10, 100], + }, + }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -201,10 +204,10 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new SumAggregation(), + { + aggregation: { type: AggregationType.SUM }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -256,10 +259,10 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new SumAggregation(), + { + aggregation: { type: AggregationType.SUM }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -310,10 +313,12 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new LastValueAggregation(), + { + aggregation: { + type: AggregationType.LAST_VALUE, + }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -364,10 +369,13 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]), + { + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { boundaries: [1, 10, 100] }, + }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -419,10 +427,13 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ - aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]), + { + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { boundaries: [1, 10, 100] }, + }, instrumentName: '*', - }), + }, ], readers: [reader], }); @@ -472,7 +483,10 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ aggregation: new SumAggregation(), instrumentName: '*' }), + { + aggregation: { type: AggregationType.SUM }, + instrumentName: '*', + }, ], readers: [reader], }); @@ -561,7 +575,10 @@ describe('PrometheusSerializer', () => { const reader = new TestMetricReader(); const meterProvider = new MeterProvider({ views: [ - new View({ aggregation: new SumAggregation(), instrumentName: '*' }), + { + aggregation: { type: AggregationType.SUM }, + instrumentName: '*', + }, ], readers: [reader], }); diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/package.json b/experimental/packages/opentelemetry-instrumentation-fetch/package.json index 90fc46e9f6..2943b07c13 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/package.json +++ b/experimental/packages/opentelemetry-instrumentation-fetch/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts index 955c734fad..7f81d7cd42 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts @@ -288,18 +288,17 @@ describe('fetch', () => { } fetchInstrumentation = new FetchInstrumentation(config); - webTracerProviderWithZone = new WebTracerProvider(); + dummySpanExporter = new DummySpanExporter(); + webTracerProviderWithZone = new WebTracerProvider({ + spanProcessors: [new tracing.SimpleSpanProcessor(dummySpanExporter)], + }); registerInstrumentations({ tracerProvider: webTracerProviderWithZone, instrumentations: [fetchInstrumentation], }); webTracerWithZone = webTracerProviderWithZone.getTracer('fetch-test'); - dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); clearResourceTimingsSpy = sinon.stub(performance, 'clearResourceTimings'); - webTracerProviderWithZone.addSpanProcessor( - new tracing.SimpleSpanProcessor(dummySpanExporter) - ); // endSpan is called after the whole response body is read // this process is scheduled at the same time the fetch promise is resolved diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index fa08d92763..c668254eaa 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -32,7 +32,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc-protobuf-ts.test.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc-protobuf-ts.test.ts index 8e238a6acc..df920ae059 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc-protobuf-ts.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc-protobuf-ts.test.ts @@ -154,9 +154,10 @@ function shouldNotCreateSpans( describe('#grpc-protobuf', () => { let client: GrpcTesterClient; let server: grpc.Server; - const provider = new NodeTracerProvider(); let contextManager: ContextManager; - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); before(() => { propagation.setGlobalPropagator(new W3CTraceContextPropagator()); diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts index fc86aaf0ab..05df2be1f2 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts @@ -755,8 +755,9 @@ export const runTests = ( }; describe('enable()', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); beforeEach(() => { memoryExporter.reset(); }); @@ -799,8 +800,9 @@ export const runTests = ( }); describe('disable()', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); beforeEach(() => { memoryExporter.reset(); }); @@ -830,8 +832,9 @@ export const runTests = ( }); describe('Test filtering requests using metadata', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); beforeEach(() => { memoryExporter.reset(); }); @@ -859,7 +862,9 @@ export const runTests = ( }); describe('Test filtering requests using options', () => { - const provider = new NodeTracerProvider(); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); const checkSpans: { [key: string]: boolean } = { unaryMethod: false, UnaryMethod: false, @@ -868,7 +873,6 @@ export const runTests = ( ServerStreamMethod: true, BidiStreamMethod: false, }; - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); @@ -936,8 +940,9 @@ export const runTests = ( }); describe('Test capturing metadata', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); const clientMetadata = new Metadata(); clientMetadata.add('client_metadata_key', 'client_metadata_value'); diff --git a/experimental/packages/opentelemetry-instrumentation-http/package.json b/experimental/packages/opentelemetry-instrumentation-http/package.json index 0f4b8ae1b8..0f10ebc7b2 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/package.json +++ b/experimental/packages/opentelemetry-instrumentation-http/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts index cd38055a4e..9262bfae17 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts @@ -38,7 +38,6 @@ import { import type * as http from 'http'; import type * as https from 'https'; import { Socket } from 'net'; -import * as semver from 'semver'; import * as url from 'url'; import { HttpInstrumentationConfig } from './types'; import { VERSION } from './version'; @@ -526,10 +525,6 @@ export class HttpInstrumentation extends InstrumentationBase { this._diag.debug('outgoingRequest on error()', error); if (responseFinished) { @@ -766,18 +761,6 @@ export class HttpInstrumentation extends InstrumentationBase { context.disable(); }); describe('get', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); instrumentation.setTracerProvider(provider); beforeEach(() => { memoryExporter.reset(); @@ -88,15 +89,7 @@ describe('Packages', () => { }, ].forEach(({ name, httpPackage }) => { it(`should create a span for GET requests and add propagation headers by using ${name} package`, async () => { - if (process.versions.node.startsWith('12') && name === 'got') { - // got complains with nock and node version 12+ - // > RequestError: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type function - // so let's make a real call - nock.cleanAll(); - nock.enableNetConnect(); - } else { - nock.load(path.join(__dirname, '../', '/fixtures/google-http.json')); - } + nock.load(path.join(__dirname, '../', '/fixtures/google-http.json')); const urlparsed = url.parse( `${protocol}://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8` diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts index a9f3b506a6..faced10302 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-enable.test.ts @@ -65,10 +65,11 @@ const hostname = 'localhost'; const serverName = 'my.server.name'; const pathname = '/test'; const memoryExporter = new InMemorySpanExporter(); -const provider = new BasicTracerProvider(); +const provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], +}); instrumentation.setTracerProvider(provider); const tracer = provider.getTracer('test-https'); -provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); function doNock( hostname: string, diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts index a7c5972a6a..85e12123ed 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts @@ -55,8 +55,9 @@ describe('Packages', () => { context.disable(); }); describe('get', () => { - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); instrumentation.setTracerProvider(provider); beforeEach(() => { memoryExporter.reset(); @@ -88,24 +89,10 @@ describe('Packages', () => { }, ].forEach(({ name, httpPackage }) => { it(`should create a span for GET requests and add propagation headers by using ${name} package`, async () => { - if (process.versions.node.startsWith('12') && name === 'got') { - // got complains with nock and node version 12+ - // > RequestError: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type function - // so let's make a real call - nock.cleanAll(); - nock.enableNetConnect(); - } else { - nock.load(path.join(__dirname, '../', '/fixtures/google-https.json')); - } + nock.load(path.join(__dirname, '../', '/fixtures/google-https.json')); const urlparsed = url.parse( - name === 'got' && process.versions.node.startsWith('12') - ? // there is an issue with got 9.6 version and node 12 when redirecting so url above will not work - // https://github.com/nock/nock/pull/1551 - // https://github.com/sindresorhus/got/commit/bf1aa5492ae2bc78cbbec6b7d764906fb156e6c2#diff-707a4781d57c42085155dcb27edb9ccbR258 - // TODO: check if this is still the case when new version - 'https://www.google.com' - : 'https://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8' + 'https://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8' ); const result = await httpPackage.get(urlparsed.href!); if (!resHeaders) { diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/esm.test.mjs b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/esm.test.mjs index da19460c4e..597dadfeda 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/esm.test.mjs +++ b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/esm.test.mjs @@ -45,9 +45,10 @@ import { import { assertSpan } from '../../build/test/utils/assertSpan.js'; import { HttpInstrumentation } from '../../build/src/index.js'; -const provider = new NodeTracerProvider(); const memoryExporter = new InMemorySpanExporter(); -provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); +const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], +}); const instrumentation = new HttpInstrumentation(); instrumentation.setTracerProvider(provider); diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts index 558bbcb8ff..47fb01989c 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/http-enable.test.ts @@ -129,8 +129,9 @@ describe('HttpInstrumentation Integration tests', () => { }); }); - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); instrumentation.setTracerProvider(provider); beforeEach(() => { memoryExporter.reset(); diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts index ec0c35f630..309ad0afe6 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/integrations/https-enable.test.ts @@ -129,8 +129,9 @@ describe('HttpsInstrumentation Integration tests', () => { done(); }); }); - const provider = new NodeTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + const provider = new NodeTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); instrumentation.setTracerProvider(provider); beforeEach(() => { memoryExporter.reset(); diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json index ccb9b402b6..418fe11bfd 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts index 0886650e11..4b9c38afd1 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/unmocked.test.ts @@ -41,13 +41,14 @@ describe('unmocked xhr', () => { let testSpans: TestSpanProcessor; let provider: WebTracerProvider; beforeEach(() => { - provider = new WebTracerProvider(); + testSpans = new TestSpanProcessor(); + provider = new WebTracerProvider({ + spanProcessors: [testSpans], + }); registerInstrumentations({ instrumentations: [new XMLHttpRequestInstrumentation()], tracerProvider: provider, }); - testSpans = new TestSpanProcessor(); - provider.addSpanProcessor(testSpans); }); afterEach(() => { // nop diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts index ede395200a..cd9d18e84b 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts @@ -302,21 +302,23 @@ describe('xhr', () => { xmlHttpRequestInstrumentation = new XMLHttpRequestInstrumentation( config ); - webTracerProviderWithZone = new WebTracerProvider(); + dummySpanExporter = new DummySpanExporter(); + webTracerProviderWithZone = new WebTracerProvider({ + spanProcessors: [ + new tracing.SimpleSpanProcessor(dummySpanExporter), + ], + }); registerInstrumentations({ instrumentations: [xmlHttpRequestInstrumentation], tracerProvider: webTracerProviderWithZone, }); webTracerWithZone = webTracerProviderWithZone.getTracer('xhr-test'); - dummySpanExporter = new DummySpanExporter(); + exportSpy = sinon.stub(dummySpanExporter, 'export'); clearResourceTimingsSpy = sinon.stub( performance as unknown as Performance, 'clearResourceTimings' ); - webTracerProviderWithZone.addSpanProcessor( - new tracing.SimpleSpanProcessor(dummySpanExporter) - ); rootSpan = webTracerWithZone.startSpan('root'); api.context.with( @@ -910,18 +912,19 @@ describe('xhr', () => { ); spyEntries.withArgs('resource').returns(resources); - webTracerWithZoneProvider = new WebTracerProvider(); + dummySpanExporter = new DummySpanExporter(); + webTracerWithZoneProvider = new WebTracerProvider({ + spanProcessors: [ + new tracing.SimpleSpanProcessor(dummySpanExporter), + ], + }); registerInstrumentations({ instrumentations: [new XMLHttpRequestInstrumentation(config)], tracerProvider: webTracerWithZoneProvider, }); - dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); - webTracerWithZoneProvider.addSpanProcessor( - new tracing.SimpleSpanProcessor(dummySpanExporter) - ); webTracerWithZone = webTracerWithZoneProvider.getTracer('xhr-test'); rootSpan = webTracerWithZone.startSpan('root'); @@ -1497,21 +1500,22 @@ describe('xhr', () => { xmlHttpRequestInstrumentation = new XMLHttpRequestInstrumentation( config ); - webTracerProviderWithZone = new WebTracerProvider(); + dummySpanExporter = new DummySpanExporter(); + exportSpy = sinon.stub(dummySpanExporter, 'export'); + webTracerProviderWithZone = new WebTracerProvider({ + spanProcessors: [ + new tracing.SimpleSpanProcessor(dummySpanExporter), + ], + }); registerInstrumentations({ instrumentations: [xmlHttpRequestInstrumentation], tracerProvider: webTracerProviderWithZone, }); webTracerWithZone = webTracerProviderWithZone.getTracer('xhr-test'); - dummySpanExporter = new DummySpanExporter(); - exportSpy = sinon.stub(dummySpanExporter, 'export'); clearResourceTimingsSpy = sinon.stub( performance as unknown as Performance, 'clearResourceTimings' ); - webTracerProviderWithZone.addSpanProcessor( - new tracing.SimpleSpanProcessor(dummySpanExporter) - ); rootSpan = webTracerWithZone.startSpan('root'); api.context.with( @@ -2081,18 +2085,20 @@ describe('xhr', () => { ); spyEntries.withArgs('resource').returns(resources); - webTracerWithZoneProvider = new WebTracerProvider(); + dummySpanExporter = new DummySpanExporter(); + webTracerWithZoneProvider = new WebTracerProvider({ + spanProcessors: [ + new tracing.SimpleSpanProcessor(dummySpanExporter), + ], + }); registerInstrumentations({ instrumentations: [new XMLHttpRequestInstrumentation(config)], tracerProvider: webTracerWithZoneProvider, }); - dummySpanExporter = new DummySpanExporter(); exportSpy = sinon.stub(dummySpanExporter, 'export'); - webTracerWithZoneProvider.addSpanProcessor( - new tracing.SimpleSpanProcessor(dummySpanExporter) - ); + webTracerWithZone = webTracerWithZoneProvider.getTracer('xhr-test'); rootSpan = webTracerWithZone.startSpan('root'); diff --git a/experimental/packages/opentelemetry-instrumentation/package.json b/experimental/packages/opentelemetry-instrumentation/package.json index 0c1dbc6bd2..3824983ab5 100644 --- a/experimental/packages/opentelemetry-instrumentation/package.json +++ b/experimental/packages/opentelemetry-instrumentation/package.json @@ -111,7 +111,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "sideEffects": false } diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/InstrumentationBase.test.ts b/experimental/packages/opentelemetry-instrumentation/test/node/InstrumentationBase.test.ts index 0a36f4e277..fd732c2bd9 100644 --- a/experimental/packages/opentelemetry-instrumentation/test/node/InstrumentationBase.test.ts +++ b/experimental/packages/opentelemetry-instrumentation/test/node/InstrumentationBase.test.ts @@ -17,12 +17,12 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import * as path from 'path'; +import { InstrumentationBase } from '../../src'; import { - InstrumentationBase, - InstrumentationModuleDefinition, InstrumentationNodeModuleDefinition, + InstrumentationModuleDefinition, InstrumentationNodeModuleFile, -} from '../../src'; +} from '../../src/'; const MODULE_NAME = 'test-module'; const MODULE_FILE_NAME = 'test-module-file'; diff --git a/experimental/packages/opentelemetry-sdk-node/package.json b/experimental/packages/opentelemetry-sdk-node/package.json index f75884aad9..e5c34fcc8f 100644 --- a/experimental/packages/opentelemetry-sdk-node/package.json +++ b/experimental/packages/opentelemetry-sdk-node/package.json @@ -31,7 +31,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts index 7e9b7dde0d..52ffb8c51c 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts @@ -55,7 +55,7 @@ import { PrometheusExporter as PrometheusMetricExporter } from '@opentelemetry/e import { MeterProvider, MetricReader, - View, + ViewOptions, ConsoleMetricExporter, PeriodicExportingMetricReader, } from '@opentelemetry/sdk-metrics'; @@ -67,7 +67,7 @@ import { NodeTracerConfig, NodeTracerProvider, } from '@opentelemetry/sdk-trace-node'; -import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { NodeSDKConfiguration } from './types'; import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core'; import { @@ -84,9 +84,9 @@ export type MeterProviderConfig = { */ reader?: MetricReader; /** - * List of {@link View}s that should be passed to the MeterProvider + * List of {@link ViewOptions}s that should be passed to the MeterProvider */ - views?: View[]; + views?: ViewOptions[]; }; export type LoggerProviderConfig = { @@ -358,7 +358,7 @@ export class NodeSDK { ? this._resource : this._resource.merge( new Resource({ - [SEMRESATTRS_SERVICE_NAME]: this._serviceName, + [ATTR_SERVICE_NAME]: this._serviceName, }) ); diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 2c451b1295..4a14369214 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -19,7 +19,7 @@ import { TextMapPropagator } from '@opentelemetry/api'; import { Instrumentation } from '@opentelemetry/instrumentation'; import { Detector, DetectorSync, IResource } from '@opentelemetry/resources'; import { LogRecordProcessor } from '@opentelemetry/sdk-logs'; -import { MetricReader, View } from '@opentelemetry/sdk-metrics'; +import { MetricReader, ViewOptions } from '@opentelemetry/sdk-metrics'; import { Sampler, SpanExporter, @@ -36,7 +36,7 @@ export interface NodeSDKConfiguration { logRecordProcessor: LogRecordProcessor; logRecordProcessors?: LogRecordProcessor[]; metricReader: MetricReader; - views: View[]; + views: ViewOptions[]; instrumentations: (Instrumentation | Instrumentation[])[]; resource: IResource; resourceDetectors: Array; diff --git a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts index 0032517e33..87c7e0f849 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -37,7 +37,6 @@ import { InstrumentType, MeterProvider, PeriodicExportingMetricReader, - View, } from '@opentelemetry/sdk-metrics'; import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; @@ -55,6 +54,7 @@ import { NoopSpanProcessor, IdGenerator, AlwaysOffSampler, + SpanProcessor, } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import * as semver from 'semver'; @@ -264,13 +264,25 @@ describe('Node SDK', () => { ); const apiTracerProvider = trace.getTracerProvider() as ProxyTracerProvider; - assert.ok(apiTracerProvider.getDelegate() instanceof NodeTracerProvider); + const nodeTracerProvider = apiTracerProvider.getDelegate(); + + assert.ok(nodeTracerProvider instanceof NodeTracerProvider); + + const spanProcessor = nodeTracerProvider['_activeSpanProcessor'] as any; + + assert( + spanProcessor.constructor.name === 'MultiSpanProcessor', + 'is MultiSpanProcessor' + ); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = spanProcessor[ + '_spanProcessors' + ] as SpanProcessor[]; - assert(sdk['_tracerProvider'] instanceof NodeTracerProvider); - assert(listOfProcessors.length === 3); + assert( + listOfProcessors.length === 3, + 'it has the right amount of processors' + ); assert(listOfProcessors[0] instanceof NoopSpanProcessor); assert(listOfProcessors[1] instanceof SimpleSpanProcessor); assert(listOfProcessors[2] instanceof BatchSpanProcessor); @@ -441,11 +453,11 @@ describe('Node SDK', () => { const sdk = new NodeSDK({ metricReader: metricReader, views: [ - new View({ + { name: 'test-view', instrumentName: 'test_counter', instrumentType: InstrumentType.COUNTER, - }), + }, ], autoDetectResources: false, }); @@ -1334,6 +1346,18 @@ describe('Node SDK', () => { describe('setup exporter from env', () => { let stubLoggerError: Sinon.SinonStub; + const getSdkSpanProcessors = (sdk: NodeSDK) => { + const tracerProvider = sdk['_tracerProvider']; + + assert(tracerProvider instanceof NodeTracerProvider); + + const activeSpanProcessor = tracerProvider['_activeSpanProcessor']; + + assert(activeSpanProcessor.constructor.name === 'MultiSpanProcessor'); + + return (activeSpanProcessor as any)['_spanProcessors'] as SpanProcessor[]; + }; + beforeEach(() => { stubLoggerError = Sinon.stub(diag, 'warn'); }); @@ -1344,8 +1368,7 @@ describe('setup exporter from env', () => { it('should use default exporter when nor env neither SDK config is given', async () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1359,8 +1382,7 @@ describe('setup exporter from env', () => { traceExporter, }); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1375,8 +1397,7 @@ describe('setup exporter from env', () => { spanProcessor, }); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); @@ -1391,8 +1412,7 @@ describe('setup exporter from env', () => { traceExporter, }); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1407,8 +1427,7 @@ describe('setup exporter from env', () => { sampler: new AlwaysOffSampler(), }); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert.ok( sdk['_tracerProvider']!['_config']?.sampler instanceof AlwaysOffSampler @@ -1425,9 +1444,7 @@ describe('setup exporter from env', () => { env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; const sdk = new NodeSDK(); sdk.start(); - - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1443,9 +1460,7 @@ describe('setup exporter from env', () => { env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = 'grpc'; const sdk = new NodeSDK(); sdk.start(); - - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1466,12 +1481,10 @@ describe('setup exporter from env', () => { 'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.' ); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; - const activeProcessor = sdk['_tracerProvider']?.getActiveSpanProcessor(); + const listOfProcessors = getSdkSpanProcessors(sdk); - assert(listOfProcessors.length === 0); - assert(activeProcessor instanceof NoopSpanProcessor); + assert(listOfProcessors.length === 1); + assert(listOfProcessors[0] instanceof NoopSpanProcessor); delete env.OTEL_TRACES_EXPORTER; await sdk.shutdown(); }); @@ -1481,8 +1494,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1502,8 +1514,7 @@ describe('setup exporter from env', () => { 'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.' ); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1538,8 +1549,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1556,8 +1566,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 2); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1576,8 +1585,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1594,8 +1602,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 2); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1614,8 +1621,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 3); assert(listOfProcessors[0] instanceof BatchSpanProcessor); @@ -1635,8 +1641,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 2); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); @@ -1652,8 +1657,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); @@ -1668,8 +1672,7 @@ describe('setup exporter from env', () => { const sdk = new NodeSDK(); sdk.start(); - const listOfProcessors = - sdk['_tracerProvider']!['_registeredSpanProcessors']!; + const listOfProcessors = getSdkSpanProcessors(sdk); assert(listOfProcessors.length === 1); assert(listOfProcessors[0] instanceof SimpleSpanProcessor); diff --git a/experimental/packages/otlp-exporter-base/package.json b/experimental/packages/otlp-exporter-base/package.json index 8d54aa2eb4..58c4803819 100644 --- a/experimental/packages/otlp-exporter-base/package.json +++ b/experimental/packages/otlp-exporter-base/package.json @@ -68,7 +68,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/otlp-grpc-exporter-base/package.json b/experimental/packages/otlp-grpc-exporter-base/package.json index 645186c78a..fac0f4ca27 100644 --- a/experimental/packages/otlp-grpc-exporter-base/package.json +++ b/experimental/packages/otlp-grpc-exporter-base/package.json @@ -32,7 +32,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/otlp-transformer/package.json b/experimental/packages/otlp-transformer/package.json index acb8853dac..30d545e449 100644 --- a/experimental/packages/otlp-transformer/package.json +++ b/experimental/packages/otlp-transformer/package.json @@ -42,7 +42,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/experimental/packages/sdk-logs/package.json b/experimental/packages/sdk-logs/package.json index 37ae70bd11..24f494fd1e 100644 --- a/experimental/packages/sdk-logs/package.json +++ b/experimental/packages/sdk-logs/package.json @@ -26,7 +26,7 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "engines": { - "node": ">=14" + "node": ">=18" }, "scripts": { "prepublishOnly": "npm run compile", diff --git a/experimental/packages/shim-opencensus/package.json b/experimental/packages/shim-opencensus/package.json index b1b293091a..1509210a8e 100644 --- a/experimental/packages/shim-opencensus/package.json +++ b/experimental/packages/shim-opencensus/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/experimental/packages/shim-opencensus/test/util.ts b/experimental/packages/shim-opencensus/test/util.ts index 842525ea0c..69a45204e6 100644 --- a/experimental/packages/shim-opencensus/test/util.ts +++ b/experimental/packages/shim-opencensus/test/util.ts @@ -22,11 +22,7 @@ import { SimpleSpanProcessor, } from '@opentelemetry/sdk-trace-base'; import { ShimTracer } from '../src/ShimTracer'; -import * as semver from 'semver'; -import { - AsyncHooksContextManager, - AsyncLocalStorageContextManager, -} from '@opentelemetry/context-async-hooks'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { Tracer, TracerProvider, context } from '@opentelemetry/api'; export async function withTestTracer( @@ -43,11 +39,11 @@ export async function withTestTracer( export async function withTestTracerProvider( func: (otelTracerProvider: TracerProvider) => void | Promise ): Promise { + const inMemExporter = new InMemorySpanExporter(); const tracerProvider = new BasicTracerProvider({ sampler: new AlwaysOnSampler(), + spanProcessors: [new SimpleSpanProcessor(inMemExporter)], }); - const inMemExporter = new InMemorySpanExporter(); - tracerProvider.addSpanProcessor(new SimpleSpanProcessor(inMemExporter)); await func(tracerProvider); @@ -61,10 +57,7 @@ export function setupNodeContextManager( before: Mocha.HookFunction, after: Mocha.HookFunction ) { - const ContextManager = semver.gte(process.version, '14.8.0') - ? AsyncLocalStorageContextManager - : AsyncHooksContextManager; - const instance = new ContextManager(); + const instance = new AsyncLocalStorageContextManager(); instance.enable(); before(() => context.setGlobalContextManager(instance)); after(() => context.disable()); diff --git a/integration-tests/propagation-validation-server/package.json b/integration-tests/propagation-validation-server/package.json index c02cc4cc49..d394a22c36 100644 --- a/integration-tests/propagation-validation-server/package.json +++ b/integration-tests/propagation-validation-server/package.json @@ -23,6 +23,6 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } } diff --git a/package-lock.json b/package-lock.json index 66caf2a017..dbd8b37732 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,7 +104,7 @@ "@opentelemetry/semantic-conventions": "1.28.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "examples/http": { @@ -126,7 +126,7 @@ "cross-env": "^6.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "examples/https": { @@ -148,7 +148,7 @@ "cross-env": "^6.0.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "examples/opentelemetry-web": { @@ -184,7 +184,7 @@ "webpack-merge": "^5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "examples/opentelemetry-web/node_modules/typescript": { @@ -219,7 +219,7 @@ "@opentelemetry/semantic-conventions": "1.28.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/backwards-compatibility/node14": { @@ -235,7 +235,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/backwards-compatibility/node14/node_modules/@types/node": { @@ -257,7 +257,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/backwards-compatibility/node16/node_modules/@types/node": { @@ -312,7 +312,7 @@ "@opentelemetry/shim-opencensus": "0.57.0" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/examples/prometheus": { @@ -353,7 +353,7 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/packages/api-logs": { @@ -383,7 +383,7 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "experimental/packages/exporter-logs-otlp-grpc": { @@ -415,7 +415,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -461,7 +461,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -506,7 +506,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -540,7 +540,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -585,7 +585,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -628,7 +628,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -667,7 +667,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -702,7 +702,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -747,7 +747,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -779,7 +779,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -808,7 +808,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -857,7 +857,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -904,7 +904,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -943,7 +943,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -985,7 +985,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -1032,7 +1032,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -1082,7 +1082,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" @@ -1122,7 +1122,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -1154,7 +1154,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -1194,7 +1194,7 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -1366,7 +1366,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" @@ -1449,7 +1449,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opencensus/core": "^0.1.0", @@ -1543,7 +1543,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/@ampproject/remapping": { @@ -27948,7 +27948,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -27968,7 +27968,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "packages/opentelemetry-context-zone-peer-dep": { @@ -28004,7 +28004,7 @@ "zone.js": "0.15.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0", @@ -28041,7 +28041,7 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28072,7 +28072,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" @@ -28117,7 +28117,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" @@ -28142,7 +28142,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28178,7 +28178,7 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28218,10 +28218,10 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "packages/opentelemetry-resources/node_modules/@opentelemetry/api": { @@ -28307,10 +28307,10 @@ "webpack": "5.96.1" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "packages/opentelemetry-sdk-trace-node": { @@ -28341,7 +28341,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28390,7 +28390,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28419,7 +28419,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" @@ -28459,10 +28459,10 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "packages/template": { @@ -28476,7 +28476,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "selenium-tests": { @@ -28519,7 +28519,7 @@ "webpack-merge": "5.10.0" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" @@ -28666,7 +28666,7 @@ "typescript": "4.4.4" }, "engines": { - "node": ">=14" + "node": ">=18" } } }, diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index f7c1f0cdb7..cc919952ff 100644 --- a/packages/opentelemetry-context-async-hooks/package.json +++ b/packages/opentelemetry-context-async-hooks/package.json @@ -30,7 +30,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index c474b5d1cd..e79a564ca8 100644 --- a/packages/opentelemetry-context-zone-peer-dep/package.json +++ b/packages/opentelemetry-context-zone-peer-dep/package.json @@ -33,7 +33,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index 8437a4c138..3ec7e48e8b 100644 --- a/packages/opentelemetry-context-zone/package.json +++ b/packages/opentelemetry-context-zone/package.json @@ -31,7 +31,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index f95c8f443f..ec8f23fa87 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -43,7 +43,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-core/src/common/attributes.ts b/packages/opentelemetry-core/src/common/attributes.ts index 0726acd581..d2636090c2 100644 --- a/packages/opentelemetry-core/src/common/attributes.ts +++ b/packages/opentelemetry-core/src/common/attributes.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { diag, SpanAttributeValue, SpanAttributes } from '@opentelemetry/api'; +import { diag, AttributeValue, Attributes } from '@opentelemetry/api'; -export function sanitizeAttributes(attributes: unknown): SpanAttributes { - const out: SpanAttributes = {}; +export function sanitizeAttributes(attributes: unknown): Attributes { + const out: Attributes = {}; if (typeof attributes !== 'object' || attributes == null) { return out; @@ -46,7 +46,7 @@ export function isAttributeKey(key: unknown): key is string { return typeof key === 'string' && key.length > 0; } -export function isAttributeValue(val: unknown): val is SpanAttributeValue { +export function isAttributeValue(val: unknown): val is AttributeValue { if (val == null) { return true; } diff --git a/packages/opentelemetry-core/src/trace/sampler/ParentBasedSampler.ts b/packages/opentelemetry-core/src/trace/sampler/ParentBasedSampler.ts index a3abf53bf4..dcfe3a253c 100644 --- a/packages/opentelemetry-core/src/trace/sampler/ParentBasedSampler.ts +++ b/packages/opentelemetry-core/src/trace/sampler/ParentBasedSampler.ts @@ -20,7 +20,7 @@ import { Link, Sampler, SamplingResult, - SpanAttributes, + Attributes, SpanKind, TraceFlags, trace, @@ -66,7 +66,7 @@ export class ParentBasedSampler implements Sampler { traceId: string, spanName: string, spanKind: SpanKind, - attributes: SpanAttributes, + attributes: Attributes, links: Link[] ): SamplingResult { const parentContext = trace.getSpanContext(context); diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index 999d043920..505162d711 100644 --- a/packages/opentelemetry-exporter-jaeger/package.json +++ b/packages/opentelemetry-exporter-jaeger/package.json @@ -30,7 +30,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index 0b897b0c6a..ea54383183 100644 --- a/packages/opentelemetry-exporter-zipkin/package.json +++ b/packages/opentelemetry-exporter-zipkin/package.json @@ -39,7 +39,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-propagator-b3/package.json b/packages/opentelemetry-propagator-b3/package.json index 85ce8bc2eb..77985c4af5 100644 --- a/packages/opentelemetry-propagator-b3/package.json +++ b/packages/opentelemetry-propagator-b3/package.json @@ -32,7 +32,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-propagator-jaeger/package.json b/packages/opentelemetry-propagator-jaeger/package.json index 0de69ea26c..1a8da7d34f 100644 --- a/packages/opentelemetry-propagator-jaeger/package.json +++ b/packages/opentelemetry-propagator-jaeger/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json index 4d763f731d..7f2a547080 100644 --- a/packages/opentelemetry-resources/package.json +++ b/packages/opentelemetry-resources/package.json @@ -43,7 +43,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", @@ -88,7 +88,7 @@ "webpack-merge": "5.10.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" }, "dependencies": { "@opentelemetry/core": "1.30.0", diff --git a/packages/opentelemetry-resources/src/IResource.ts b/packages/opentelemetry-resources/src/IResource.ts index b53a0e0244..c911904ce4 100644 --- a/packages/opentelemetry-resources/src/IResource.ts +++ b/packages/opentelemetry-resources/src/IResource.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ResourceAttributes } from './types'; +import { Attributes } from '@opentelemetry/api'; /** * An interface that represents a resource. A Resource describes the entity for which signals (metrics or trace) are @@ -33,7 +33,7 @@ export interface IResource { /** * @returns the Resource's attributes. */ - readonly attributes: ResourceAttributes; + readonly attributes: Attributes; /** * Returns a promise that will never be rejected. Resolves when all async attributes have finished being added to diff --git a/packages/opentelemetry-resources/src/Resource.ts b/packages/opentelemetry-resources/src/Resource.ts index d44dbacc4d..c2ec93ecff 100644 --- a/packages/opentelemetry-resources/src/Resource.ts +++ b/packages/opentelemetry-resources/src/Resource.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { diag } from '@opentelemetry/api'; +import { Attributes, diag } from '@opentelemetry/api'; import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_TELEMETRY_SDK_LANGUAGE, @@ -22,7 +22,6 @@ import { SEMRESATTRS_TELEMETRY_SDK_VERSION, } from '@opentelemetry/semantic-conventions'; import { SDK_INFO } from '@opentelemetry/core'; -import { ResourceAttributes } from './types'; import { defaultServiceName } from './platform'; import { IResource } from './IResource'; @@ -32,9 +31,9 @@ import { IResource } from './IResource'; */ export class Resource implements IResource { static readonly EMPTY = new Resource({}); - private _syncAttributes?: ResourceAttributes; - private _asyncAttributesPromise?: Promise; - private _attributes?: ResourceAttributes; + private _syncAttributes?: Attributes; + private _asyncAttributesPromise?: Promise; + private _attributes?: Attributes; /** * Check if async attributes have resolved. This is useful to avoid awaiting @@ -72,8 +71,8 @@ export class Resource implements IResource { * information about the entity as numbers, strings or booleans * TODO: Consider to add check/validation on attributes. */ - attributes: ResourceAttributes, - asyncAttributesPromise?: Promise + attributes: Attributes, + asyncAttributesPromise?: Promise ) { this._attributes = attributes; this.asyncAttributesPending = asyncAttributesPromise != null; @@ -92,7 +91,7 @@ export class Resource implements IResource { ); } - get attributes(): ResourceAttributes { + get attributes(): Attributes { if (this.asyncAttributesPending) { diag.error( 'Accessing resource attributes before async attributes settled' @@ -124,7 +123,7 @@ export class Resource implements IResource { merge(other: IResource | null): IResource { if (!other) return this; - // SpanAttributes from other resource overwrite attributes from this resource. + // Attributes from other resource overwrite attributes from this resource. const mergedSyncAttributes = { ...this._syncAttributes, //Support for old resource implementation where _syncAttributes is not defined diff --git a/packages/opentelemetry-resources/src/detectors/BrowserDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/BrowserDetectorSync.ts index 5fed355327..0e204920b7 100644 --- a/packages/opentelemetry-resources/src/detectors/BrowserDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/BrowserDetectorSync.ts @@ -14,12 +14,13 @@ * limitations under the License. */ +import { Attributes } from '@opentelemetry/api'; import { SEMRESATTRS_PROCESS_RUNTIME_DESCRIPTION, SEMRESATTRS_PROCESS_RUNTIME_NAME, SEMRESATTRS_PROCESS_RUNTIME_VERSION, } from '@opentelemetry/semantic-conventions'; -import { DetectorSync, ResourceAttributes } from '../types'; +import { DetectorSync } from '../types'; import { diag } from '@opentelemetry/api'; import { ResourceDetectionConfig } from '../config'; import { IResource } from '../IResource'; @@ -39,7 +40,7 @@ class BrowserDetectorSync implements DetectorSync { if (!isBrowser) { return Resource.empty(); } - const browserResource: ResourceAttributes = { + const browserResource: Attributes = { [SEMRESATTRS_PROCESS_RUNTIME_NAME]: 'browser', [SEMRESATTRS_PROCESS_RUNTIME_DESCRIPTION]: 'Web Browser', [SEMRESATTRS_PROCESS_RUNTIME_VERSION]: navigator.userAgent, @@ -54,7 +55,7 @@ class BrowserDetectorSync implements DetectorSync { * @returns The sanitized resource attributes. */ private _getResourceAttributes( - browserResource: ResourceAttributes, + browserResource: Attributes, _config?: ResourceDetectionConfig ) { if (browserResource[SEMRESATTRS_PROCESS_RUNTIME_VERSION] === '') { diff --git a/packages/opentelemetry-resources/src/detectors/EnvDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/EnvDetectorSync.ts index 329d489ec4..cb64529cbd 100644 --- a/packages/opentelemetry-resources/src/detectors/EnvDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/EnvDetectorSync.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { diag } from '@opentelemetry/api'; +import { Attributes, diag } from '@opentelemetry/api'; import { getEnv } from '@opentelemetry/core'; import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { Resource } from '../Resource'; -import { DetectorSync, ResourceAttributes } from '../types'; +import { DetectorSync } from '../types'; import { ResourceDetectionConfig } from '../config'; import { IResource } from '../IResource'; @@ -54,7 +54,7 @@ class EnvDetectorSync implements DetectorSync { * @param config The resource detection config */ detect(_config?: ResourceDetectionConfig): IResource { - const attributes: ResourceAttributes = {}; + const attributes: Attributes = {}; const env = getEnv(); const rawAttributes = env.OTEL_RESOURCE_ATTRIBUTES; @@ -90,12 +90,10 @@ class EnvDetectorSync implements DetectorSync { * of key/value pairs. * @returns The sanitized resource attributes. */ - private _parseResourceAttributes( - rawEnvAttributes?: string - ): ResourceAttributes { + private _parseResourceAttributes(rawEnvAttributes?: string): Attributes { if (!rawEnvAttributes) return {}; - const attributes: ResourceAttributes = {}; + const attributes: Attributes = {}; const rawAttributes: string[] = rawEnvAttributes.split( this._COMMA_SEPARATOR, -1 diff --git a/packages/opentelemetry-resources/src/detectors/platform/node/HostDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/platform/node/HostDetectorSync.ts index 164b07db64..123976dc57 100644 --- a/packages/opentelemetry-resources/src/detectors/platform/node/HostDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/platform/node/HostDetectorSync.ts @@ -14,13 +14,14 @@ * limitations under the License. */ +import { Attributes } from '@opentelemetry/api'; import { SEMRESATTRS_HOST_ARCH, SEMRESATTRS_HOST_ID, SEMRESATTRS_HOST_NAME, } from '@opentelemetry/semantic-conventions'; import { Resource } from '../../../Resource'; -import { DetectorSync, ResourceAttributes } from '../../../types'; +import { DetectorSync } from '../../../types'; import { ResourceDetectionConfig } from '../../../config'; import { arch, hostname } from 'os'; import { normalizeArch } from './utils'; @@ -32,7 +33,7 @@ import { getMachineId } from './machine-id/getMachineId'; */ class HostDetectorSync implements DetectorSync { detect(_config?: ResourceDetectionConfig): Resource { - const attributes: ResourceAttributes = { + const attributes: Attributes = { [SEMRESATTRS_HOST_NAME]: hostname(), [SEMRESATTRS_HOST_ARCH]: normalizeArch(arch()), }; @@ -40,9 +41,9 @@ class HostDetectorSync implements DetectorSync { return new Resource(attributes, this._getAsyncAttributes()); } - private _getAsyncAttributes(): Promise { + private _getAsyncAttributes(): Promise { return getMachineId().then(machineId => { - const attributes: ResourceAttributes = {}; + const attributes: Attributes = {}; if (machineId) { attributes[SEMRESATTRS_HOST_ID] = machineId; } diff --git a/packages/opentelemetry-resources/src/detectors/platform/node/OSDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/platform/node/OSDetectorSync.ts index 19c10a504e..aca5fbca76 100644 --- a/packages/opentelemetry-resources/src/detectors/platform/node/OSDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/platform/node/OSDetectorSync.ts @@ -14,12 +14,13 @@ * limitations under the License. */ +import { Attributes } from '@opentelemetry/api'; import { SEMRESATTRS_OS_TYPE, SEMRESATTRS_OS_VERSION, } from '@opentelemetry/semantic-conventions'; import { Resource } from '../../../Resource'; -import { DetectorSync, ResourceAttributes } from '../../../types'; +import { DetectorSync } from '../../../types'; import { ResourceDetectionConfig } from '../../../config'; import { platform, release } from 'os'; import { normalizeType } from './utils'; @@ -30,7 +31,7 @@ import { normalizeType } from './utils'; */ class OSDetectorSync implements DetectorSync { detect(_config?: ResourceDetectionConfig): Resource { - const attributes: ResourceAttributes = { + const attributes: Attributes = { [SEMRESATTRS_OS_TYPE]: normalizeType(platform()), [SEMRESATTRS_OS_VERSION]: release(), }; diff --git a/packages/opentelemetry-resources/src/detectors/platform/node/ProcessDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/platform/node/ProcessDetectorSync.ts index e2f9fdbf55..70523112c9 100644 --- a/packages/opentelemetry-resources/src/detectors/platform/node/ProcessDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/platform/node/ProcessDetectorSync.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { diag } from '@opentelemetry/api'; +import { Attributes, diag } from '@opentelemetry/api'; import { SEMRESATTRS_PROCESS_COMMAND, SEMRESATTRS_PROCESS_COMMAND_ARGS, @@ -27,7 +27,7 @@ import { SEMRESATTRS_PROCESS_RUNTIME_VERSION, } from '@opentelemetry/semantic-conventions'; import { Resource } from '../../../Resource'; -import { DetectorSync, ResourceAttributes } from '../../../types'; +import { DetectorSync } from '../../../types'; import { ResourceDetectionConfig } from '../../../config'; import { IResource } from '../../../IResource'; import * as os from 'os'; @@ -38,7 +38,7 @@ import * as os from 'os'; */ class ProcessDetectorSync implements DetectorSync { detect(_config?: ResourceDetectionConfig): IResource { - const attributes: ResourceAttributes = { + const attributes: Attributes = { [SEMRESATTRS_PROCESS_PID]: process.pid, [SEMRESATTRS_PROCESS_EXECUTABLE_NAME]: process.title, [SEMRESATTRS_PROCESS_EXECUTABLE_PATH]: process.execPath, diff --git a/packages/opentelemetry-resources/src/detectors/platform/node/ServiceInstanceIdDetectorSync.ts b/packages/opentelemetry-resources/src/detectors/platform/node/ServiceInstanceIdDetectorSync.ts index 7c0afae59e..306f90548d 100644 --- a/packages/opentelemetry-resources/src/detectors/platform/node/ServiceInstanceIdDetectorSync.ts +++ b/packages/opentelemetry-resources/src/detectors/platform/node/ServiceInstanceIdDetectorSync.ts @@ -14,9 +14,10 @@ * limitations under the License. */ +import { Attributes } from '@opentelemetry/api'; import { SEMRESATTRS_SERVICE_INSTANCE_ID } from '@opentelemetry/semantic-conventions'; import { Resource } from '../../../Resource'; -import { DetectorSync, ResourceAttributes } from '../../../types'; +import { DetectorSync } from '../../../types'; import { ResourceDetectionConfig } from '../../../config'; import { randomUUID } from 'crypto'; @@ -25,7 +26,7 @@ import { randomUUID } from 'crypto'; */ class ServiceInstanceIdDetectorSync implements DetectorSync { detect(_config?: ResourceDetectionConfig): Resource { - const attributes: ResourceAttributes = { + const attributes: Attributes = { [SEMRESATTRS_SERVICE_INSTANCE_ID]: randomUUID(), }; diff --git a/packages/opentelemetry-resources/src/index.ts b/packages/opentelemetry-resources/src/index.ts index 2162658c3d..4c93e1da78 100644 --- a/packages/opentelemetry-resources/src/index.ts +++ b/packages/opentelemetry-resources/src/index.ts @@ -17,7 +17,7 @@ export { Resource } from './Resource'; export { IResource } from './IResource'; export { defaultServiceName } from './platform'; -export { DetectorSync, ResourceAttributes, Detector } from './types'; +export { DetectorSync, Detector } from './types'; export { ResourceDetectionConfig } from './config'; export { browserDetector, diff --git a/packages/opentelemetry-resources/src/types.ts b/packages/opentelemetry-resources/src/types.ts index d20c09faa2..9004cffdf0 100644 --- a/packages/opentelemetry-resources/src/types.ts +++ b/packages/opentelemetry-resources/src/types.ts @@ -15,16 +15,8 @@ */ import { ResourceDetectionConfig } from './config'; -import { SpanAttributes } from '@opentelemetry/api'; import { IResource } from './IResource'; -/** - * Interface for Resource attributes. - * General `Attributes` interface is added in api v1.1.0. - * To backward support older api (1.0.x), the deprecated `SpanAttributes` is used here. - */ -export type ResourceAttributes = SpanAttributes; - /** * @deprecated please use {@link DetectorSync} */ diff --git a/packages/opentelemetry-resources/test/Resource.test.ts b/packages/opentelemetry-resources/test/Resource.test.ts index 3916e1c985..900ca9bbeb 100644 --- a/packages/opentelemetry-resources/test/Resource.test.ts +++ b/packages/opentelemetry-resources/test/Resource.test.ts @@ -17,7 +17,7 @@ import * as sinon from 'sinon'; import * as assert from 'assert'; import { SDK_INFO } from '@opentelemetry/core'; -import { Resource, ResourceAttributes } from '../src'; +import { Resource } from '../src'; import { SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_TELEMETRY_SDK_LANGUAGE, @@ -25,7 +25,7 @@ import { SEMRESATTRS_TELEMETRY_SDK_VERSION, } from '@opentelemetry/semantic-conventions'; import { describeBrowser, describeNode } from './util'; -import { diag } from '@opentelemetry/api'; +import { Attributes, diag } from '@opentelemetry/api'; import { Resource as Resource190 } from '@opentelemetry/resources_1.9.0'; describe('Resource', () => { @@ -167,7 +167,7 @@ describe('Resource', () => { it('should merge async attributes into sync attributes once resolved', async () => { //async attributes that resolve after 1 ms - const asyncAttributes = new Promise(resolve => { + const asyncAttributes = new Promise(resolve => { setTimeout( () => resolve({ async: 'fromasync', shared: 'fromasync' }), 1 @@ -248,7 +248,7 @@ describe('Resource', () => { ); //async attributes that resolve after 1 ms - const asyncAttributes = new Promise(resolve => { + const asyncAttributes = new Promise(resolve => { setTimeout( () => resolve({ promise2: 'promise2val', shared: 'promise2val' }), 1 diff --git a/packages/opentelemetry-sdk-trace-base/package.json b/packages/opentelemetry-sdk-trace-base/package.json index 7ab110bef9..4d8fbc5a02 100644 --- a/packages/opentelemetry-sdk-trace-base/package.json +++ b/packages/opentelemetry-sdk-trace-base/package.json @@ -44,7 +44,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", @@ -87,7 +87,7 @@ "webpack": "5.96.1" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" }, "dependencies": { "@opentelemetry/core": "1.30.0", diff --git a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts index 27188cbf04..042e98beba 100644 --- a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts @@ -68,11 +68,9 @@ export class BasicTracerProvider implements TracerProvider { >(); private readonly _config: TracerConfig; - private readonly _registeredSpanProcessors: SpanProcessor[] = []; private readonly _tracers: Map = new Map(); - - activeSpanProcessor: SpanProcessor; - readonly resource: IResource; + private readonly _resource: IResource; + private readonly _activeSpanProcessor: MultiSpanProcessor; constructor(config: TracerConfig = {}) { const mergedConfig = merge( @@ -80,30 +78,30 @@ export class BasicTracerProvider implements TracerProvider { loadDefaultConfig(), reconfigureLimits(config) ); - this.resource = mergedConfig.resource ?? Resource.empty(); + this._resource = mergedConfig.resource ?? Resource.empty(); if (mergedConfig.mergeResourceWithDefaults) { - this.resource = Resource.default().merge(this.resource); + this._resource = Resource.default().merge(this._resource); } this._config = Object.assign({}, mergedConfig, { - resource: this.resource, + resource: this._resource, }); + const spanProcessors: SpanProcessor[] = []; + if (config.spanProcessors?.length) { - this._registeredSpanProcessors = [...config.spanProcessors]; - this.activeSpanProcessor = new MultiSpanProcessor( - this._registeredSpanProcessors - ); + spanProcessors.push(...config.spanProcessors); } else { const defaultExporter = this._buildExporterFromEnv(); - if (defaultExporter !== undefined) { - const batchProcessor = new BatchSpanProcessor(defaultExporter); - this.activeSpanProcessor = batchProcessor; - } else { - this.activeSpanProcessor = new NoopSpanProcessor(); - } + spanProcessors.push( + defaultExporter + ? new BatchSpanProcessor(defaultExporter) + : new NoopSpanProcessor() + ); } + + this._activeSpanProcessor = new MultiSpanProcessor(spanProcessors); } getTracer( @@ -118,7 +116,8 @@ export class BasicTracerProvider implements TracerProvider { new Tracer( { name, version, schemaUrl: options?.schemaUrl }, this._config, - this + this._resource, + this._activeSpanProcessor ) ); } @@ -127,34 +126,6 @@ export class BasicTracerProvider implements TracerProvider { return this._tracers.get(key)!; } - /** - * @deprecated please use {@link TracerConfig} spanProcessors property - * Adds a new {@link SpanProcessor} to this tracer. - * @param spanProcessor the new SpanProcessor to be added. - */ - addSpanProcessor(spanProcessor: SpanProcessor): void { - if (this._registeredSpanProcessors.length === 0) { - // since we might have enabled by default a batchProcessor, we disable it - // before adding the new one - this.activeSpanProcessor - .shutdown() - .catch(err => - diag.error( - 'Error while trying to shutdown current span processor', - err - ) - ); - } - this._registeredSpanProcessors.push(spanProcessor); - this.activeSpanProcessor = new MultiSpanProcessor( - this._registeredSpanProcessors - ); - } - - getActiveSpanProcessor(): SpanProcessor { - return this.activeSpanProcessor; - } - /** * Register this TracerProvider for use with the OpenTelemetry API. * Undefined values may be replaced with defaults, and @@ -179,7 +150,7 @@ export class BasicTracerProvider implements TracerProvider { forceFlush(): Promise { const timeout = this._config.forceFlushTimeoutMillis; - const promises = this._registeredSpanProcessors.map( + const promises = this._activeSpanProcessor['_spanProcessors'].map( (spanProcessor: SpanProcessor) => { return new Promise(resolve => { let state: ForceFlushState; @@ -227,7 +198,7 @@ export class BasicTracerProvider implements TracerProvider { } shutdown(): Promise { - return this.activeSpanProcessor.shutdown(); + return this._activeSpanProcessor.shutdown(); } /** diff --git a/packages/opentelemetry-sdk-trace-base/src/Sampler.ts b/packages/opentelemetry-sdk-trace-base/src/Sampler.ts index 0a4236e882..6824fe3cce 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Sampler.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Sampler.ts @@ -17,7 +17,7 @@ import { Context, Link, - SpanAttributes, + Attributes, SpanKind, TraceState, } from '@opentelemetry/api'; @@ -58,7 +58,7 @@ export interface SamplingResult { * Caller may call {@link Sampler}.shouldSample any number of times and * can safely cache the returned value. */ - attributes?: Readonly; + attributes?: Readonly; /** * A {@link TraceState} that will be associated with the {@link Span} through * the new {@link SpanContext}. Samplers SHOULD return the TraceState from @@ -83,7 +83,7 @@ export interface Sampler { * span to be created starts a new trace. * @param spanName of the span to be created. * @param spanKind of the span to be created. - * @param attributes Initial set of SpanAttributes for the Span being constructed. + * @param attributes Initial set of Attributes for the Span being constructed. * @param links Collection of links that will be associated with the Span to * be created. Typically useful for batch operations. * @returns a {@link SamplingResult}. @@ -93,7 +93,7 @@ export interface Sampler { traceId: string, spanName: string, spanKind: SpanKind, - attributes: SpanAttributes, + attributes: Attributes, links: Link[] ): SamplingResult; diff --git a/packages/opentelemetry-sdk-trace-base/src/Span.ts b/packages/opentelemetry-sdk-trace-base/src/Span.ts index 39a8b30308..9d567e794d 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Span.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Span.ts @@ -21,8 +21,8 @@ import { HrTime, Link, Span as APISpan, - SpanAttributes, - SpanAttributeValue, + Attributes, + AttributeValue, SpanContext, SpanKind, SpanStatus, @@ -48,23 +48,43 @@ import { SEMATTRS_EXCEPTION_STACKTRACE, SEMATTRS_EXCEPTION_TYPE, } from '@opentelemetry/semantic-conventions'; -import { ExceptionEventName } from './enums'; import { ReadableSpan } from './export/ReadableSpan'; +import { ExceptionEventName } from './enums'; import { SpanProcessor } from './SpanProcessor'; import { TimedEvent } from './TimedEvent'; -import { Tracer } from './Tracer'; import { SpanLimits } from './types'; +/** + * This type provides the properties of @link{ReadableSpan} at the same time + * of the Span API + */ +export type Span = APISpan & ReadableSpan; + +interface SpanOptions { + resource: IResource; + scope: InstrumentationLibrary; + context: Context; + spanContext: SpanContext; + name: string; + kind: SpanKind; + parentSpanId?: string; + links?: Link[]; + startTime?: TimeInput; + attributes?: Attributes; + spanLimits: SpanLimits; + spanProcessor: SpanProcessor; +} + /** * This class represents a span. */ -export class Span implements APISpan, ReadableSpan { +export class SpanImpl implements Span { // Below properties are included to implement ReadableSpan for export // purposes but are not intended to be written-to directly. private readonly _spanContext: SpanContext; readonly kind: SpanKind; readonly parentSpanId?: string; - readonly attributes: SpanAttributes = {}; + readonly attributes: Attributes = {}; readonly links: Link[] = []; readonly events: TimedEvent[] = []; readonly startTime: HrTime; @@ -91,55 +111,41 @@ export class Span implements APISpan, ReadableSpan { private readonly _startTimeProvided: boolean; /** - * Constructs a new Span instance. - * - * @deprecated calling Span constructor directly is not supported. Please use tracer.startSpan. - * */ - constructor( - parentTracer: Tracer, - context: Context, - spanName: string, - spanContext: SpanContext, - kind: SpanKind, - parentSpanId?: string, - links: Link[] = [], - startTime?: TimeInput, - _deprecatedClock?: unknown, // keeping this argument even though it is unused to ensure backwards compatibility - attributes?: SpanAttributes - ) { - this.name = spanName; - this._spanContext = spanContext; - this.parentSpanId = parentSpanId; - this.kind = kind; - this.links = links; - + * Constructs a new SpanImpl instance. + */ + constructor(opts: SpanOptions) { const now = Date.now(); + + this._spanContext = opts.spanContext; this._performanceStartTime = otperformance.now(); this._performanceOffset = now - (this._performanceStartTime + getTimeOrigin()); - this._startTimeProvided = startTime != null; - - this.startTime = this._getTime(startTime ?? now); - - this.resource = parentTracer.resource; - this.instrumentationLibrary = parentTracer.instrumentationLibrary; - this._spanLimits = parentTracer.getSpanLimits(); + this._startTimeProvided = opts.startTime != null; + this._spanLimits = opts.spanLimits; this._attributeValueLengthLimit = this._spanLimits.attributeValueLengthLimit || 0; - - if (attributes != null) { - this.setAttributes(attributes); + this._spanProcessor = opts.spanProcessor; + + this.name = opts.name; + this.parentSpanId = opts.parentSpanId; + this.kind = opts.kind; + this.links = opts.links || []; + this.startTime = this._getTime(opts.startTime ?? now); + this.resource = opts.resource; + this.instrumentationLibrary = opts.scope; + + if (opts.attributes != null) { + this.setAttributes(opts.attributes); } - this._spanProcessor = parentTracer.getActiveSpanProcessor(); - this._spanProcessor.onStart(this, context); + this._spanProcessor.onStart(this, opts.context); } spanContext(): SpanContext { return this._spanContext; } - setAttribute(key: string, value?: SpanAttributeValue): this; + setAttribute(key: string, value?: AttributeValue): this; setAttribute(key: string, value: unknown): this { if (value == null || this._isSpanEnded()) return this; if (key.length === 0) { @@ -163,7 +169,7 @@ export class Span implements APISpan, ReadableSpan { return this; } - setAttributes(attributes: SpanAttributes): this { + setAttributes(attributes: Attributes): this { for (const [k, v] of Object.entries(attributes)) { this.setAttribute(k, v); } @@ -179,7 +185,7 @@ export class Span implements APISpan, ReadableSpan { */ addEvent( name: string, - attributesOrStartTime?: SpanAttributes | TimeInput, + attributesOrStartTime?: Attributes | TimeInput, timeStamp?: TimeInput ): this { if (this._isSpanEnded()) return this; @@ -313,7 +319,7 @@ export class Span implements APISpan, ReadableSpan { } recordException(exception: Exception, time?: TimeInput): void { - const attributes: SpanAttributes = {}; + const attributes: Attributes = {}; if (typeof exception === 'string') { attributes[SEMATTRS_EXCEPTION_MESSAGE] = exception; } else if (exception) { @@ -392,7 +398,7 @@ export class Span implements APISpan, ReadableSpan { * @param value Attribute value * @returns truncated attribute value if required, otherwise same value */ - private _truncateToSize(value: SpanAttributeValue): SpanAttributeValue { + private _truncateToSize(value: AttributeValue): AttributeValue { const limit = this._attributeValueLengthLimit; // Check limit if (limit <= 0) { diff --git a/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts b/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts index 1f835ba710..068caa432d 100644 --- a/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts +++ b/packages/opentelemetry-sdk-trace-base/src/TimedEvent.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { HrTime, SpanAttributes } from '@opentelemetry/api'; +import { HrTime, Attributes } from '@opentelemetry/api'; /** * Represents a timed event. @@ -25,7 +25,7 @@ export interface TimedEvent { /** The name of the event. */ name: string; /** The attributes of the event. */ - attributes?: SpanAttributes; + attributes?: Attributes; /** Count of attributes of the event that were dropped due to collection limits */ droppedAttributesCount?: number; } diff --git a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts index f943e6a11c..c7ebdcc010 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts @@ -20,15 +20,14 @@ import { sanitizeAttributes, isTracingSuppressed, } from '@opentelemetry/core'; -import { IResource } from '@opentelemetry/resources'; -import { BasicTracerProvider } from './BasicTracerProvider'; -import { Span } from './Span'; +import { SpanImpl } from './Span'; import { GeneralLimits, SpanLimits, TracerConfig } from './types'; import { mergeConfig } from './utility'; import { SpanProcessor } from './SpanProcessor'; import { Sampler } from './Sampler'; import { IdGenerator } from './IdGenerator'; import { RandomIdGenerator } from './platform'; +import { IResource } from '@opentelemetry/resources'; /** * This class represents a basic tracer. @@ -38,23 +37,27 @@ export class Tracer implements api.Tracer { private readonly _generalLimits: GeneralLimits; private readonly _spanLimits: SpanLimits; private readonly _idGenerator: IdGenerator; - readonly resource: IResource; readonly instrumentationLibrary: InstrumentationLibrary; + private readonly _resource: IResource; + private readonly _spanProcessor: SpanProcessor; + /** * Constructs a new Tracer instance. */ constructor( instrumentationLibrary: InstrumentationLibrary, config: TracerConfig, - private _tracerProvider: BasicTracerProvider + resource: IResource, + spanProcessor: SpanProcessor ) { const localConfig = mergeConfig(config); this._sampler = localConfig.sampler; this._generalLimits = localConfig.generalLimits; this._spanLimits = localConfig.spanLimits; this._idGenerator = config.idGenerator || new RandomIdGenerator(); - this.resource = _tracerProvider.resource; + this._resource = resource; + this._spanProcessor = spanProcessor; this.instrumentationLibrary = instrumentationLibrary; } @@ -138,18 +141,20 @@ export class Tracer implements api.Tracer { Object.assign(attributes, samplingResult.attributes) ); - const span = new Span( - this, + const span = new SpanImpl({ + resource: this._resource, + scope: this.instrumentationLibrary, context, - name, spanContext, - spanKind, - parentSpanId, + name, + kind: spanKind, links, - options.startTime, - undefined, - initAttributes - ); + parentSpanId, + attributes: initAttributes, + startTime: options.startTime, + spanProcessor: this._spanProcessor, + spanLimits: this._spanLimits, + }); return span; } @@ -250,8 +255,4 @@ export class Tracer implements api.Tracer { getSpanLimits(): SpanLimits { return this._spanLimits; } - - getActiveSpanProcessor(): SpanProcessor { - return this._tracerProvider.getActiveSpanProcessor(); - } } diff --git a/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts b/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts index 20ffea4c56..34741c0323 100644 --- a/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts +++ b/packages/opentelemetry-sdk-trace-base/src/export/ReadableSpan.ts @@ -17,7 +17,7 @@ import { SpanKind, SpanStatus, - SpanAttributes, + Attributes, HrTime, Link, SpanContext, @@ -34,7 +34,7 @@ export interface ReadableSpan { readonly startTime: HrTime; readonly endTime: HrTime; readonly status: SpanStatus; - readonly attributes: SpanAttributes; + readonly attributes: Attributes; readonly links: Link[]; readonly events: TimedEvent[]; readonly duration: HrTime; diff --git a/packages/opentelemetry-sdk-trace-base/src/sampler/ParentBasedSampler.ts b/packages/opentelemetry-sdk-trace-base/src/sampler/ParentBasedSampler.ts index 6f89ac6431..eb621adcf9 100644 --- a/packages/opentelemetry-sdk-trace-base/src/sampler/ParentBasedSampler.ts +++ b/packages/opentelemetry-sdk-trace-base/src/sampler/ParentBasedSampler.ts @@ -18,7 +18,7 @@ import { Context, isSpanContextValid, Link, - SpanAttributes, + Attributes, SpanKind, TraceFlags, trace, @@ -64,7 +64,7 @@ export class ParentBasedSampler implements Sampler { traceId: string, spanName: string, spanKind: SpanKind, - attributes: SpanAttributes, + attributes: Attributes, links: Link[] ): SamplingResult { const parentContext = trace.getSpanContext(context); 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 282331810d..62395128f9 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts @@ -44,6 +44,8 @@ import { ConsoleSpanExporter, SimpleSpanProcessor, } from '../../src'; +import { SpanImpl } from '../../src/Span'; +import { MultiSpanProcessor } from '../../src/MultiSpanProcessor'; class DummyPropagator implements TextMapPropagator { inject(context: Context, carrier: any, setter: TextMapSetter): void { @@ -90,25 +92,45 @@ describe('BasicTracerProvider', () => { it('should use noop span processor by default', () => { const tracer = new BasicTracerProvider(); - assert.ok(tracer.activeSpanProcessor instanceof NoopSpanProcessor); + assert.ok(tracer['_activeSpanProcessor'] instanceof MultiSpanProcessor); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'][0] instanceof + NoopSpanProcessor + ); }); it('should use noop span processor by default and no diag error', () => { const errorStub = sinon.spy(diag, 'error'); const tracer = new BasicTracerProvider(); - assert.ok(tracer.activeSpanProcessor instanceof NoopSpanProcessor); + assert.ok(tracer['_activeSpanProcessor'] instanceof MultiSpanProcessor); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'][0] instanceof + NoopSpanProcessor + ); sinon.assert.notCalled(errorStub); }); }); describe('when user sets unavailable exporter', () => { it('should use noop span processor by default and show diag error', () => { - const errorStub = sinon.spy(diag, 'error'); envSource.OTEL_TRACES_EXPORTER = 'someExporter'; - + const errorStub = sinon.spy(diag, 'error'); const tracer = new BasicTracerProvider(); - assert.ok(tracer.activeSpanProcessor instanceof NoopSpanProcessor); + assert.ok(tracer['_activeSpanProcessor'] instanceof MultiSpanProcessor); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'][0] instanceof + NoopSpanProcessor + ); sinon.assert.calledWith( errorStub, 'Exporter "someExporter" requested through environment variable is unavailable.' @@ -121,16 +143,22 @@ describe('BasicTracerProvider', () => { it('should use the span processors defined in the config', () => { const traceExporter = new ConsoleSpanExporter(); const spanProcessor = new SimpleSpanProcessor(traceExporter); - const tracer = new BasicTracerProvider({ spanProcessors: [spanProcessor], }); + + assert.ok(tracer['_activeSpanProcessor'] instanceof MultiSpanProcessor); assert.ok( - tracer['_registeredSpanProcessors'][0] instanceof SimpleSpanProcessor + tracer['_activeSpanProcessor']['_spanProcessors'].length === 1 ); assert.ok( - tracer['_registeredSpanProcessors'][0]['_exporter'] instanceof - ConsoleSpanExporter + tracer['_activeSpanProcessor']['_spanProcessors'][0] instanceof + SimpleSpanProcessor + ); + assert.ok( + tracer['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof ConsoleSpanExporter ); }); }); @@ -436,13 +464,21 @@ describe('BasicTracerProvider', () => { W3CTraceContextPropagator ); /* BasicTracerProvider has no exporters by default, so skipping testing the exporter getter */ - provider.register(); - const processor = provider.getActiveSpanProcessor(); - assert(processor instanceof BatchSpanProcessor); - // @ts-expect-error access configured to verify its the correct one - const exporter = processor._exporter; - assert(exporter instanceof DummyExporter); + + assert.ok(provider['_activeSpanProcessor'] instanceof MultiSpanProcessor); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0] instanceof + BatchSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof DummyExporter + ); sinon.assert.calledOnceWithExactly( setGlobalPropagatorStub, @@ -484,11 +520,20 @@ describe('BasicTracerProvider', () => { const provider = new CustomTracerProvider({}); provider.register(); - const processor = provider.getActiveSpanProcessor(); - assert(processor instanceof BatchSpanProcessor); - // @ts-expect-error access configured to verify its the correct one - const exporter = processor._exporter; - assert(exporter instanceof DummyExporter); + + assert.ok(provider['_activeSpanProcessor'] instanceof MultiSpanProcessor); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0] instanceof + BatchSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof DummyExporter + ); sinon.assert.calledOnceWithExactly( setGlobalPropagatorStub, @@ -588,11 +633,22 @@ describe('BasicTracerProvider', () => { envSource.OTEL_TRACES_EXPORTER = 'memory'; const provider = new CustomTracerProvider({}); provider.register(); - const processor = provider.getActiveSpanProcessor(); - assert(processor instanceof BatchSpanProcessor); - // @ts-expect-error access configured to verify its the correct one - const exporter = processor._exporter; - assert(exporter instanceof InMemorySpanExporter); + + assert.ok( + provider['_activeSpanProcessor'] instanceof MultiSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0] instanceof + BatchSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof InMemorySpanExporter + ); }); }); }); @@ -602,22 +658,22 @@ describe('BasicTracerProvider', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span'); assert.ok(span); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); }); it('should propagate resources', () => { const tracerProvider = new BasicTracerProvider(); const tracer = tracerProvider.getTracer('default'); const span = tracer.startSpan('my-span') as Span; - assert.strictEqual(tracer.resource, tracerProvider.resource); - assert.strictEqual(span.resource, tracerProvider.resource); + assert.strictEqual(tracer['_resource'], tracerProvider['_resource']); + assert.strictEqual(span.resource, tracerProvider['_resource']); }); it('should start a span with name and options', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span', {}); assert.ok(span); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); const context = span.spanContext(); assert.ok(context.traceId.match(/[a-f0-9]{32}/)); assert.ok(context.spanId.match(/[a-f0-9]{16}/)); @@ -658,7 +714,7 @@ describe('BasicTracerProvider', () => { traceState: state, }) ); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); const context = span.spanContext(); assert.strictEqual(context.traceId, 'd4cda95b652f4a1592b449d5929fda1b'); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); @@ -711,7 +767,7 @@ describe('BasicTracerProvider', () => { 'invalid-parent' as unknown as SpanContext ) ); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); assert.deepStrictEqual((span as Span).parentSpanId, undefined); }); @@ -726,7 +782,7 @@ describe('BasicTracerProvider', () => { traceFlags: TraceFlags.SAMPLED, }) ); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); const context = span.spanContext(); assert.ok(context.traceId.match(/[a-f0-9]{32}/)); assert.ok(context.spanId.match(/[a-f0-9]{16}/)); @@ -753,7 +809,7 @@ describe('BasicTracerProvider', () => { sampler: new AlwaysOnSampler(), }).getTracer('default'); const span = tracer.startSpan('my-span'); - assert.ok(span instanceof Span); + assert.ok(span instanceof SpanImpl); assert.strictEqual(span.spanContext().traceFlags, TraceFlags.SAMPLED); assert.strictEqual(span.isRecording(), true); }); @@ -778,7 +834,7 @@ describe('BasicTracerProvider', () => { }); describe('.forceFlush()', () => { - it('should call forceFlush on all registered span processors', done => { + it('should call forceFlush with the default processor', done => { sinon.restore(); const forceFlushStub = sinon.stub( NoopSpanProcessor.prototype, @@ -787,11 +843,33 @@ describe('BasicTracerProvider', () => { forceFlushStub.resolves(); const tracerProvider = new BasicTracerProvider(); + + tracerProvider + .forceFlush() + .then(() => { + sinon.restore(); + assert(forceFlushStub.calledOnce); + done(); + }) + .catch(error => { + sinon.restore(); + done(error); + }); + }); + + it('should call forceFlush on all registered span processors', done => { + sinon.restore(); + const forceFlushStub = sinon.stub( + NoopSpanProcessor.prototype, + 'forceFlush' + ); + forceFlushStub.resolves(); + const spanProcessorOne = new NoopSpanProcessor(); const spanProcessorTwo = new NoopSpanProcessor(); - - tracerProvider.addSpanProcessor(spanProcessorOne); - tracerProvider.addSpanProcessor(spanProcessorTwo); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [spanProcessorOne, spanProcessorTwo], + }); tracerProvider .forceFlush() @@ -815,11 +893,11 @@ describe('BasicTracerProvider', () => { ); forceFlushStub.returns(Promise.reject('Error')); - const tracerProvider = new BasicTracerProvider(); const spanProcessorOne = new NoopSpanProcessor(); const spanProcessorTwo = new NoopSpanProcessor(); - tracerProvider.addSpanProcessor(spanProcessorOne); - tracerProvider.addSpanProcessor(spanProcessorTwo); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [spanProcessorOne, spanProcessorTwo], + }); tracerProvider .forceFlush() @@ -851,7 +929,7 @@ describe('BasicTracerProvider', () => { describe('.resource', () => { it('should use the default resource when no resource is provided', function () { const tracerProvider = new BasicTracerProvider(); - assert.deepStrictEqual(tracerProvider.resource, Resource.default()); + assert.deepStrictEqual(tracerProvider['_resource'], Resource.default()); }); it('should not merge with defaults when flag is set to false', function () { @@ -860,7 +938,7 @@ describe('BasicTracerProvider', () => { mergeResourceWithDefaults: false, resource: expectedResource, }); - assert.deepStrictEqual(tracerProvider.resource, expectedResource); + assert.deepStrictEqual(tracerProvider['_resource'], expectedResource); }); it('should merge with defaults when flag is set to true', function () { @@ -870,7 +948,7 @@ describe('BasicTracerProvider', () => { resource: providedResource, }); assert.deepStrictEqual( - tracerProvider.resource, + tracerProvider['_resource'], Resource.default().merge(providedResource) ); }); @@ -880,7 +958,7 @@ describe('BasicTracerProvider', () => { it('should trigger shutdown when manually invoked', () => { const tracerProvider = new BasicTracerProvider(); const shutdownStub = sinon.stub( - tracerProvider.getActiveSpanProcessor(), + tracerProvider['_activeSpanProcessor'], 'shutdown' ); tracerProvider.shutdown(); diff --git a/packages/opentelemetry-sdk-trace-base/test/common/MultiSpanProcessor.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/MultiSpanProcessor.test.ts index 7412a121ca..34292ed899 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/MultiSpanProcessor.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/MultiSpanProcessor.test.ts @@ -53,38 +53,25 @@ describe('MultiSpanProcessor', () => { } }); - it('should handle empty span processor', () => { - const multiSpanProcessor = new MultiSpanProcessor([]); - - const tracerProvider = new BasicTracerProvider(); - tracerProvider.addSpanProcessor(multiSpanProcessor); - const tracer = tracerProvider.getTracer('default'); - const span = tracer.startSpan('one'); - span.end(); - multiSpanProcessor.shutdown(); - }); - it('should handle one span processor', () => { const processor1 = new TestProcessor(); - const multiSpanProcessor = new MultiSpanProcessor([processor1]); - - const tracerProvider = new BasicTracerProvider(); - tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [processor1], + }); const tracer = tracerProvider.getTracer('default'); const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); span.end(); assert.strictEqual(processor1.spans.length, 1); - multiSpanProcessor.shutdown(); + tracerProvider['_activeSpanProcessor'].shutdown(); }); it('should handle two span processor', async () => { const processor1 = new TestProcessor(); const processor2 = new TestProcessor(); - const multiSpanProcessor = new MultiSpanProcessor([processor1, processor2]); - - const tracerProvider = new BasicTracerProvider(); - tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [processor1, processor2], + }); const tracer = tracerProvider.getTracer('default'); const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); @@ -94,18 +81,18 @@ describe('MultiSpanProcessor', () => { assert.strictEqual(processor1.spans.length, 1); assert.strictEqual(processor1.spans.length, processor2.spans.length); - await multiSpanProcessor.shutdown(); - assert.strictEqual(processor1.spans.length, 0); - assert.strictEqual(processor1.spans.length, processor2.spans.length); + tracerProvider.shutdown().then(() => { + assert.strictEqual(processor1.spans.length, 0); + assert.strictEqual(processor1.spans.length, processor2.spans.length); + }); }); it('should export spans on manual shutdown from two span processor', () => { const processor1 = new TestProcessor(); const processor2 = new TestProcessor(); - const multiSpanProcessor = new MultiSpanProcessor([processor1, processor2]); - - const tracerProvider = new BasicTracerProvider(); - tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [processor1, processor2], + }); const tracer = tracerProvider.getTracer('default'); const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); @@ -124,10 +111,9 @@ describe('MultiSpanProcessor', () => { it('should export spans on manual shutdown from two span processor', () => { const processor1 = new TestProcessor(); const processor2 = new TestProcessor(); - const multiSpanProcessor = new MultiSpanProcessor([processor1, processor2]); - - const tracerProvider = new BasicTracerProvider(); - tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [processor1, processor2], + }); const tracer = tracerProvider.getTracer('default'); const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); 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 ef06a1d884..1e9297b7b0 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/Span.test.ts @@ -23,8 +23,8 @@ import { SpanKind, TraceFlags, HrTime, - SpanAttributes, - SpanAttributeValue, + Attributes, + AttributeValue, } from '@opentelemetry/api'; import { DEFAULT_ATTRIBUTE_COUNT_LIMIT, @@ -42,6 +42,7 @@ import { import * as assert from 'assert'; import * as sinon from 'sinon'; import { BasicTracerProvider, Span, SpanProcessor } from '../../src'; +import { SpanImpl } from '../../src/Span'; import { invalidAttributes, validAttributes } from './util'; const performanceTimeOrigin: HrTime = [1, 1]; @@ -76,25 +77,31 @@ describe('Span', () => { }; it('should create a Span instance', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); - assert.ok(span instanceof Span); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); + assert.ok(span instanceof SpanImpl); span.end(); }); it('should have valid startTime', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.ok( hrTimeToMilliseconds(span.startTime) > hrTimeToMilliseconds(performanceTimeOrigin) @@ -102,13 +109,16 @@ describe('Span', () => { }); it('should have valid endTime', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.end(); assert.ok( hrTimeToNanoseconds(span.endTime) >= hrTimeToNanoseconds(span.startTime), @@ -123,25 +133,31 @@ describe('Span', () => { }); it('should have a duration', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.end(); assert.ok(hrTimeToNanoseconds(span.duration) >= 0); }); it('should ensure duration is never negative even if provided with inconsistent times', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); // @ts-expect-error writing readonly property. performance time origin is mocked to return ms value of [1,1] span['_performanceOffset'] = 0; span.end(hrTimeToMilliseconds(span.startTime) - 1); @@ -149,13 +165,16 @@ describe('Span', () => { }); it('should have valid event.time', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addEvent('my-event'); assert.ok( hrTimeToMilliseconds(span.events[0].time) > @@ -165,16 +184,17 @@ describe('Span', () => { it('should have an entered time for event', () => { const startTime = Date.now(); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER, - undefined, - [], - startTime - ); + name, + kind: SpanKind.SERVER, + startTime, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); const eventTimeMS = 123; const spanStartTime = hrTimeToMilliseconds(span.startTime); const eventTime = spanStartTime + eventTimeMS; @@ -188,16 +208,17 @@ describe('Span', () => { describe('when 2nd param is "TimeInput" type', () => { it('should have an entered time for event - ', () => { const startTime = Date.now(); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER, - undefined, - [], - startTime - ); + name, + kind: SpanKind.SERVER, + startTime, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); const eventTimeMS = 123; const spanStartTime = hrTimeToMilliseconds(span.startTime); const eventTime = spanStartTime + eventTimeMS; @@ -210,13 +231,16 @@ describe('Span', () => { }); it('should get the span context of span', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); const context = span.spanContext(); assert.strictEqual(context.traceId, spanContext.traceId); assert.strictEqual(context.traceFlags, TraceFlags.SAMPLED); @@ -228,24 +252,30 @@ describe('Span', () => { describe('isRecording', () => { it('should return true when span is not ended', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.ok(span.isRecording()); span.end(); }); it('should return false when span is ended', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.end(); assert.ok(span.isRecording() === false); }); @@ -254,32 +284,38 @@ describe('Span', () => { describe('setAttribute', () => { describe('when default options set', () => { it('should set an attribute', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (const [k, v] of Object.entries(validAttributes)) { span.setAttribute(k, v); } for (const [k, v] of Object.entries(invalidAttributes)) { - span.setAttribute(k, v as unknown as SpanAttributeValue); + span.setAttribute(k, v as unknown as AttributeValue); } assert.deepStrictEqual(span.attributes, validAttributes); }); it('should be able to overwrite attributes', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setAttribute('overwrite', 'initial value'); span.setAttribute('overwrite', 'overwritten value'); @@ -299,13 +335,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 150; i++) { span.setAttribute('foo' + i, 'bar' + i); } @@ -331,13 +370,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should truncate value which length exceeds this limit', () => { span.setAttribute('attr-with-more-length', 'abcdefgh'); @@ -375,18 +417,17 @@ describe('Span', () => { }); it('should truncate value when attributes are passed to the constructor', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT, - undefined, - undefined, - undefined, - undefined, - { 'attr-with-more-length': 'abcdefgh' } - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + attributes: { 'attr-with-more-length': 'abcdefgh' }, + }); assert.strictEqual(span.attributes['attr-with-more-length'], 'abcde'); }); }); @@ -399,13 +440,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should not truncate any value', () => { span.setAttribute('attr-not-truncate', 'abcdefgh'); @@ -436,13 +480,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 150; i++) { span.setAttribute('foo' + i, 'bar' + i); } @@ -464,13 +511,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should truncate value which length exceeds this limit', () => { span.setAttribute('attr-with-more-length', 'abcdefgh'); @@ -516,13 +566,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should not truncate any value', () => { span.setAttribute('attr-not-truncate', 'abcdefgh'); @@ -556,13 +609,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 150; i++) { span.setAttribute('foo' + i, 'bar' + i); } @@ -588,13 +644,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 150; i++) { span.setAttribute('foo' + i, 'bar' + i); } @@ -624,13 +683,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should truncate value which length exceeds span limit', () => { span.setAttribute('attr-with-more-length', 'abcdefgh'); @@ -680,13 +742,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); it('should not truncate value', () => { span.setAttribute('attr-with-more-length', 'abcdefghijklmn'); @@ -726,16 +791,19 @@ describe('Span', () => { describe('setAttributes', () => { it('should be able to set multiple attributes', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setAttributes(validAttributes); - span.setAttributes(invalidAttributes as unknown as SpanAttributes); + span.setAttributes(invalidAttributes as unknown as Attributes); assert.deepStrictEqual(span.attributes, validAttributes); }); @@ -743,30 +811,36 @@ describe('Span', () => { describe('addEvent', () => { it('should add an event', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addEvent('sent'); span.addEvent('rev', { attr1: 'value', attr2: 123, attr3: true }); span.end(); }); it('should sanitize attribute values', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addEvent('rev', { ...validAttributes, ...invalidAttributes, - } as unknown as SpanAttributes); + } as unknown as Attributes); span.end(); assert.strictEqual(span.events.length, 1); @@ -776,13 +850,16 @@ describe('Span', () => { }); it('should drop extra events', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); const debugStub = sinon.spy(diag, 'debug'); const warnStub = sinon.spy(diag, 'warn'); @@ -803,13 +880,16 @@ describe('Span', () => { }); it('should store the count of dropped events in droppedEventsCount', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 150; i++) { span.addEvent('sent' + i); } @@ -825,13 +905,16 @@ describe('Span', () => { }, }).getTracer('default'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); for (let i = 0; i < 10; i++) { span.addEvent('sent' + i); } @@ -841,13 +924,16 @@ describe('Span', () => { }); it('should set an error status', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setStatus({ code: SpanStatusCode.ERROR, message: 'This is an error', @@ -860,13 +946,16 @@ describe('Span', () => { it('should drop non-string status message', function () { const warnStub = sinon.spy(diag, 'warn'); - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setStatus({ code: SpanStatusCode.ERROR, message: new Error('this is not a string') as any, @@ -883,14 +972,17 @@ describe('Span', () => { it('should return ReadableSpan', () => { const parentId = '5c1c63257de34c67'; - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.INTERNAL, - parentId - ); + name: 'my-span', + kind: SpanKind.INTERNAL, + parentSpanId: parentId, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.name, 'my-span'); assert.strictEqual(span.kind, SpanKind.INTERNAL); @@ -910,13 +1002,16 @@ describe('Span', () => { }); it('should return ReadableSpan with attributes', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'my-span', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setAttribute('attr1', 'value1'); assert.deepStrictEqual(span.attributes, { attr1: 'value1' }); @@ -936,21 +1031,23 @@ describe('Span', () => { }); it('should return ReadableSpan with links', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT, - undefined, - [ + name: 'my-span', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + links: [ { context: linkContext }, { context: linkContext, attributes: { attr1: 'value', attr2: 123, attr3: true }, }, - ] - ); + ], + }); assert.strictEqual(span.links.length, 2); assert.deepStrictEqual(span.links, [ { @@ -966,13 +1063,16 @@ describe('Span', () => { }); it('should be possible to add a link after span creation', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CONSUMER - ); + name: 'my-span', + kind: SpanKind.CONSUMER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addLink({ context: linkContext }); @@ -987,13 +1087,16 @@ describe('Span', () => { }); it('should be possible to add multiple links after span creation', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CONSUMER - ); + name: 'my-span', + kind: SpanKind.CONSUMER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addLinks([ { context: linkContext }, @@ -1018,13 +1121,16 @@ describe('Span', () => { }); it('should return ReadableSpan with events', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - 'my-span', + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'my-span', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.addEvent('sent'); assert.strictEqual(span.events.length, 1); const [event] = span.events; @@ -1053,13 +1159,16 @@ describe('Span', () => { }); it('should return ReadableSpan with new status', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.setStatus({ code: SpanStatusCode.ERROR, message: 'This is an error', @@ -1077,13 +1186,16 @@ describe('Span', () => { }); it('should only end a span once', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); const endTime = Date.now(); span.end(endTime); span.end(endTime + 10); @@ -1091,13 +1203,16 @@ describe('Span', () => { }); it('should update name', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); span.updateName('foo-span'); span.end(); @@ -1107,13 +1222,16 @@ describe('Span', () => { }); it('should have ended', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.SERVER - ); + name, + kind: SpanKind.SERVER, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.ended, false); span.end(); assert.strictEqual(span.ended, true); @@ -1131,9 +1249,9 @@ describe('Span', () => { shutdown: () => Promise.resolve(), }; - const provider = new BasicTracerProvider(); - - provider.addSpanProcessor(processor); + const provider = new BasicTracerProvider({ + spanProcessors: [processor], + }); provider.getTracer('default').startSpan('test'); assert.ok(started); @@ -1150,9 +1268,9 @@ describe('Span', () => { shutdown: () => Promise.resolve(), }; - const provider = new BasicTracerProvider(); - - provider.addSpanProcessor(processor); + const provider = new BasicTracerProvider({ + spanProcessors: [processor], + }); provider .getTracer('default') @@ -1171,9 +1289,9 @@ describe('Span', () => { shutdown: () => Promise.resolve(), }; - const provider = new BasicTracerProvider(); - - provider.addSpanProcessor(processor); + const provider = new BasicTracerProvider({ + spanProcessors: [processor], + }); provider.getTracer('default').startSpan('test').end(); assert.ok(ended); @@ -1189,9 +1307,9 @@ describe('Span', () => { shutdown: () => Promise.resolve(), }; - const provider = new BasicTracerProvider(); - - provider.addSpanProcessor(processor); + const provider = new BasicTracerProvider({ + spanProcessors: [processor], + }); const s = provider.getTracer('default').startSpan('test') as Span; assert.ok(s.attributes.attr); @@ -1211,13 +1329,16 @@ describe('Span', () => { invalidExceptions.forEach(key => { describe(`when exception is (${JSON.stringify(key)})`, () => { it('should NOT record an exception', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.events.length, 0); span.recordException(key); assert.strictEqual(span.events.length, 0); @@ -1231,13 +1352,16 @@ describe('Span', () => { error = 'boom'; }); it('should record an exception', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.events.length, 0); span.recordException(error); @@ -1264,13 +1388,16 @@ describe('Span', () => { describe(`when exception type is an object with ${errorObj.description}`, () => { const error: Exception = errorObj.obj; it('should record an exception', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.events.length, 0); span.recordException(error); @@ -1294,13 +1421,16 @@ describe('Span', () => { describe('when time is provided', () => { it('should record an exception with provided time', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); // @ts-expect-error writing readonly property. performance time origin is mocked to return ms value of [1,1] span['_performanceOffset'] = 0; assert.strictEqual(span.events.length, 0); @@ -1312,13 +1442,16 @@ describe('Span', () => { describe('when exception code is numeric', () => { it('should record an exception with string value', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); assert.strictEqual(span.events.length, 0); span.recordException({ code: 12 }); const event = span.events[0]; @@ -1330,18 +1463,17 @@ describe('Span', () => { describe('when attributes are specified', () => { it('should store specified attributes', () => { - const span = new Span( - tracer, - ROOT_CONTEXT, - name, + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT, - undefined, - undefined, - undefined, - undefined, - { foo: 'bar' } - ); + name, + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + attributes: { foo: 'bar' }, + }); assert.deepStrictEqual(span.attributes, { foo: 'bar' }); }); }); diff --git a/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts index 70058ac79e..41e374e15c 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { - SpanAttributes, + Attributes, Context, context, createContextKey, @@ -65,7 +65,7 @@ describe('Tracer', () => { _traceId: string, _spanName: string, _spanKind: SpanKind, - attributes: SpanAttributes, + attributes: Attributes, links: Link[] ) { // The attributes object should be valid. @@ -82,7 +82,7 @@ describe('Tracer', () => { testAttribute: 'foobar', // invalid attributes should be sanitized. ...invalidAttributes, - } as unknown as SpanAttributes, + } as unknown as Attributes, traceState: this.traceState, }; } @@ -114,7 +114,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); assert.ok(tracer instanceof Tracer); }); @@ -123,7 +124,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); assert.strictEqual( tracer['_sampler'].toString(), @@ -135,7 +137,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new AlwaysOffSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('span1'); assert.ok(!span.isRecording()); @@ -146,7 +149,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new AlwaysOnSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('span2'); assert.ok(span.isRecording()); @@ -157,7 +161,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('span3'); assert.strictEqual((span as Span).attributes.testAttribute, 'foobar'); @@ -169,7 +174,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler(traceState) }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('stateSpan'); assert.strictEqual(span.spanContext().traceState, traceState); @@ -179,7 +185,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const lib: InstrumentationLibrary = tracer.instrumentationLibrary; @@ -195,7 +202,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('span3', undefined, context); @@ -218,7 +226,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan( 'aSpan', @@ -239,7 +248,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan( 'aSpan', @@ -259,12 +269,18 @@ describe('Tracer', () => { const sp: SpanProcessor = new DummySpanProcessor(); const onStartSpy = sinon.spy(sp, 'onStart'); - const tp = new BasicTracerProvider(); - tp.addSpanProcessor(sp); + const tp = new BasicTracerProvider({ + spanProcessors: [sp], + }); const sampler: Sampler = new AlwaysOnSampler(); const shouldSampleSpy = sinon.spy(sampler, 'shouldSample'); - const tracer = new Tracer({ name: 'default' }, { sampler }, tp); + const tracer = new Tracer( + { name: 'default' }, + { sampler }, + tp['_resource'], + tp['_activeSpanProcessor'] + ); const span = tracer.startSpan('a', {}, context) as Span; assert.strictEqual(span.parentSpanId, parent.spanId); sinon.assert.calledOnceWithExactly( @@ -289,12 +305,18 @@ describe('Tracer', () => { const sp: SpanProcessor = new DummySpanProcessor(); const onStartSpy = sinon.spy(sp, 'onStart'); - const tp = new BasicTracerProvider(); - tp.addSpanProcessor(sp); + const tp = new BasicTracerProvider({ + spanProcessors: [sp], + }); const sampler: Sampler = new AlwaysOnSampler(); const shouldSampleSpy = sinon.spy(sampler, 'shouldSample'); - const tracer = new Tracer({ name: 'default' }, { sampler }, tp); + const tracer = new Tracer( + { name: 'default' }, + { sampler }, + tp['_resource'], + tp['_activeSpanProcessor'] + ); const span = tracer.startSpan('a', { root: true }, context) as Span; assert.strictEqual(span.parentSpanId, undefined); sinon.assert.calledOnce(shouldSampleSpy); @@ -311,7 +333,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('my-span'); const context = span.spanContext(); @@ -325,7 +348,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('my-span'); const context = span.spanContext(); @@ -339,7 +363,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, {}, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const span = tracer.startSpan('my-span'); const context = span.spanContext(); @@ -351,7 +376,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const spy = sinon.spy(tracer, 'startSpan'); @@ -374,7 +400,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const spy = sinon.spy(tracer, 'startSpan'); @@ -401,7 +428,8 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const ctxKey = createContextKey('foo'); @@ -436,13 +464,14 @@ describe('Tracer', () => { const tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new TestSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); const attributes = { ...validAttributes, ...invalidAttributes, - } as unknown as SpanAttributes; + } as unknown as Attributes; const links = [ { context: { diff --git a/packages/opentelemetry-sdk-trace-base/test/common/export/BatchSpanProcessorBase.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/export/BatchSpanProcessorBase.test.ts index 2c36114aaa..80cb7e4c42 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/export/BatchSpanProcessorBase.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/export/BatchSpanProcessorBase.test.ts @@ -32,12 +32,12 @@ import { Span, SpanExporter, } from '../../../src'; -import { context } from '@opentelemetry/api'; +import { Attributes, context } from '@opentelemetry/api'; import { TestRecordOnlySampler } from './TestRecordOnlySampler'; import { TestTracingSpanExporter } from './TestTracingSpanExporter'; import { TestStackContextManager } from './TestStackContextManager'; import { BatchSpanProcessorBase } from '../../../src/export/BatchSpanProcessorBase'; -import { Resource, ResourceAttributes } from '@opentelemetry/resources'; +import { Resource } from '@opentelemetry/resources'; function createSampledSpan(spanName: string): Span { const tracer = new BasicTracerProvider({ @@ -442,7 +442,7 @@ describe('BatchSpanProcessorBase', () => { const tracer = new BasicTracerProvider({ resource: new Resource( {}, - new Promise(resolve => { + new Promise(resolve => { setTimeout(() => resolve({ async: 'fromasync' }), 1); }) ), diff --git a/packages/opentelemetry-sdk-trace-base/test/common/export/ConsoleSpanExporter.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/export/ConsoleSpanExporter.test.ts index c73f318fff..1e41f12b77 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/export/ConsoleSpanExporter.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/export/ConsoleSpanExporter.test.ts @@ -43,18 +43,15 @@ describe('ConsoleSpanExporter', () => { describe('.export()', () => { it('should export information about span', () => { assert.doesNotThrow(() => { + consoleExporter = new ConsoleSpanExporter(); const basicTracerProvider = new BasicTracerProvider({ sampler: new AlwaysOnSampler(), + spanProcessors: [new SimpleSpanProcessor(consoleExporter)], }); - consoleExporter = new ConsoleSpanExporter(); const spyConsole = sinon.spy(console, 'dir'); const spyExport = sinon.spy(consoleExporter, 'export'); - basicTracerProvider.addSpanProcessor( - new SimpleSpanProcessor(consoleExporter) - ); - const instrumentationScopeName = '@opentelemetry/sdk-trace-base/test'; const instrumentationScopeVersion = '1.2.3'; const tracer = basicTracerProvider.getTracer( diff --git a/packages/opentelemetry-sdk-trace-base/test/common/export/InMemorySpanExporter.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/export/InMemorySpanExporter.test.ts index 91c4bffaf6..e4a45731b7 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/export/InMemorySpanExporter.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/export/InMemorySpanExporter.test.ts @@ -29,8 +29,9 @@ describe('InMemorySpanExporter', () => { beforeEach(() => { memoryExporter = new InMemorySpanExporter(); - provider = new BasicTracerProvider(); - provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + provider = new BasicTracerProvider({ + spanProcessors: [new SimpleSpanProcessor(memoryExporter)], + }); }); it('should get finished spans', () => { diff --git a/packages/opentelemetry-sdk-trace-base/test/common/export/SimpleSpanProcessor.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/export/SimpleSpanProcessor.test.ts index f1e1bf16b3..745cd2c82c 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/export/SimpleSpanProcessor.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/export/SimpleSpanProcessor.test.ts @@ -32,11 +32,12 @@ import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor, - Span, } from '../../../src'; +import { SpanImpl } from '../../../src/Span'; import { TestStackContextManager } from './TestStackContextManager'; import { TestTracingSpanExporter } from './TestTracingSpanExporter'; -import { Resource, ResourceAttributes } from '@opentelemetry/resources'; +import { Attributes } from '@opentelemetry/api'; +import { Resource } from '@opentelemetry/resources'; import { TestExporterWithDelay } from './TestExporterWithDelay'; describe('SimpleSpanProcessor', () => { @@ -63,13 +64,17 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span( - provider.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + const tracer = provider.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); assert.strictEqual(exporter.getFinishedSpans().length, 0); @@ -87,13 +92,17 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.NONE, }; - const span = new Span( - provider.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + const tracer = provider.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); assert.strictEqual(exporter.getFinishedSpans().length, 0); @@ -112,13 +121,17 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span( - provider.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + const tracer = provider.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); sinon.stub(exporter, 'export').callsFake((_, callback) => { @@ -164,7 +177,7 @@ describe('SimpleSpanProcessor', () => { const providerWithAsyncResource = new BasicTracerProvider({ resource: new Resource( {}, - new Promise(resolve => { + new Promise(resolve => { setTimeout(() => resolve({ async: 'fromasync' }), 1); }) ), @@ -174,13 +187,18 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span( - providerWithAsyncResource.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + + const tracer = providerWithAsyncResource.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); assert.strictEqual(exporter.getFinishedSpans().length, 0); @@ -205,7 +223,7 @@ describe('SimpleSpanProcessor', () => { const providerWithAsyncResource = new BasicTracerProvider({ resource: new Resource( {}, - new Promise(resolve => { + new Promise(resolve => { setTimeout(() => resolve({ async: 'fromasync' }), 1); }) ), @@ -215,13 +233,17 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span( - providerWithAsyncResource.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + const tracer = providerWithAsyncResource.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); processor.onEnd(span); @@ -274,13 +296,17 @@ describe('SimpleSpanProcessor', () => { spanId: '5e0c63257de34c92', traceFlags: TraceFlags.SAMPLED, }; - const span = new Span( - provider.getTracer('default'), - ROOT_CONTEXT, - 'span-name', + const tracer = provider.getTracer('default'); + const span = new SpanImpl({ + scope: tracer.instrumentationLibrary, + resource: tracer['_resource'], + context: ROOT_CONTEXT, spanContext, - SpanKind.CLIENT - ); + name: 'span-name', + kind: SpanKind.CLIENT, + spanLimits: tracer.getSpanLimits(), + spanProcessor: tracer['_spanProcessor'], + }); processor.onStart(span, ROOT_CONTEXT); processor.onEnd(span); @@ -303,7 +329,7 @@ describe('SimpleSpanProcessor', () => { // spanId: '5e0c63257de34c92', // traceFlags: TraceFlags.SAMPLED, // }; - // const span = new Span( + // const span = new SpanImpl( // providerWithAsyncResource.getTracer('default'), // ROOT_CONTEXT, // 'span-name', diff --git a/packages/opentelemetry-sdk-trace-base/test/common/export/TestTracingSpanExporter.ts b/packages/opentelemetry-sdk-trace-base/test/common/export/TestTracingSpanExporter.ts index 89eae8d8b5..3153b1f48c 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/export/TestTracingSpanExporter.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/export/TestTracingSpanExporter.ts @@ -35,8 +35,6 @@ export class TestTracingSpanExporter extends InMemorySpanExporter { constructor() { super(); - const tracerProvider = new BasicTracerProvider(); - const spanProcessor: SpanProcessor = { forceFlush: () => { return Promise.resolve(); @@ -50,12 +48,15 @@ export class TestTracingSpanExporter extends InMemorySpanExporter { }, }; - tracerProvider.addSpanProcessor(spanProcessor); + const tracerProvider = new BasicTracerProvider({ + spanProcessors: [spanProcessor], + }); this._tracer = new Tracer( { name: 'default', version: '0.0.1' }, { sampler: new AlwaysOnSampler() }, - tracerProvider + tracerProvider['_resource'], + tracerProvider['_activeSpanProcessor'] ); } diff --git a/packages/opentelemetry-sdk-trace-node/package.json b/packages/opentelemetry-sdk-trace-node/package.json index e4fff7efc2..97cb45d3a6 100644 --- a/packages/opentelemetry-sdk-trace-node/package.json +++ b/packages/opentelemetry-sdk-trace-node/package.json @@ -31,7 +31,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts b/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts index 9d552162f6..abb25f4db9 100644 --- a/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-node/src/NodeTracerProvider.ts @@ -13,17 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - AsyncHooksContextManager, - AsyncLocalStorageContextManager, -} from '@opentelemetry/context-async-hooks'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { B3Propagator, B3InjectEncoding } from '@opentelemetry/propagator-b3'; import { BasicTracerProvider, PROPAGATOR_FACTORY, SDKRegistrationConfig, } from '@opentelemetry/sdk-trace-base'; -import * as semver from 'semver'; import { NodeTracerConfig } from './config'; import { JaegerPropagator } from '@opentelemetry/propagator-jaeger'; @@ -58,10 +54,7 @@ export class NodeTracerProvider extends BasicTracerProvider { override register(config: SDKRegistrationConfig = {}): void { if (config.contextManager === undefined) { - const ContextManager = semver.gte(process.version, '14.8.0') - ? AsyncLocalStorageContextManager - : AsyncHooksContextManager; - config.contextManager = new ContextManager(); + config.contextManager = new AsyncLocalStorageContextManager(); config.contextManager.enable(); } diff --git a/packages/opentelemetry-sdk-trace-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-sdk-trace-node/test/NodeTracerProvider.test.ts index a656f6f69b..f9017f1534 100644 --- a/packages/opentelemetry-sdk-trace-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-node/test/NodeTracerProvider.test.ts @@ -108,7 +108,6 @@ describe('NodeTracerProvider', () => { sampler: new AlwaysOnSampler(), }); const span = provider.getTracer('default').startSpan('my-span'); - assert.ok(span instanceof Span); assert.strictEqual(span.spanContext().traceFlags, TraceFlags.SAMPLED); assert.strictEqual(span.isRecording(), true); }); @@ -127,7 +126,6 @@ describe('NodeTracerProvider', () => { traceFlags: TraceFlags.NONE, }) ); - assert.ok(sampledParent instanceof Span); assert.strictEqual( sampledParent.spanContext().traceFlags, TraceFlags.SAMPLED @@ -141,7 +139,6 @@ describe('NodeTracerProvider', () => { {}, trace.setSpan(ROOT_CONTEXT, sampledParent) ); - assert.ok(span instanceof Span); assert.strictEqual(span.spanContext().traceFlags, TraceFlags.SAMPLED); assert.strictEqual(span.isRecording(), true); }); @@ -305,11 +302,23 @@ describe('NodeTracerProvider', () => { const provider = new CustomTracerProvider({}); provider.register(); - const processor = provider.getActiveSpanProcessor(); - assert(processor instanceof BatchSpanProcessor); - // @ts-expect-error access configured to verify its the correct one - const exporter = processor._exporter; - assert(exporter instanceof DummyExporter); + + assert.ok( + provider['_activeSpanProcessor'].constructor.name === + 'MultiSpanProcessor' + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0] instanceof + BatchSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof DummyExporter + ); assert.strictEqual(propagation['_getGlobalPropagator'](), propagator); }); @@ -350,11 +359,23 @@ describe('NodeTracerProvider', () => { const provider = new CustomTracerProvider({}); provider.register(); - const processor = provider.getActiveSpanProcessor(); - assert(processor instanceof BatchSpanProcessor); - // @ts-expect-error access configured to verify its the correct one - const exporter = processor._exporter; - assert(exporter instanceof DummyExporter); + + assert.ok( + provider['_activeSpanProcessor'].constructor.name === + 'MultiSpanProcessor' + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'].length === 1 + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0] instanceof + BatchSpanProcessor + ); + assert.ok( + provider['_activeSpanProcessor']['_spanProcessors'][0][ + '_exporter' + ] instanceof DummyExporter + ); assert.strictEqual(propagation['_getGlobalPropagator'](), propagator); }); diff --git a/packages/opentelemetry-sdk-trace-node/test/registration.test.ts b/packages/opentelemetry-sdk-trace-node/test/registration.test.ts index 5c35f8de97..2b1466b179 100644 --- a/packages/opentelemetry-sdk-trace-node/test/registration.test.ts +++ b/packages/opentelemetry-sdk-trace-node/test/registration.test.ts @@ -23,13 +23,9 @@ import { trace, ProxyTracerProvider, } from '@opentelemetry/api'; -import { - AsyncHooksContextManager, - AsyncLocalStorageContextManager, -} from '@opentelemetry/context-async-hooks'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { CompositePropagator } from '@opentelemetry/core'; import { NodeTracerProvider } from '../src'; -import * as semver from 'semver'; const assertInstanceOf = (actual: object, ExpectedInstance: Function) => { assert.ok( @@ -38,10 +34,6 @@ const assertInstanceOf = (actual: object, ExpectedInstance: Function) => { ); }; -const DefaultContextManager = semver.gte(process.version, '14.8.0') - ? AsyncLocalStorageContextManager - : AsyncHooksContextManager; - describe('API registration', () => { beforeEach(() => { context.disable(); @@ -53,7 +45,10 @@ describe('API registration', () => { const tracerProvider = new NodeTracerProvider(); tracerProvider.register(); - assertInstanceOf(context['_getContextManager'](), DefaultContextManager); + assertInstanceOf( + context['_getContextManager'](), + AsyncLocalStorageContextManager + ); assertInstanceOf( propagation['_getGlobalPropagator'](), CompositePropagator @@ -113,7 +108,10 @@ describe('API registration', () => { assert.strictEqual(propagation['_getGlobalPropagator'](), propagator); - assertInstanceOf(context['_getContextManager'](), DefaultContextManager); + assertInstanceOf( + context['_getContextManager'](), + AsyncLocalStorageContextManager + ); const apiTracerProvider = trace.getTracerProvider() as ProxyTracerProvider; assert.ok(apiTracerProvider.getDelegate() === tracerProvider); diff --git a/packages/opentelemetry-sdk-trace-web/package.json b/packages/opentelemetry-sdk-trace-web/package.json index 414b1c2cd4..2f3808fa4f 100644 --- a/packages/opentelemetry-sdk-trace-web/package.json +++ b/packages/opentelemetry-sdk-trace-web/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", diff --git a/packages/opentelemetry-shim-opentracing/package.json b/packages/opentelemetry-shim-opentracing/package.json index 0b40498597..cd20e052f4 100644 --- a/packages/opentelemetry-shim-opentracing/package.json +++ b/packages/opentelemetry-shim-opentracing/package.json @@ -28,7 +28,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/src/**/*.js", diff --git a/packages/opentelemetry-shim-opentracing/src/shim.ts b/packages/opentelemetry-shim-opentracing/src/shim.ts index 8c4b209c12..3113609f30 100644 --- a/packages/opentelemetry-shim-opentracing/src/shim.ts +++ b/packages/opentelemetry-shim-opentracing/src/shim.ts @@ -16,8 +16,8 @@ import * as api from '@opentelemetry/api'; import { - SpanAttributes, - SpanAttributeValue, + Attributes, + AttributeValue, SpanStatusCode, TextMapPropagator, } from '@opentelemetry/api'; @@ -291,7 +291,7 @@ export class SpanShim extends opentracing.Span { * @param eventName name of the event. * @param payload an arbitrary object to be attached to the event. */ - override logEvent(eventName: string, payload?: SpanAttributes): void { + override logEvent(eventName: string, payload?: Attributes): void { this._logInternal(eventName, payload); } @@ -301,7 +301,7 @@ export class SpanShim extends opentracing.Span { * @param keyValuePairs a set of key-value pairs to be used as event attributes * @param timestamp optional timestamp for the event */ - override log(keyValuePairs: SpanAttributes, timestamp?: number): this { + override log(keyValuePairs: Attributes, timestamp?: number): this { const entries = Object.entries(keyValuePairs); const eventEntry = entries.find(([key, _]) => key === 'event'); const eventName = eventEntry?.[1] || 'log'; @@ -313,7 +313,7 @@ export class SpanShim extends opentracing.Span { private _logInternal( eventName: string, - attributes: SpanAttributes | undefined, + attributes: Attributes | undefined, timestamp?: number ): void { if (attributes && eventName === 'error') { @@ -325,7 +325,7 @@ export class SpanShim extends opentracing.Span { return; } - const mappedAttributes: api.SpanAttributes = {}; + const mappedAttributes: api.Attributes = {}; for (const [k, v] of entries) { switch (k) { case 'error.kind': { @@ -356,7 +356,7 @@ export class SpanShim extends opentracing.Span { * Adds a set of tags to the span. * @param keyValueMap set of KV pairs representing tags */ - override addTags(keyValueMap: SpanAttributes): this { + override addTags(keyValueMap: Attributes): this { for (const [key, value] of Object.entries(keyValueMap)) { if (this._setErrorAsSpanStatusCode(key, value)) { continue; @@ -374,7 +374,7 @@ export class SpanShim extends opentracing.Span { * @param key key for the tag * @param value value for the tag */ - override setTag(key: string, value: SpanAttributeValue): this { + override setTag(key: string, value: AttributeValue): this { if (this._setErrorAsSpanStatusCode(key, value)) { return this; } @@ -402,7 +402,7 @@ export class SpanShim extends opentracing.Span { private _setErrorAsSpanStatusCode( key: string, - value: SpanAttributeValue | undefined + value: AttributeValue | undefined ): boolean { if (key === opentracing.Tags.ERROR) { const statusCode = SpanShim._mapErrorTag(value); @@ -413,7 +413,7 @@ export class SpanShim extends opentracing.Span { } private static _mapErrorTag( - value: SpanAttributeValue | undefined + value: AttributeValue | undefined ): SpanStatusCode { switch (value) { case true: diff --git a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts index fb65e63acb..11952d31e0 100644 --- a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts +++ b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts @@ -260,7 +260,7 @@ describe('OpenTracing Shim', () => { const otSpan = (span as SpanShim).getSpan() as Span; - const adjustment = otSpan['_performanceOffset']; + const adjustment = (otSpan as any)['_performanceOffset']; assert.strictEqual(otSpan.links.length, 1); assert.deepStrictEqual( @@ -496,7 +496,7 @@ describe('OpenTracing Shim', () => { it('sets explicit end timestamp', () => { const now = performance.now(); span.finish(now); - const adjustment = otSpan['_performanceOffset']; + const adjustment = (otSpan as any)['_performanceOffset']; assert.deepStrictEqual( hrTimeToMilliseconds(otSpan.endTime), now + adjustment + performance.timeOrigin diff --git a/packages/sdk-metrics/package.json b/packages/sdk-metrics/package.json index e68a482f98..b21ee2073e 100644 --- a/packages/sdk-metrics/package.json +++ b/packages/sdk-metrics/package.json @@ -34,7 +34,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js", @@ -79,7 +79,7 @@ "webpack-merge": "5.10.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "@opentelemetry/api": ">=1.9.0 <1.10.0" }, "dependencies": { "@opentelemetry/core": "1.30.0", diff --git a/packages/sdk-metrics/src/InstrumentDescriptor.ts b/packages/sdk-metrics/src/InstrumentDescriptor.ts index ef09dda8bb..39c9cffd92 100644 --- a/packages/sdk-metrics/src/InstrumentDescriptor.ts +++ b/packages/sdk-metrics/src/InstrumentDescriptor.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { MetricOptions, ValueType, diag } from '@opentelemetry/api'; +import { + MetricAdvice, + MetricOptions, + ValueType, + diag, +} from '@opentelemetry/api'; import { View } from './view/View'; import { equalsCaseInsensitive } from './utils'; @@ -44,18 +49,11 @@ export interface InstrumentDescriptor { readonly type: InstrumentType; readonly valueType: ValueType; /** - * @experimental + * See {@link MetricAdvice} * - * This is intentionally not using the API's type as it's only available from @opentelemetry/api 1.7.0 and up. - * In SDK 2.0 we'll be able to bump the minimum API version and remove this workaround. + * @experimental */ - readonly advice: { - /** - * Hint the explicit bucket boundaries for SDK if the metric has been - * aggregated with a HistogramAggregator. - */ - explicitBucketBoundaries?: number[]; - }; + readonly advice: MetricAdvice; } export function createInstrumentDescriptor( diff --git a/packages/sdk-metrics/src/Instruments.ts b/packages/sdk-metrics/src/Instruments.ts index 7e27a56454..6d60792eff 100644 --- a/packages/sdk-metrics/src/Instruments.ts +++ b/packages/sdk-metrics/src/Instruments.ts @@ -22,6 +22,7 @@ import { ValueType, UpDownCounter, Counter, + Gauge, Histogram, Observable, ObservableCallback, @@ -36,7 +37,6 @@ import { AsyncWritableMetricStorage, WritableMetricStorage, } from './state/WritableMetricStorage'; -import { Gauge } from './types'; export class SyncInstrument { constructor( diff --git a/packages/sdk-metrics/src/Meter.ts b/packages/sdk-metrics/src/Meter.ts index cf0e25e56c..b4edee6868 100644 --- a/packages/sdk-metrics/src/Meter.ts +++ b/packages/sdk-metrics/src/Meter.ts @@ -17,6 +17,7 @@ import { Meter as IMeter, MetricOptions, + Gauge, Histogram, Counter, UpDownCounter, @@ -40,7 +41,6 @@ import { UpDownCounterInstrument, } from './Instruments'; import { MeterSharedState } from './state/MeterSharedState'; -import { Gauge } from './types'; /** * This class implements the {@link IMeter} interface. diff --git a/packages/sdk-metrics/src/MeterProvider.ts b/packages/sdk-metrics/src/MeterProvider.ts index 6d5cd56fd0..fa370da46b 100644 --- a/packages/sdk-metrics/src/MeterProvider.ts +++ b/packages/sdk-metrics/src/MeterProvider.ts @@ -26,7 +26,7 @@ import { MetricReader } from './export/MetricReader'; import { MeterProviderSharedState } from './state/MeterProviderSharedState'; import { MetricCollector } from './state/MetricCollector'; import { ForceFlushOptions, ShutdownOptions } from './types'; -import { View } from './view/View'; +import { View, ViewOptions } from './view/View'; /** * MeterProviderOptions provides an interface for configuring a MeterProvider. @@ -34,7 +34,7 @@ import { View } from './view/View'; export interface MeterProviderOptions { /** Resource associated with metric telemetry */ resource?: IResource; - views?: View[]; + views?: ViewOptions[]; readers?: MetricReader[]; /** * Merge resource with {@link Resource.default()}? @@ -74,14 +74,16 @@ export class MeterProvider implements IMeterProvider { ) ); if (options?.views != null && options.views.length > 0) { - for (const view of options.views) { - this._sharedState.viewRegistry.addView(view); + for (const viewOption of options.views) { + this._sharedState.viewRegistry.addView(new View(viewOption)); } } if (options?.readers != null && options.readers.length > 0) { for (const metricReader of options.readers) { - this.addMetricReader(metricReader); + const collector = new MetricCollector(this._sharedState, metricReader); + metricReader.setMetricProducer(collector); + this._sharedState.metricCollectors.push(collector); } } } @@ -103,24 +105,6 @@ export class MeterProvider implements IMeterProvider { }).meter; } - /** - * Register a {@link MetricReader} to the meter provider. After the - * registration, the MetricReader can start metrics collection. - * - *

NOTE: {@link MetricReader} instances MUST be added before creating any instruments. - * A {@link MetricReader} instance registered later may receive no or incomplete metric data. - * - * @param metricReader the metric reader to be registered. - * - * @deprecated This method will be removed in SDK 2.0. Please use - * {@link MeterProviderOptions.readers} via the {@link MeterProvider} constructor instead - */ - addMetricReader(metricReader: MetricReader) { - const collector = new MetricCollector(this._sharedState, metricReader); - metricReader.setMetricProducer(collector); - this._sharedState.metricCollectors.push(collector); - } - /** * Shut down the MeterProvider and all registered * MetricReaders. diff --git a/packages/sdk-metrics/src/export/AggregationSelector.ts b/packages/sdk-metrics/src/export/AggregationSelector.ts index 7a4eaca935..96d10daca4 100644 --- a/packages/sdk-metrics/src/export/AggregationSelector.ts +++ b/packages/sdk-metrics/src/export/AggregationSelector.ts @@ -15,15 +15,15 @@ */ import { InstrumentType } from '../InstrumentDescriptor'; -import { Aggregation } from '../view/Aggregation'; import { AggregationTemporality } from './AggregationTemporality'; +import { AggregationOption, AggregationType } from '../view/AggregationOption'; /** * Aggregation selector based on metric instrument types. */ export type AggregationSelector = ( instrumentType: InstrumentType -) => Aggregation; +) => AggregationOption; /** * Aggregation temporality selector based on metric instrument types. @@ -33,6 +33,11 @@ export type AggregationTemporalitySelector = ( ) => AggregationTemporality; export const DEFAULT_AGGREGATION_SELECTOR: AggregationSelector = - _instrumentType => Aggregation.Default(); + _instrumentType => { + return { + type: AggregationType.DEFAULT, + }; + }; + export const DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR: AggregationTemporalitySelector = _instrumentType => AggregationTemporality.CUMULATIVE; diff --git a/packages/sdk-metrics/src/export/MetricExporter.ts b/packages/sdk-metrics/src/export/MetricExporter.ts index bf9362bcdd..38ca30ce67 100644 --- a/packages/sdk-metrics/src/export/MetricExporter.ts +++ b/packages/sdk-metrics/src/export/MetricExporter.ts @@ -18,7 +18,7 @@ import { AggregationTemporality } from './AggregationTemporality'; import { ResourceMetrics } from './MetricData'; import { ExportResult } from '@opentelemetry/core'; import { InstrumentType } from '../InstrumentDescriptor'; -import { Aggregation } from '../view/Aggregation'; +import { AggregationOption } from '../view/AggregationOption'; /** * An interface that allows different metric services to export recorded data @@ -55,7 +55,7 @@ export interface PushMetricExporter { * Select the {@link Aggregation} for the given * {@link InstrumentType} for this exporter. */ - selectAggregation?(instrumentType: InstrumentType): Aggregation; + selectAggregation?(instrumentType: InstrumentType): AggregationOption; /** * Returns a promise which resolves when the last exportation is completed. diff --git a/packages/sdk-metrics/src/export/MetricReader.ts b/packages/sdk-metrics/src/export/MetricReader.ts index e87d55884d..abf4c8bd03 100644 --- a/packages/sdk-metrics/src/export/MetricReader.ts +++ b/packages/sdk-metrics/src/export/MetricReader.ts @@ -25,13 +25,13 @@ import { ForceFlushOptions, ShutdownOptions, } from '../types'; -import { Aggregation } from '../view/Aggregation'; import { AggregationSelector, AggregationTemporalitySelector, DEFAULT_AGGREGATION_SELECTOR, DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR, } from './AggregationSelector'; +import { AggregationOption } from '../view/AggregationOption'; import { CardinalitySelector } from './CardinalitySelector'; export interface MetricReaderOptions { @@ -107,10 +107,10 @@ export abstract class MetricReader { } /** - * Select the {@link Aggregation} for the given {@link InstrumentType} for this + * Select the {@link AggregationOption} for the given {@link InstrumentType} for this * reader. */ - selectAggregation(instrumentType: InstrumentType): Aggregation { + selectAggregation(instrumentType: InstrumentType): AggregationOption { return this._aggregationSelector(instrumentType); } diff --git a/packages/sdk-metrics/src/index.ts b/packages/sdk-metrics/src/index.ts index 414766c099..4f359214bc 100644 --- a/packages/sdk-metrics/src/index.ts +++ b/packages/sdk-metrics/src/index.ts @@ -67,17 +67,14 @@ export type InstrumentDescriptor = MetricDescriptor; export { MeterProvider, MeterProviderOptions } from './MeterProvider'; +export { AggregationOption, AggregationType } from './view/AggregationOption'; + +export { ViewOptions } from './view/View'; + export { - DefaultAggregation, - ExplicitBucketHistogramAggregation, - ExponentialHistogramAggregation, - DropAggregation, - HistogramAggregation, - LastValueAggregation, - SumAggregation, - Aggregation, -} from './view/Aggregation'; - -export { View, ViewOptions } from './view/View'; + IAttributesProcessor, + createAllowListAttributesProcessor, + createDenyListAttributesProcessor, +} from './view/AttributesProcessor'; export { TimeoutError } from './utils'; diff --git a/packages/sdk-metrics/src/state/AsyncMetricStorage.ts b/packages/sdk-metrics/src/state/AsyncMetricStorage.ts index be2cf7f25a..4f8651915a 100644 --- a/packages/sdk-metrics/src/state/AsyncMetricStorage.ts +++ b/packages/sdk-metrics/src/state/AsyncMetricStorage.ts @@ -17,7 +17,6 @@ import { HrTime } from '@opentelemetry/api'; import { Accumulation, Aggregator } from '../aggregator/types'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; -import { AttributesProcessor } from '../view/AttributesProcessor'; import { MetricStorage } from './MetricStorage'; import { MetricData } from '../export/MetricData'; import { DeltaMetricProcessor } from './DeltaMetricProcessor'; @@ -26,6 +25,7 @@ import { Maybe } from '../utils'; import { MetricCollectorHandle } from './MetricCollector'; import { AttributeHashMap } from './HashMap'; import { AsyncWritableMetricStorage } from './WritableMetricStorage'; +import { IAttributesProcessor } from '../view/AttributesProcessor'; /** * Internal interface. @@ -42,7 +42,7 @@ export class AsyncMetricStorage> constructor( _instrumentDescriptor: InstrumentDescriptor, aggregator: Aggregator, - private _attributesProcessor: AttributesProcessor, + private _attributesProcessor: IAttributesProcessor, collectorHandles: MetricCollectorHandle[], private _aggregationCardinalityLimit?: number ) { diff --git a/packages/sdk-metrics/src/state/MeterProviderSharedState.ts b/packages/sdk-metrics/src/state/MeterProviderSharedState.ts index fa7903b20e..2e8bc57796 100644 --- a/packages/sdk-metrics/src/state/MeterProviderSharedState.ts +++ b/packages/sdk-metrics/src/state/MeterProviderSharedState.ts @@ -16,11 +16,13 @@ import { InstrumentationScope } from '@opentelemetry/core'; import { IResource } from '@opentelemetry/resources'; -import { Aggregation, InstrumentType } from '..'; +import { InstrumentType } from '..'; import { instrumentationScopeId } from '../utils'; import { ViewRegistry } from '../view/ViewRegistry'; import { MeterSharedState } from './MeterSharedState'; import { MetricCollector, MetricCollectorHandle } from './MetricCollector'; +import { toAggregation } from '../view/AggregationOption'; +import { Aggregation } from '../view/Aggregation'; /** * An internal record for shared meter provider states. @@ -47,7 +49,10 @@ export class MeterProviderSharedState { selectAggregations(instrumentType: InstrumentType) { const result: [MetricCollectorHandle, Aggregation][] = []; for (const collector of this.metricCollectors) { - result.push([collector, collector.selectAggregation(instrumentType)]); + result.push([ + collector, + toAggregation(collector.selectAggregation(instrumentType)), + ]); } return result; } diff --git a/packages/sdk-metrics/src/state/MeterSharedState.ts b/packages/sdk-metrics/src/state/MeterSharedState.ts index 028a43634e..4ff18fec7e 100644 --- a/packages/sdk-metrics/src/state/MeterSharedState.ts +++ b/packages/sdk-metrics/src/state/MeterSharedState.ts @@ -32,7 +32,10 @@ import { MultiMetricStorage } from './MultiWritableMetricStorage'; import { ObservableRegistry } from './ObservableRegistry'; import { SyncMetricStorage } from './SyncMetricStorage'; import { Accumulation, Aggregator } from '../aggregator/types'; -import { AttributesProcessor } from '../view/AttributesProcessor'; +import { + createNoopAttributesProcessor, + IAttributesProcessor, +} from '../view/AttributesProcessor'; import { MetricStorage } from './MetricStorage'; /** @@ -171,7 +174,7 @@ export class MeterSharedState { const storage = new MetricStorageType( descriptor, aggregator, - AttributesProcessor.Noop(), + createNoopAttributesProcessor(), [collector], cardinalityLimit ) as R; @@ -195,7 +198,7 @@ interface MetricStorageConstructor { new ( instrumentDescriptor: InstrumentDescriptor, aggregator: Aggregator>, - attributesProcessor: AttributesProcessor, + attributesProcessor: IAttributesProcessor, collectors: MetricCollectorHandle[], aggregationCardinalityLimit?: number ): MetricStorage; diff --git a/packages/sdk-metrics/src/state/SyncMetricStorage.ts b/packages/sdk-metrics/src/state/SyncMetricStorage.ts index 9d01e26386..10786c3dec 100644 --- a/packages/sdk-metrics/src/state/SyncMetricStorage.ts +++ b/packages/sdk-metrics/src/state/SyncMetricStorage.ts @@ -18,7 +18,7 @@ import { Context, HrTime, Attributes } from '@opentelemetry/api'; import { WritableMetricStorage } from './WritableMetricStorage'; import { Accumulation, Aggregator } from '../aggregator/types'; import { InstrumentDescriptor } from '../InstrumentDescriptor'; -import { AttributesProcessor } from '../view/AttributesProcessor'; +import { IAttributesProcessor } from '../view/AttributesProcessor'; import { MetricStorage } from './MetricStorage'; import { MetricData } from '../export/MetricData'; import { DeltaMetricProcessor } from './DeltaMetricProcessor'; @@ -41,7 +41,7 @@ export class SyncMetricStorage> constructor( instrumentDescriptor: InstrumentDescriptor, aggregator: Aggregator, - private _attributesProcessor: AttributesProcessor, + private _attributesProcessor: IAttributesProcessor, collectorHandles: MetricCollectorHandle[], private _aggregationCardinalityLimit?: number ) { diff --git a/packages/sdk-metrics/src/types.ts b/packages/sdk-metrics/src/types.ts index 2ad1cefcfd..89af1eea33 100644 --- a/packages/sdk-metrics/src/types.ts +++ b/packages/sdk-metrics/src/types.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Context, Attributes } from '@opentelemetry/api'; export type CommonReaderOptions = { timeoutMillis?: number; @@ -24,14 +23,3 @@ export type CollectionOptions = CommonReaderOptions; export type ShutdownOptions = CommonReaderOptions; export type ForceFlushOptions = CommonReaderOptions; - -/** - * This is intentionally not using the API's type as it's only available from @opentelemetry/api 1.9.0 and up. - * In SDK 2.0 we'll be able to bump the minimum API version and remove this workaround. - */ -export interface Gauge { - /** - * Records a measurement. Value of the measurement must not be negative. - */ - record(value: number, attributes?: AttributesTypes, context?: Context): void; -} diff --git a/packages/sdk-metrics/src/view/Aggregation.ts b/packages/sdk-metrics/src/view/Aggregation.ts index f34bd1231a..f3894489b1 100644 --- a/packages/sdk-metrics/src/view/Aggregation.ts +++ b/packages/sdk-metrics/src/view/Aggregation.ts @@ -32,40 +32,16 @@ import { Maybe } from '../utils'; * * Aggregation provides a set of built-in aggregations via static methods. */ -export abstract class Aggregation { - abstract createAggregator( +export interface Aggregation { + createAggregator( instrument: InstrumentDescriptor ): Aggregator>; - - static Drop(): Aggregation { - return DROP_AGGREGATION; - } - - static Sum(): Aggregation { - return SUM_AGGREGATION; - } - - static LastValue(): Aggregation { - return LAST_VALUE_AGGREGATION; - } - - static Histogram(): Aggregation { - return HISTOGRAM_AGGREGATION; - } - - static ExponentialHistogram(): Aggregation { - return EXPONENTIAL_HISTOGRAM_AGGREGATION; - } - - static Default(): Aggregation { - return DEFAULT_AGGREGATION; - } } /** * The default drop aggregation. */ -export class DropAggregation extends Aggregation { +export class DropAggregation implements Aggregation { private static DEFAULT_INSTANCE = new DropAggregator(); createAggregator(_instrument: InstrumentDescriptor) { return DropAggregation.DEFAULT_INSTANCE; @@ -75,7 +51,7 @@ export class DropAggregation extends Aggregation { /** * The default sum aggregation. */ -export class SumAggregation extends Aggregation { +export class SumAggregation implements Aggregation { private static MONOTONIC_INSTANCE = new SumAggregator(true); private static NON_MONOTONIC_INSTANCE = new SumAggregator(false); createAggregator(instrument: InstrumentDescriptor) { @@ -95,7 +71,7 @@ export class SumAggregation extends Aggregation { /** * The default last value aggregation. */ -export class LastValueAggregation extends Aggregation { +export class LastValueAggregation implements Aggregation { private static DEFAULT_INSTANCE = new LastValueAggregator(); createAggregator(_instrument: InstrumentDescriptor) { return LastValueAggregation.DEFAULT_INSTANCE; @@ -104,8 +80,9 @@ export class LastValueAggregation extends Aggregation { /** * The default histogram aggregation. + */ -export class HistogramAggregation extends Aggregation { +export class HistogramAggregation implements Aggregation { private static DEFAULT_INSTANCE = new HistogramAggregator( [0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000], true @@ -118,7 +95,7 @@ export class HistogramAggregation extends Aggregation { /** * The explicit bucket histogram aggregation. */ -export class ExplicitBucketHistogramAggregation extends Aggregation { +export class ExplicitBucketHistogramAggregation implements Aggregation { private _boundaries: number[]; /** @@ -129,7 +106,6 @@ export class ExplicitBucketHistogramAggregation extends Aggregation { boundaries: number[], private readonly _recordMinMax = true ) { - super(); if (boundaries == null) { throw new Error( 'ExplicitBucketHistogramAggregation should be created with explicit boundaries, if a single bucket histogram is required, please pass an empty array' @@ -154,13 +130,11 @@ export class ExplicitBucketHistogramAggregation extends Aggregation { } } -export class ExponentialHistogramAggregation extends Aggregation { +export class ExponentialHistogramAggregation implements Aggregation { constructor( private readonly _maxSize: number = 160, private readonly _recordMinMax = true - ) { - super(); - } + ) {} createAggregator(_instrument: InstrumentDescriptor) { return new ExponentialHistogramAggregator( this._maxSize, @@ -172,7 +146,7 @@ export class ExponentialHistogramAggregation extends Aggregation { /** * The default aggregation. */ -export class DefaultAggregation extends Aggregation { +export class DefaultAggregation implements Aggregation { private _resolve(instrument: InstrumentDescriptor): Aggregation { // cast to unknown to disable complaints on the (unreachable) fallback. switch (instrument.type as unknown) { @@ -206,9 +180,10 @@ export class DefaultAggregation extends Aggregation { } } -const DROP_AGGREGATION = new DropAggregation(); -const SUM_AGGREGATION = new SumAggregation(); -const LAST_VALUE_AGGREGATION = new LastValueAggregation(); -const HISTOGRAM_AGGREGATION = new HistogramAggregation(); -const EXPONENTIAL_HISTOGRAM_AGGREGATION = new ExponentialHistogramAggregation(); -const DEFAULT_AGGREGATION = new DefaultAggregation(); +export const DROP_AGGREGATION = new DropAggregation(); +export const SUM_AGGREGATION = new SumAggregation(); +export const LAST_VALUE_AGGREGATION = new LastValueAggregation(); +export const HISTOGRAM_AGGREGATION = new HistogramAggregation(); +export const EXPONENTIAL_HISTOGRAM_AGGREGATION = + new ExponentialHistogramAggregation(); +export const DEFAULT_AGGREGATION = new DefaultAggregation(); diff --git a/packages/sdk-metrics/src/view/AggregationOption.ts b/packages/sdk-metrics/src/view/AggregationOption.ts new file mode 100644 index 0000000000..255f523bcf --- /dev/null +++ b/packages/sdk-metrics/src/view/AggregationOption.ts @@ -0,0 +1,107 @@ +/* + * 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 { + Aggregation, + DEFAULT_AGGREGATION, + DROP_AGGREGATION, + ExplicitBucketHistogramAggregation, + ExponentialHistogramAggregation, + HISTOGRAM_AGGREGATION, + LAST_VALUE_AGGREGATION, + SUM_AGGREGATION, +} from './Aggregation'; + +export enum AggregationType { + DEFAULT = 0, + DROP = 1, + SUM = 2, + LAST_VALUE = 3, + EXPLICIT_BUCKET_HISTOGRAM = 4, + EXPONENTIAL_HISTOGRAM = 5, +} + +export type SumAggregationOption = { + type: AggregationType.SUM; +}; + +export type LastValueAggregationOption = { + type: AggregationType.LAST_VALUE; +}; + +export type DropAggregationOption = { + type: AggregationType.DROP; +}; + +export type DefaultAggregationOption = { + type: AggregationType.DEFAULT; +}; + +export type HistogramAggregationOption = { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM; + options?: { + recordMinMax?: boolean; + boundaries: number[]; + }; +}; + +export type ExponentialHistogramAggregationOption = { + type: AggregationType.EXPONENTIAL_HISTOGRAM; + options?: { + recordMinMax?: boolean; + maxSize?: number; + }; +}; + +export type AggregationOption = + | ExponentialHistogramAggregationOption + | HistogramAggregationOption + | SumAggregationOption + | DropAggregationOption + | DefaultAggregationOption + | LastValueAggregationOption; + +export function toAggregation(option: AggregationOption): Aggregation { + switch (option.type) { + case AggregationType.DEFAULT: + return DEFAULT_AGGREGATION; + case AggregationType.DROP: + return DROP_AGGREGATION; + case AggregationType.SUM: + return SUM_AGGREGATION; + case AggregationType.LAST_VALUE: + return LAST_VALUE_AGGREGATION; + case AggregationType.EXPONENTIAL_HISTOGRAM: { + const expOption = option as ExponentialHistogramAggregationOption; + return new ExponentialHistogramAggregation( + expOption.options?.maxSize, + expOption.options?.recordMinMax + ); + } + case AggregationType.EXPLICIT_BUCKET_HISTOGRAM: { + const expOption = option as HistogramAggregationOption; + if (expOption.options == null) { + return HISTOGRAM_AGGREGATION; + } else { + return new ExplicitBucketHistogramAggregation( + expOption.options?.boundaries, + expOption.options?.recordMinMax + ); + } + } + default: + throw new Error('Unsupported Aggregation'); + } +} diff --git a/packages/sdk-metrics/src/view/AttributesProcessor.ts b/packages/sdk-metrics/src/view/AttributesProcessor.ts index 53f2cddaff..d074385fef 100644 --- a/packages/sdk-metrics/src/view/AttributesProcessor.ts +++ b/packages/sdk-metrics/src/view/AttributesProcessor.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import { Context, MetricAttributes } from '@opentelemetry/api'; +import { Context, Attributes } from '@opentelemetry/api'; /** * The {@link AttributesProcessor} is responsible for customizing which * attribute(s) are to be reported as metrics dimension(s) and adding * additional dimension(s) from the {@link Context}. */ -export abstract class AttributesProcessor { +export interface IAttributesProcessor { /** * Process the metric instrument attributes. * @@ -29,33 +29,31 @@ export abstract class AttributesProcessor { * @param context The active context when the instrument is synchronous. * `undefined` otherwise. */ - abstract process( - incoming: MetricAttributes, - context?: Context - ): MetricAttributes; - - static Noop() { - return NOOP; - } + process: (incoming: Attributes, context?: Context) => Attributes; } -export class NoopAttributesProcessor extends AttributesProcessor { - process(incoming: MetricAttributes, _context?: Context) { +class NoopAttributesProcessor implements IAttributesProcessor { + process(incoming: Attributes, _context?: Context) { return incoming; } } -/** - * {@link AttributesProcessor} that filters by allowed attribute names and drops any names that are not in the - * allow list. - */ -export class FilteringAttributesProcessor extends AttributesProcessor { - constructor(private _allowedAttributeNames: string[]) { - super(); +class MultiAttributesProcessor implements IAttributesProcessor { + constructor(private readonly _processors: IAttributesProcessor[]) {} + process(incoming: Attributes, context?: Context): Attributes { + let filteredAttributes = incoming; + for (const processor of this._processors) { + filteredAttributes = processor.process(filteredAttributes, context); + } + return filteredAttributes; } +} + +class AllowListProcessor implements IAttributesProcessor { + constructor(private _allowedAttributeNames: string[]) {} - process(incoming: MetricAttributes, _context: Context): MetricAttributes { - const filteredAttributes: MetricAttributes = {}; + process(incoming: Attributes, _context?: Context): Attributes { + const filteredAttributes: Attributes = {}; Object.keys(incoming) .filter(attributeName => this._allowedAttributeNames.includes(attributeName) @@ -68,4 +66,62 @@ export class FilteringAttributesProcessor extends AttributesProcessor { } } +class DenyListProcessor implements IAttributesProcessor { + constructor(private _deniedAttributeNames: string[]) {} + + process(incoming: Attributes, _context?: Context): Attributes { + const filteredAttributes: Attributes = {}; + Object.keys(incoming) + .filter( + attributeName => !this._deniedAttributeNames.includes(attributeName) + ) + .forEach( + attributeName => + (filteredAttributes[attributeName] = incoming[attributeName]) + ); + return filteredAttributes; + } +} + +/** + * @internal + * + * Create an {@link IAttributesProcessor} that acts as a simple pass-through for attributes. + */ +export function createNoopAttributesProcessor(): IAttributesProcessor { + return NOOP; +} + +/** + * @internal + * + * Create an {@link IAttributesProcessor} that applies all processors from the provided list in order. + * + * @param processors Processors to apply in order. + */ +export function createMultiAttributesProcessor( + processors: IAttributesProcessor[] +): IAttributesProcessor { + return new MultiAttributesProcessor(processors); +} + +/** + * Create an {@link IAttributesProcessor} that filters by allowed attribute names and drops any names that are not in the + * allow list. + */ +export function createAllowListAttributesProcessor( + attributeAllowList: string[] +): IAttributesProcessor { + return new AllowListProcessor(attributeAllowList); +} + +/** + * Create an {@link IAttributesProcessor} that drops attributes based on the names provided in the deny list + */ +export function createDenyListAttributesProcessor( + attributeDenyList: string[] +): IAttributesProcessor { + return new DenyListProcessor(attributeDenyList); +} + const NOOP = new NoopAttributesProcessor(); diff --git a/packages/sdk-metrics/src/view/View.ts b/packages/sdk-metrics/src/view/View.ts index 9a8e7cc60f..822279b4c9 100644 --- a/packages/sdk-metrics/src/view/View.ts +++ b/packages/sdk-metrics/src/view/View.ts @@ -16,13 +16,19 @@ import { PatternPredicate } from './Predicate'; import { - AttributesProcessor, - FilteringAttributesProcessor, + createMultiAttributesProcessor, + createNoopAttributesProcessor, + IAttributesProcessor, } from './AttributesProcessor'; import { InstrumentSelector } from './InstrumentSelector'; import { MeterSelector } from './MeterSelector'; import { Aggregation } from './Aggregation'; import { InstrumentType } from '../InstrumentDescriptor'; +import { + AggregationOption, + AggregationType, + toAggregation, +} from './AggregationOption'; export type ViewOptions = { /** @@ -42,25 +48,28 @@ export type ViewOptions = { description?: string; /** * Alters the metric stream: - * If provided, the attributes that are not in the list will be ignored. + * If provided, the attributes will be modified as defined by the processors in the list. Processors are applied + * in the order they're provided. * If not provided, all attribute keys will be used by default. * * @example drops all attributes with top-level keys except for 'myAttr' and 'myOtherAttr' - * attributeKeys: ['myAttr', 'myOtherAttr'] + * attributesProcessors: [createAllowListProcessor(['myAttr', 'myOtherAttr'])] * @example drops all attributes - * attributeKeys: [] + * attributesProcessors: [createAllowListProcessor([])] + * @example allows all attributes except for 'myAttr' + * attributesProcessors: [createDenyListProcessor(['myAttr']] */ - attributeKeys?: string[]; + attributesProcessors?: IAttributesProcessor[]; /** * Alters the metric stream: - * Alters the {@link Aggregation} of the metric stream. + * Alters the Aggregation of the metric stream. * * @example changes the aggregation of the selected instrument(s) to ExplicitBucketHistogramAggregation - * aggregation: new ExplicitBucketHistogramAggregation([1, 10, 100]) + * aggregation: { type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, options: { boundaries: [1, 10, 100] } } * @example changes the aggregation of the selected instrument(s) to LastValueAggregation - * aggregation: new LastValueAggregation() + * aggregation: { type: AggregationType.LAST_VALUE, options: { boundaries: [1, 10, 100] } } */ - aggregation?: Aggregation; + aggregation?: AggregationOption; /** * Alters the metric stream: * Sets a limit on the number of unique attribute combinations (cardinality) that can be aggregated. @@ -137,6 +146,26 @@ function isSelectorNotProvided(options: ViewOptions): boolean { ); } +function validateViewOptions(viewOptions: ViewOptions) { + // If no criteria is provided, the SDK SHOULD treat it as an error. + // It is recommended that the SDK implementations fail fast. + if (isSelectorNotProvided(viewOptions)) { + throw new Error('Cannot create view with no selector arguments supplied'); + } + + // the SDK SHOULD NOT allow Views with a specified name to be declared with instrument selectors that + // may select more than one instrument (e.g. wild card instrument name) in the same Meter. + if ( + viewOptions.name != null && + (viewOptions?.instrumentName == null || + PatternPredicate.hasWildcard(viewOptions.instrumentName)) + ) { + throw new Error( + 'Views with a specified name must be declared with an instrument selector that selects at most one instrument per meter.' + ); + } +} + /** * Can be passed to a {@link MeterProvider} to select instruments and alter their metric stream. */ @@ -144,7 +173,7 @@ export class View { readonly name?: string; readonly description?: string; readonly aggregation: Aggregation; - readonly attributesProcessor: AttributesProcessor; + readonly attributesProcessor: IAttributesProcessor; readonly instrumentSelector: InstrumentSelector; readonly meterSelector: MeterSelector; readonly aggregationCardinalityLimit?: number; @@ -167,9 +196,9 @@ export class View { * Alters the metric stream: * This will be used as the description of the metrics stream. * If not provided, the original Instrument description will be used by default. - * @param viewOptions.attributeKeys + * @param viewOptions.attributesProcessors * Alters the metric stream: - * If provided, the attributes that are not in the list will be ignored. + * If provided, the attributes will be modified as defined by the added processors. * If not provided, all attribute keys will be used by default. * @param viewOptions.aggregationCardinalityLimit * Alters the metric stream: @@ -206,36 +235,22 @@ export class View { * }) */ constructor(viewOptions: ViewOptions) { - // If no criteria is provided, the SDK SHOULD treat it as an error. - // It is recommended that the SDK implementations fail fast. - if (isSelectorNotProvided(viewOptions)) { - throw new Error('Cannot create view with no selector arguments supplied'); - } - - // the SDK SHOULD NOT allow Views with a specified name to be declared with instrument selectors that - // may select more than one instrument (e.g. wild card instrument name) in the same Meter. - if ( - viewOptions.name != null && - (viewOptions?.instrumentName == null || - PatternPredicate.hasWildcard(viewOptions.instrumentName)) - ) { - throw new Error( - 'Views with a specified name must be declared with an instrument selector that selects at most one instrument per meter.' - ); - } + validateViewOptions(viewOptions); - // Create AttributesProcessor if attributeKeys are defined set. - if (viewOptions.attributeKeys != null) { - this.attributesProcessor = new FilteringAttributesProcessor( - viewOptions.attributeKeys + // Create multi-processor if attributesProcessors are defined. + if (viewOptions.attributesProcessors != null) { + this.attributesProcessor = createMultiAttributesProcessor( + viewOptions.attributesProcessors ); } else { - this.attributesProcessor = AttributesProcessor.Noop(); + this.attributesProcessor = createNoopAttributesProcessor(); } this.name = viewOptions.name; this.description = viewOptions.description; - this.aggregation = viewOptions.aggregation ?? Aggregation.Default(); + this.aggregation = toAggregation( + viewOptions.aggregation ?? { type: AggregationType.DEFAULT } + ); this.instrumentSelector = new InstrumentSelector({ name: viewOptions.instrumentName, type: viewOptions.instrumentType, diff --git a/packages/sdk-metrics/test/MeterProvider.test.ts b/packages/sdk-metrics/test/MeterProvider.test.ts index 453945200d..05cd76e1e2 100644 --- a/packages/sdk-metrics/test/MeterProvider.test.ts +++ b/packages/sdk-metrics/test/MeterProvider.test.ts @@ -19,7 +19,6 @@ import { MeterProvider, InstrumentType, DataPointType, - ExplicitBucketHistogramAggregation, HistogramMetricData, DataPoint, } from '../src'; @@ -31,8 +30,9 @@ import { } from './util'; import { TestMetricReader } from './export/TestMetricReader'; import * as sinon from 'sinon'; -import { View } from '../src/view/View'; import { Meter } from '../src/Meter'; +import { createAllowListAttributesProcessor } from '../src/view/AttributesProcessor'; +import { AggregationType } from '../src/view/AggregationOption'; import { Resource } from '@opentelemetry/resources'; describe('MeterProvider', () => { @@ -200,11 +200,11 @@ describe('MeterProvider', () => { resource: defaultResource, // Add view to rename 'non-renamed-instrument' to 'renamed-instrument' views: [ - new View({ + { name: 'renamed-instrument', description: 'my renamed instrument', instrumentName: 'non-renamed-instrument', - }), + }, ], readers: [reader], }); @@ -262,17 +262,19 @@ describe('MeterProvider', () => { ); }); - it('with attributeKeys should drop non-listed attributes', async () => { + it('with allowListProcessor should drop non-listed attributes', async () => { const reader = new TestMetricReader(); // Add view to drop all attributes except 'attrib1' const meterProvider = new MeterProvider({ resource: defaultResource, views: [ - new View({ - attributeKeys: ['attrib1'], + { + attributesProcessors: [ + createAllowListAttributesProcessor(['attrib1']), + ], instrumentName: 'non-renamed-instrument', - }), + }, ], readers: [reader], }); @@ -335,10 +337,10 @@ describe('MeterProvider', () => { const meterProvider = new MeterProvider({ resource: defaultResource, views: [ - new View({ + { name: 'renamed-instrument', instrumentName: 'test-counter', - }), + }, ], readers: [reader], }); @@ -407,11 +409,11 @@ describe('MeterProvider', () => { resource: defaultResource, views: [ // Add view that renames 'test-counter' to 'renamed-instrument' on 'meter1' - new View({ + { name: 'renamed-instrument', instrumentName: 'test-counter', meterName: 'meter1', - }), + }, ], readers: [reader], }); @@ -480,16 +482,16 @@ describe('MeterProvider', () => { resource: defaultResource, // Add Views to rename both instruments (of different types) to the same name. views: [ - new View({ + { name: 'renamed-instrument', instrumentName: 'test-counter', meterName: 'meter1', - }), - new View({ + }, + { name: 'renamed-instrument', instrumentName: 'test-histogram', meterName: 'meter1', - }), + }, ], readers: [reader], }); @@ -548,14 +550,21 @@ describe('MeterProvider', () => { const meterProvider = new MeterProvider({ resource: defaultResource, views: [ - new View({ + { instrumentUnit: 'ms', - aggregation: new ExplicitBucketHistogramAggregation(msBoundaries), - }), - new View({ + // aggregation: new ExplicitBucketHistogramAggregation(msBoundaries), + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { boundaries: msBoundaries }, + }, + }, + { instrumentUnit: 's', - aggregation: new ExplicitBucketHistogramAggregation(sBoundaries), - }), + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { boundaries: sBoundaries }, + }, + }, ], readers: [reader], }); @@ -610,10 +619,10 @@ describe('MeterProvider', () => { resource: defaultResource, readers: [reader], views: [ - new View({ + { instrumentName: 'test-counter', aggregationCardinalityLimit: 2, // Set cardinality limit to 2 - }), + }, ], }); @@ -655,10 +664,10 @@ describe('MeterProvider', () => { resource: defaultResource, readers: [reader], views: [ - new View({ + { instrumentName: 'test-observable-counter', aggregationCardinalityLimit: 2, // Set cardinality limit to 2 - }), + }, ], }); diff --git a/packages/sdk-metrics/test/export/MetricReader.test.ts b/packages/sdk-metrics/test/export/MetricReader.test.ts index b08cde5e38..cc091c9797 100644 --- a/packages/sdk-metrics/test/export/MetricReader.test.ts +++ b/packages/sdk-metrics/test/export/MetricReader.test.ts @@ -21,8 +21,8 @@ import { assertRejects } from '../test-utils'; import { emptyResourceMetrics, TestMetricProducer } from './TestMetricProducer'; import { TestMetricReader } from './TestMetricReader'; import { - Aggregation, AggregationTemporality, + AggregationType, DataPointType, InstrumentType, ScopeMetrics, @@ -228,9 +228,17 @@ describe('MetricReader', () => { it('should override default when provided with a selector', () => { const reader = new TestMetricReader({ - aggregationSelector: _instrumentType => Aggregation.Sum(), + aggregationSelector: _instrumentType => { + return { + type: AggregationType.SUM, + }; + }, + }); + assertAggregationSelector(reader, _instrumentType => { + return { + type: AggregationType.SUM, + }; }); - assertAggregationSelector(reader, _instrumentType => Aggregation.Sum()); reader.shutdown(); }); }); diff --git a/packages/sdk-metrics/test/export/PeriodicExportingMetricReader.test.ts b/packages/sdk-metrics/test/export/PeriodicExportingMetricReader.test.ts index 1fe248cab8..3294697874 100644 --- a/packages/sdk-metrics/test/export/PeriodicExportingMetricReader.test.ts +++ b/packages/sdk-metrics/test/export/PeriodicExportingMetricReader.test.ts @@ -17,7 +17,8 @@ import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { - Aggregation, + AggregationOption, + AggregationType, CollectionResult, InstrumentType, MetricProducer, @@ -115,8 +116,8 @@ class TestDeltaMetricExporter extends TestMetricExporter { } class TestDropMetricExporter extends TestMetricExporter { - selectAggregation(_instrumentType: InstrumentType): Aggregation { - return Aggregation.Drop(); + selectAggregation(_instrumentType: InstrumentType): AggregationOption { + return { type: AggregationType.DROP }; } } diff --git a/packages/sdk-metrics/test/export/utils.ts b/packages/sdk-metrics/test/export/utils.ts index a10021ee90..77b2791b20 100644 --- a/packages/sdk-metrics/test/export/utils.ts +++ b/packages/sdk-metrics/test/export/utils.ts @@ -43,7 +43,7 @@ export function assertAggregationSelector( expectedSelector: AggregationSelector ) { for (const instrumentType of instrumentTypes) { - assert.strictEqual( + assert.deepStrictEqual( reader.selectAggregation?.(instrumentType), expectedSelector(instrumentType), `incorrect aggregation selection for ${InstrumentType[instrumentType]}` diff --git a/packages/sdk-metrics/test/regression/cumulative-exponential-histogram.test.ts b/packages/sdk-metrics/test/regression/cumulative-exponential-histogram.test.ts index 2462ddf5c8..3787308d9e 100644 --- a/packages/sdk-metrics/test/regression/cumulative-exponential-histogram.test.ts +++ b/packages/sdk-metrics/test/regression/cumulative-exponential-histogram.test.ts @@ -17,8 +17,9 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { - Aggregation, + AggregationOption, AggregationTemporality, + AggregationType, InstrumentType, MeterProvider, MetricReader, @@ -37,15 +38,15 @@ describe('cumulative-exponential-histogram', () => { it('Cumulative Histogram should have the same startTime every collection', async () => { // Works fine and passes - await doTest(Aggregation.Histogram()); + await doTest({ type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM }); }); it('Cumulative ExponentialHistogram should have the same startTime every collection', async () => { // Fails - await doTest(Aggregation.ExponentialHistogram()); + await doTest({ type: AggregationType.EXPONENTIAL_HISTOGRAM }); }); - const doTest = async (histogramAggregation: Aggregation) => { + const doTest = async (histogramAggregation: AggregationOption) => { const reader = new TestMetricReader({ aggregationTemporalitySelector() { return AggregationTemporality.CUMULATIVE; @@ -53,7 +54,7 @@ describe('cumulative-exponential-histogram', () => { aggregationSelector(type) { return type === InstrumentType.HISTOGRAM ? histogramAggregation - : Aggregation.Default(); + : { type: AggregationType.DEFAULT }; }, }); const meterProvider = new MeterProvider({ diff --git a/packages/sdk-metrics/test/regression/histogram-recording-nan.test.ts b/packages/sdk-metrics/test/regression/histogram-recording-nan.test.ts index a37c9c8e92..4cb73ff498 100644 --- a/packages/sdk-metrics/test/regression/histogram-recording-nan.test.ts +++ b/packages/sdk-metrics/test/regression/histogram-recording-nan.test.ts @@ -16,13 +16,13 @@ import * as assert from 'assert'; import { - Aggregation, AggregationTemporality, MeterProvider, MetricReader, DataPoint, ExponentialHistogram, Histogram, + AggregationType, } from '../../src'; import { TestMetricReader } from '../export/TestMetricReader'; @@ -33,7 +33,7 @@ describe('histogram-recording-nan', () => { return AggregationTemporality.CUMULATIVE; }, aggregationSelector(type) { - return Aggregation.ExponentialHistogram(); + return { type: AggregationType.EXPONENTIAL_HISTOGRAM }; }, }); const meterProvider = new MeterProvider({ @@ -65,7 +65,7 @@ describe('histogram-recording-nan', () => { return AggregationTemporality.CUMULATIVE; }, aggregationSelector(type) { - return Aggregation.Histogram(); + return { type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM }; }, }); const meterProvider = new MeterProvider({ diff --git a/packages/sdk-metrics/test/state/AsyncMetricStorage.test.ts b/packages/sdk-metrics/test/state/AsyncMetricStorage.test.ts index e940c71c18..30dfde4889 100644 --- a/packages/sdk-metrics/test/state/AsyncMetricStorage.test.ts +++ b/packages/sdk-metrics/test/state/AsyncMetricStorage.test.ts @@ -21,7 +21,7 @@ import { AggregationTemporality } from '../../src/export/AggregationTemporality' import { DataPointType } from '../../src/export/MetricData'; import { MetricCollectorHandle } from '../../src/state/MetricCollector'; import { AsyncMetricStorage } from '../../src/state/AsyncMetricStorage'; -import { NoopAttributesProcessor } from '../../src/view/AttributesProcessor'; +import { createNoopAttributesProcessor } from '../../src/view/AttributesProcessor'; import { ObservableRegistry } from '../../src/state/ObservableRegistry'; import { assertMetricData, @@ -51,7 +51,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [deltaCollector] ); @@ -151,7 +151,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [deltaCollector] ); @@ -235,7 +235,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(false), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [deltaCollector] ); @@ -321,7 +321,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [cumulativeCollector] ); @@ -453,7 +453,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [cumulativeCollector] ); @@ -547,7 +547,7 @@ describe('AsyncMetricStorage', () => { const metricStorage = new AsyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(false), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [cumulativeCollector] ); diff --git a/packages/sdk-metrics/test/state/MeterSharedState.test.ts b/packages/sdk-metrics/test/state/MeterSharedState.test.ts index 9e814a4b43..74b4ff9a27 100644 --- a/packages/sdk-metrics/test/state/MeterSharedState.test.ts +++ b/packages/sdk-metrics/test/state/MeterSharedState.test.ts @@ -19,10 +19,10 @@ import * as sinon from 'sinon'; import { MeterProvider, DataPointType, - View, - Aggregation, MetricReader, InstrumentType, + AggregationType, + ViewOptions, } from '../../src'; import { assertMetricData, @@ -44,7 +44,7 @@ describe('MeterSharedState', () => { }); describe('registerMetricStorage', () => { - function setupMeter(views?: View[], readers?: MetricReader[]) { + function setupMeter(views?: ViewOptions[], readers?: MetricReader[]) { const meterProvider = new MeterProvider({ resource: defaultResource, views, @@ -69,7 +69,7 @@ describe('MeterSharedState', () => { }, }); const { meter, meterSharedState, collectors } = setupMeter( - [new View({ instrumentName: 'test-counter' })], + [{ instrumentName: 'test-counter' }], [reader] ); @@ -92,7 +92,7 @@ describe('MeterSharedState', () => { }, }); const { meter, meterSharedState, collectors } = setupMeter( - [new View({ instrumentName: 'test-counter' })], + [{ instrumentName: 'test-counter' }], [reader] ); @@ -111,7 +111,7 @@ describe('MeterSharedState', () => { it('should register metric storages with the collector', () => { const reader = new TestMetricReader({ aggregationSelector: (instrumentType: InstrumentType) => { - return Aggregation.Drop(); + return { type: AggregationType.DROP }; }, }); const readerAggregationSelectorSpy = sinon.spy( @@ -141,12 +141,12 @@ describe('MeterSharedState', () => { it('should register metric storages with collectors', () => { const reader = new TestMetricReader({ aggregationSelector: (instrumentType: InstrumentType) => { - return Aggregation.Drop(); + return { type: AggregationType.DROP }; }, }); const reader2 = new TestMetricReader({ aggregationSelector: (instrumentType: InstrumentType) => { - return Aggregation.LastValue(); + return { type: AggregationType.LAST_VALUE }; }, }); @@ -184,7 +184,7 @@ describe('MeterSharedState', () => { }); describe('collect', () => { - function setupInstruments(views?: View[]) { + function setupInstruments(views?: ViewOptions[]) { const cumulativeReader = new TestMetricReader(); const deltaReader = new TestDeltaMetricReader(); @@ -245,8 +245,8 @@ describe('MeterSharedState', () => { it('should collect sync metrics with views', async () => { /** preparing test instrumentations */ const { metricCollectors, meter } = setupInstruments([ - new View({ name: 'foo', instrumentName: 'test' }), - new View({ name: 'bar', instrumentName: 'test' }), + { name: 'foo', instrumentName: 'test' }, + { name: 'bar', instrumentName: 'test' }, ]); /** creating metric events */ @@ -314,8 +314,8 @@ describe('MeterSharedState', () => { it('should call observable callback once with view-ed async instruments', async () => { /** preparing test instrumentations */ const { metricCollectors, meter } = setupInstruments([ - new View({ name: 'foo', instrumentName: 'test' }), - new View({ name: 'bar', instrumentName: 'test' }), + { name: 'foo', instrumentName: 'test' }, + { name: 'bar', instrumentName: 'test' }, ]); /** creating metric events */ diff --git a/packages/sdk-metrics/test/state/SyncMetricStorage.test.ts b/packages/sdk-metrics/test/state/SyncMetricStorage.test.ts index e12a291a9d..8dfb256de9 100644 --- a/packages/sdk-metrics/test/state/SyncMetricStorage.test.ts +++ b/packages/sdk-metrics/test/state/SyncMetricStorage.test.ts @@ -22,7 +22,7 @@ import { AggregationTemporality } from '../../src/export/AggregationTemporality' import { DataPointType } from '../../src/export/MetricData'; import { MetricCollectorHandle } from '../../src/state/MetricCollector'; import { SyncMetricStorage } from '../../src/state/SyncMetricStorage'; -import { NoopAttributesProcessor } from '../../src/view/AttributesProcessor'; +import { createNoopAttributesProcessor } from '../../src/view/AttributesProcessor'; import { assertMetricData, assertDataPoint, @@ -47,7 +47,7 @@ describe('SyncMetricStorage', () => { const metricStorage = new SyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [] ); @@ -65,7 +65,7 @@ describe('SyncMetricStorage', () => { const metricStorage = new SyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [deltaCollector] ); @@ -103,7 +103,7 @@ describe('SyncMetricStorage', () => { const metricStorage = new SyncMetricStorage( defaultInstrumentDescriptor, new SumAggregator(true), - new NoopAttributesProcessor(), + createNoopAttributesProcessor(), [cumulativeCollector] ); metricStorage.record(1, {}, api.context.active(), [0, 0]); diff --git a/packages/sdk-metrics/test/view/Aggregation.test.ts b/packages/sdk-metrics/test/view/Aggregation.test.ts index 51595aa590..a2b25b77f8 100644 --- a/packages/sdk-metrics/test/view/Aggregation.test.ts +++ b/packages/sdk-metrics/test/view/Aggregation.test.ts @@ -27,43 +27,16 @@ import { InstrumentType, } from '../../src/InstrumentDescriptor'; import { - Aggregation, DefaultAggregation, - DropAggregation, ExplicitBucketHistogramAggregation, HistogramAggregation, - LastValueAggregation, - SumAggregation, } from '../../src/view/Aggregation'; import { defaultInstrumentDescriptor } from '../util'; -interface AggregationConstructor { - new (...args: any[]): Aggregation; -} - interface AggregatorConstructor { new (...args: any[]): Aggregator; } -describe('Aggregation', () => { - it('static aggregations', () => { - const staticMembers: [keyof typeof Aggregation, AggregationConstructor][] = - [ - ['Drop', DropAggregation], - ['Sum', SumAggregation], - ['LastValue', LastValueAggregation], - ['Histogram', HistogramAggregation], - ['Default', DefaultAggregation], - ]; - - for (const [key, type] of staticMembers) { - const aggregation = (Aggregation[key] as () => Aggregation)(); - assert(aggregation instanceof type); - assert(aggregation.createAggregator(defaultInstrumentDescriptor)); - } - }); -}); - describe('DefaultAggregation', () => { describe('createAggregator', () => { it('should create aggregators for instrument descriptors', () => { diff --git a/packages/sdk-metrics/test/view/AttributesProcessor.test.ts b/packages/sdk-metrics/test/view/AttributesProcessor.test.ts index 8d38efacdf..0bdcac9809 100644 --- a/packages/sdk-metrics/test/view/AttributesProcessor.test.ts +++ b/packages/sdk-metrics/test/view/AttributesProcessor.test.ts @@ -15,12 +15,19 @@ */ import * as assert from 'assert'; -import { context } from '@opentelemetry/api'; -import { NoopAttributesProcessor } from '../../src/view/AttributesProcessor'; -import { FilteringAttributesProcessor } from '../../src/view/AttributesProcessor'; +import { Attributes, context } from '@opentelemetry/api'; +import { + IAttributesProcessor, + createMultiAttributesProcessor, + createNoopAttributesProcessor, + createAllowListAttributesProcessor, + createDenyListAttributesProcessor, +} from '../../src/view/AttributesProcessor'; + +import sinon = require('sinon'); describe('NoopAttributesProcessor', () => { - const processor = new NoopAttributesProcessor(); + const processor = createNoopAttributesProcessor(); it('should return identical attributes on process', () => { assert.deepStrictEqual( @@ -32,14 +39,14 @@ describe('NoopAttributesProcessor', () => { }); }); -describe('FilteringAttributesProcessor', () => { +describe('AllowListProcessor', () => { it('should not add keys when attributes do not exist', () => { - const processor = new FilteringAttributesProcessor(['foo', 'bar']); + const processor = createAllowListAttributesProcessor(['foo', 'bar']); assert.deepStrictEqual(processor.process({}, context.active()), {}); }); it('should only keep allowed attributes', () => { - const processor = new FilteringAttributesProcessor(['foo', 'bar']); + const processor = createAllowListAttributesProcessor(['foo', 'bar']); assert.deepStrictEqual( processor.process( { @@ -56,3 +63,63 @@ describe('FilteringAttributesProcessor', () => { ); }); }); + +describe('DenyListProcessor', () => { + it('should drop denie attributes', () => { + const processor = createDenyListAttributesProcessor(['foo', 'bar']); + assert.deepStrictEqual( + processor.process( + { + foo: 'fooValue', + bar: 'barValue', + baz: 'bazValue', + }, + context.active() + ), + { + baz: 'bazValue', + } + ); + }); +}); + +describe('MultiAttributesProcessor', () => { + it('should apply in order', () => { + // arrange + const firstProcessorOutput: Attributes = { foo: 'firstProcessorFoo' }; + const secondProcessorOutput: Attributes = { + foo: 'secondProcessorFoo', + bar: 'secondProcessorBar', + }; + const firstMockProcessorStubs = { + process: sinon.stub().returns(firstProcessorOutput), + }; + const firstMockProcessor = firstMockProcessorStubs as IAttributesProcessor; + + const secondMockProcessorStubs = { + process: sinon.stub().returns(secondProcessorOutput), + }; + const secondMockProcessor = + secondMockProcessorStubs as IAttributesProcessor; + + const processor = createMultiAttributesProcessor([ + firstMockProcessor, + secondMockProcessor, + ]); + + // act + const input: Attributes = { foo: 'bar' }; + const result = processor.process(input, context.active()); + + // assert + firstMockProcessorStubs.process.calledOnceWithExactly( + input, + context.active() + ); + secondMockProcessorStubs.process.calledOnceWithExactly( + firstProcessorOutput, + context.active() + ); + assert.deepStrictEqual(result, secondProcessorOutput); + }); +}); diff --git a/packages/sdk-metrics/test/view/View.test.ts b/packages/sdk-metrics/test/view/View.test.ts index 921928cf1f..f17a6ab3fc 100644 --- a/packages/sdk-metrics/test/view/View.test.ts +++ b/packages/sdk-metrics/test/view/View.test.ts @@ -15,13 +15,13 @@ */ import * as assert from 'assert'; -import { AttributesProcessor } from '../../src/view/AttributesProcessor'; -import { View } from '../../src/view/View'; import { - InstrumentType, - Aggregation, - ExplicitBucketHistogramAggregation, -} from '../../src'; + createAllowListAttributesProcessor, + createNoopAttributesProcessor, +} from '../../src/view/AttributesProcessor'; +import { InstrumentType, AggregationType } from '../../src'; +import { DEFAULT_AGGREGATION } from '../../src/view/Aggregation'; +import { View } from '../../src/view/View'; describe('View', () => { describe('constructor', () => { @@ -30,20 +30,20 @@ describe('View', () => { const view = new View({ instrumentName: '*' }); assert.strictEqual(view.name, undefined); assert.strictEqual(view.description, undefined); - assert.strictEqual(view.aggregation, Aggregation.Default()); + assert.strictEqual(view.aggregation, DEFAULT_AGGREGATION); assert.strictEqual( view.attributesProcessor, - AttributesProcessor.Noop() + createNoopAttributesProcessor() ); } { const view = new View({ meterName: '*' }); assert.strictEqual(view.name, undefined); assert.strictEqual(view.description, undefined); - assert.strictEqual(view.aggregation, Aggregation.Default()); + assert.strictEqual(view.aggregation, DEFAULT_AGGREGATION); assert.strictEqual( view.attributesProcessor, - AttributesProcessor.Noop() + createNoopAttributesProcessor() ); } }); @@ -54,14 +54,22 @@ describe('View', () => { // would implicitly rename all instruments to 'name' assert.throws(() => new View({ name: 'name' })); // would implicitly drop all attribute keys on all instruments except 'key' - assert.throws(() => new View({ attributeKeys: ['key'] })); + assert.throws( + () => + new View({ + attributesProcessors: [createAllowListAttributesProcessor(['key'])], + }) + ); // would implicitly rename all instruments to description assert.throws(() => new View({ description: 'description' })); // would implicitly change all instruments to use histogram aggregation assert.throws( () => new View({ - aggregation: new ExplicitBucketHistogramAggregation([1, 100]), + aggregation: { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM, + options: { boundaries: [1, 100] }, + }, }) ); }); diff --git a/packages/sdk-metrics/test/view/ViewRegistry.test.ts b/packages/sdk-metrics/test/view/ViewRegistry.test.ts index b766c0fda5..bb1dadfbf0 100644 --- a/packages/sdk-metrics/test/view/ViewRegistry.test.ts +++ b/packages/sdk-metrics/test/view/ViewRegistry.test.ts @@ -21,7 +21,7 @@ import { defaultInstrumentationScope, defaultInstrumentDescriptor, } from '../util'; -import { View } from '../../src'; +import { View } from '../../src/view/View'; describe('ViewRegistry', () => { describe('findViews', () => { diff --git a/packages/template/package.json b/packages/template/package.json index 466ff392d2..4c60bd1a2f 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -23,7 +23,7 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "engines": { - "node": ">=14" + "node": ">=18" }, "scripts": { "prepublishOnly": "npm run compile", diff --git a/selenium-tests/package.json b/selenium-tests/package.json index db69047238..1c38496434 100644 --- a/selenium-tests/package.json +++ b/selenium-tests/package.json @@ -26,7 +26,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "publishConfig": { "access": "restricted" diff --git a/semantic-conventions/package.json b/semantic-conventions/package.json index 7e2468bf47..f1faf2864b 100644 --- a/semantic-conventions/package.json +++ b/semantic-conventions/package.json @@ -53,7 +53,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=18" }, "files": [ "build/esm/**/*.js",