diff --git a/.circleci/config.yml b/.circleci/config.yml index 36e18dfe3e..e19df84e8a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -115,37 +115,6 @@ browsers_unit_tests: &browsers_unit_tests command: if [ "$CIRCLE_NODE_VERSION" = "v12" ]; then npm run codecov:browser; fi jobs: - lint_&_docs: - docker: - - image: node:12 - environment: - NPM_CONFIG_UNSAFE_PERM: true - steps: - - checkout - - run: - name: Install minimal doc and lint modules globally - command: npm i -g eslint@^6.8.0 eslint-plugin-node @typescript-eslint/eslint-plugin@^2.23.0 @typescript-eslint/parser@^2.23.0 eslint-plugin-header@^3.0.0 eslint-plugin-import@^2.19.1 eslint-plugin-prettier prettier lerna typedoc linkinator typescript@^3.7.2 - - run: - name: Install gts version 2.0.0 globally - command: npm i -g gts@2.0.0 - - run: - name: Symlink global modules into all lerna packages - command: lerna exec 'npm link eslint gts eslint-plugin-node @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-header eslint-plugin-import eslint-plugin-prettier prettier lerna typedoc linkinator typescript' - - run: - name: Check code style and linting - command: npm run lint - - run: - name: Install doc dependencies - command: lerna bootstrap --no-ci --scope @opentelemetry/api --include-filtered-dependencies -- --only dev - - run: - name: Docs tests - command: npm run docs-test - - run: - name: Install minimal modules to lint examples - command: npm i --no-save eslint eslint-plugin-import eslint-config-airbnb-base - - run: - name: Lint examples - command: npm run lint:examples node8: docker: - image: node:8 @@ -161,11 +130,6 @@ jobs: - image: node:12 environment: *node_test_env <<: *node_unit_tests - node13: - docker: - - image: node:13 - environment: *node_test_env - <<: *node_unit_tests node14: docker: - image: node:14 @@ -180,14 +144,9 @@ workflows: version: 2 build: jobs: - - lint_&_docs: - filters: - branches: - only: /.*/ - node8 - node10 - node12 - - node13 - node14 - node12-browsers diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0111f645e4..97b1da014c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,4 +12,4 @@ # https://help.github.com/en/articles/about-code-owners # -* @dyladan @mayurkale22 @rochdev @bg451 @OlivierAlbertini @vmarchaud @markwolff @obecny @mwear +* @dyladan @mayurkale22 @rochdev @bg451 @OlivierAlbertini @vmarchaud @markwolff @obecny @mwear @naseemkullah diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..39cd43b323 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,37 @@ +name: Lint + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: restore lerna + uses: actions/cache@master # must use unreleased master to cache multiple paths + id: cache + with: + path: | + node_modules + packages/*/node_modules + metapackages/*/node_modules + key: ${{ runner.os }}-${{ hashFiles('**/package.json') }} + + - name: Bootstrap + if: steps.cache.outputs.cache-hit != 'true' + run: | + npm install --only=dev --ignore-scripts + npx lerna bootstrap --no-ci --ignore-scripts -- --only=dev + + - name: Lint + run: | + npm run lint + npm run lint:examples + + - name: Install and Build API Dependencies + run: npx lerna bootstrap --no-ci --scope @opentelemetry/api --include-filtered-dependencies + + - name: Test Docs + run: npm run docs-test diff --git a/CHANGELOG.md b/CHANGELOG.md index 41de6d9ba8..ae1b59e09d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,32 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 0.8.3 + +#### :rocket: (Enhancement) +* `opentelemetry-node` + * [#980](https://github.com/open-telemetry/opentelemetry-js/pull/980) feat: merge user supplied and default plugin configs ([@naseemkullah](https://github.com/naseemkullah)) + +#### :bug: (Bug Fix) +* `opentelemetry-context-async-hooks` + * [#1099](https://github.com/open-telemetry/opentelemetry-js/pull/1099) fix(asynchooks-scope): fix context loss using .with() #1101 ([@vmarchaud](https://github.com/vmarchaud)) + +#### :books: (Refine Doc) +* Other + * [#1100](https://github.com/open-telemetry/opentelemetry-js/pull/1100) docs(batcher): document how to configure custom aggregators #989 ([@vmarchaud](https://github.com/vmarchaud)) +* `opentelemetry-api` + * [#1106](https://github.com/open-telemetry/opentelemetry-js/pull/1106) chore: improve API documentation ([@mayurkale22](https://github.com/mayurkale22)) + +#### Committers: 7 +- Bartlomiej Obecny ([@obecny](https://github.com/obecny)) +- Daniel Dyla ([@dyladan](https://github.com/dyladan)) +- Kanika Shah ([@kanikashah90](https://github.com/kanikashah90)) +- Mayur Kale ([@mayurkale22](https://github.com/mayurkale22)) +- Naseem ([@naseemkullah](https://github.com/naseemkullah)) +- Valentin Marchaud ([@vmarchaud](https://github.com/vmarchaud)) +- [@shivkanya9146](https://github.com/shivkanya9146) + + ## 0.8.2 #### :rocket: (Enhancement) diff --git a/README.md b/README.md index c19f11402a..2db50aa664 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ If you are a library author looking to build OpenTelemetry into your library, pl | Platform Version | Supported | |------------------|-------------------------------------------------| | Node.JS `v14` | ✅ | -| Node.JS `v13` | ✅ | | Node.JS `v12` | ✅ | | Node.JS `v10` | ✅ | | Node.JS `v8` | See [Node Support](#node-support) below | @@ -134,6 +133,7 @@ Approvers ([@open-telemetry/js-approvers](https://github.com/orgs/open-telemetry - [Mark Wolff](https://github.com/markwolff), Microsoft - [Bartlomiej Obecny](https://github.com/obecny), LightStep - [Matthew Wear](https://github.com/mwear), LightStep +- [Naseem K. Ullah](https://github.com/naseemkullah), Transit *Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver).* @@ -261,4 +261,3 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [otel-contrib-plugin-express]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-express [otel-contrib-plugin-user-interaction]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/web/opentelemetry-plugin-user-interaction [otel-contrib-plugin-document-load]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/web/opentelemetry-plugin-document-load - diff --git a/doc/batcher-api.md b/doc/batcher-api.md new file mode 100644 index 0000000000..d627faca1d --- /dev/null +++ b/doc/batcher-api.md @@ -0,0 +1,143 @@ +# Batcher API Guide + +[The batcher](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-metrics/src/export/Batcher.ts?rgh-link-date=2020-05-25T18%3A43%3A57Z) has two responsibilities: choosing which aggregator to choose for a metric instrument and store the last record for each metric ready to be exported. + +## Selecting a specific aggregator for metrics + +Sometimes you may want to use a specific aggregator for one of your metric, export an average of the last X values instead of just the last one. + +Here is what an aggregator that does that would look like: +```ts +import { Aggregator } from '@opentelemetry/metrics'; +import { hrTime } from '@opentelemetry/core'; + +export class AverageAggregator implements Aggregator { + + private _values: number[] = []; + private _limit: number; + + constructor (limit?: number) { + this._limit = limit ?? 10; + } + + update (value: number) { + this._values.push(value); + if (this._values.length >= this._limit) { + this._values = this._values.slice(0, 10); + } + } + + toPoint() { + const sum =this._values.reduce((agg, value) => { + agg += value; + return agg; + }, 0); + return { + value: this._values.length > 0 ? sum / this._values.length : 0, + timestamp: hrTime(), + } + } +} +``` + +Now we will need to implement our own batcher to configure the sdk to use our new aggregator. To simplify even more, we will just extend the `UngroupedBatcher` (which is the default) to avoid re-implementing the whole `Aggregator` interface. + +Here the result: +```ts +import { + UngroupedBatcher, + MetricDescriptor, + CounterSumAggregator, + ObserverAggregator, + MeasureExactAggregator, +} from '@opentelemetry/metrics'; + +export class CustomBatcher extends UngroupedBatcher { + aggregatorFor (metricDescriptor: MetricDescriptor) { + if (metricDescriptor.labels === 'metricToBeAveraged') { + return new AverageAggregator(10); + } + // this is exactly what the "UngroupedBatcher" does, we will re-use it + // to fallback on the default behavior + switch (metricDescriptor.metricKind) { + case MetricKind.COUNTER: + return new CounterSumAggregator(); + case MetricKind.OBSERVER: + return new ObserverAggregator(); + default: + return new MeasureExactAggregator(); + } + } +} +``` + +Finally, we need to specify to the `MeterProvider` to use our `CustomBatcher` when creating new meter: + +```ts +import { + UngroupedBatcher, + MetricDescriptor, + CounterSumAggregator, + ObserverAggregator, + MeasureExactAggregator, + MeterProvider, + Aggregator, +} from '@opentelemetry/metrics'; +import { hrTime } from '@opentelemetry/core'; + +export class AverageAggregator implements Aggregator { + + private _values: number[] = []; + private _limit: number; + + constructor (limit?: number) { + this._limit = limit ?? 10; + } + + update (value: number) { + this._values.push(value); + if (this._values.length >= this._limit) { + this._values = this._values.slice(0, 10); + } + } + + toPoint() { + const sum =this._values.reduce((agg, value) => { + agg += value; + return agg; + }, 0); + return { + value: this._values.length > 0 ? sum / this._values.length : 0, + timestamp: hrTime(), + } + } +} + +export class CustomBatcher extends UngroupedBatcher { + aggregatorFor (metricDescriptor: MetricDescriptor) { + if (metricDescriptor.name === 'requests') { + return new AverageAggregator(10); + } + // this is exactly what the "UngroupedBatcher" does, we will re-use it + // to fallback on the default behavior + switch (metricDescriptor.metricKind) { + case MetricKind.COUNTER: + return new CounterSumAggregator(); + case MetricKind.OBSERVER: + return new ObserverAggregator(); + default: + return new MeasureExactAggregator(); + } + } +} + +const meter = new MeterProvider({ + batcher: new CustomBatcher(), + interval: 1000, +}).getMeter('example-custom-batcher'); + +const requestsLatency = meter.createMeasure('requests', { + monotonic: true, + description: 'Average latency' +}); +``` \ No newline at end of file diff --git a/examples/basic-tracer-node/package.json b/examples/basic-tracer-node/package.json index 614c5cec9c..45b211d013 100644 --- a/examples/basic-tracer-node/package.json +++ b/examples/basic-tracer-node/package.json @@ -1,7 +1,7 @@ { "name": "example-basic-tracer-node", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/tracing in Node.js", "main": "index.js", "scripts": { @@ -24,9 +24,9 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/exporter-jaeger": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/exporter-jaeger": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/examples/collector-exporter-node/package.json b/examples/collector-exporter-node/package.json index 34dc191acb..f8d88fffd7 100644 --- a/examples/collector-exporter-node/package.json +++ b/examples/collector-exporter-node/package.json @@ -1,7 +1,7 @@ { "name": "example-collector-exporter-node", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/collector-exporter in Node.js", "main": "index.js", "scripts": { @@ -26,9 +26,9 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/exporter-collector": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/exporter-collector": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/examples/grpc/package.json b/examples/grpc/package.json index a2018dc018..6166ae3fc4 100644 --- a/examples/grpc/package.json +++ b/examples/grpc/package.json @@ -1,7 +1,7 @@ { "name": "grpc-example", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of gRPC integration with OpenTelemetry", "main": "index.js", "scripts": { @@ -28,12 +28,12 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/exporter-jaeger": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/plugin-grpc": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/exporter-jaeger": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/plugin-grpc": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "google-protobuf": "^3.9.2", "grpc": "^1.23.3", "node-pre-gyp": "0.12.0" diff --git a/examples/http/package.json b/examples/http/package.json index 883e79cfea..5456cac954 100644 --- a/examples/http/package.json +++ b/examples/http/package.json @@ -1,7 +1,7 @@ { "name": "http-example", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of HTTP integration with OpenTelemetry", "main": "index.js", "scripts": { @@ -28,12 +28,12 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/exporter-jaeger": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/plugin-http": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/exporter-jaeger": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/plugin-http": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", "devDependencies": { diff --git a/examples/https/package.json b/examples/https/package.json index f65360d862..da9a3549b1 100644 --- a/examples/https/package.json +++ b/examples/https/package.json @@ -1,7 +1,7 @@ { "name": "https-example", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of HTTPs integration with OpenTelemetry", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -29,12 +29,12 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/exporter-jaeger": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/plugin-https": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/exporter-jaeger": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/plugin-https": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", "devDependencies": { diff --git a/examples/metrics/package.json b/examples/metrics/package.json index 75c71a498c..8938b0beba 100644 --- a/examples/metrics/package.json +++ b/examples/metrics/package.json @@ -1,7 +1,7 @@ { "name": "example-metrics", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/metrics", "main": "index.js", "scripts": { @@ -26,8 +26,8 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/exporter-prometheus": "^0.8.2", - "@opentelemetry/metrics": "^0.8.2" + "@opentelemetry/exporter-prometheus": "^0.8.3", + "@opentelemetry/metrics": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/examples/opentracing-shim/package.json b/examples/opentracing-shim/package.json index 8df9a822cd..ff5b6b95ce 100644 --- a/examples/opentracing-shim/package.json +++ b/examples/opentracing-shim/package.json @@ -1,7 +1,7 @@ { "name": "opentracing-shim", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/shim-opentracing in Node.js", "main": "index.js", "scripts": { @@ -29,11 +29,11 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/exporter-jaeger": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/shim-opentracing": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/exporter-jaeger": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/shim-opentracing": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "opentracing": "^0.14.4" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", diff --git a/examples/prometheus/package.json b/examples/prometheus/package.json index 62b1b260d9..dbb521c332 100644 --- a/examples/prometheus/package.json +++ b/examples/prometheus/package.json @@ -1,6 +1,6 @@ { "name": "prometheus-example", - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/metrics and @opentelemetry/exporter-prometheus", "main": "index.js", "scripts": { @@ -9,7 +9,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/exporter-prometheus": "^0.8.2", - "@opentelemetry/metrics": "^0.8.2" + "@opentelemetry/exporter-prometheus": "^0.8.3", + "@opentelemetry/metrics": "^0.8.3" } } diff --git a/examples/tracer-web/package.json b/examples/tracer-web/package.json index 2f1e601e14..ecf4b1a222 100644 --- a/examples/tracer-web/package.json +++ b/examples/tracer-web/package.json @@ -1,7 +1,7 @@ { "name": "web-tracer-example", "private": true, - "version": "0.8.2", + "version": "0.8.3", "description": "Example of using @opentelemetry/web in browser", "main": "index.js", "scripts": { @@ -34,14 +34,14 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/context-zone": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/exporter-collector": "^0.8.2", + "@opentelemetry/context-zone": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/exporter-collector": "^0.8.3", "@opentelemetry/plugin-document-load": "^0.6.1", "@opentelemetry/plugin-user-interaction": "^0.6.1", - "@opentelemetry/plugin-xml-http-request": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", - "@opentelemetry/web": "^0.8.2" + "@opentelemetry/plugin-xml-http-request": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", + "@opentelemetry/web": "^0.8.3" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/getting-started/monitored-example/package.json b/getting-started/monitored-example/package.json index daec19d5a9..465c457fd5 100644 --- a/getting-started/monitored-example/package.json +++ b/getting-started/monitored-example/package.json @@ -9,7 +9,7 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/metrics": "^0.8.2", + "@opentelemetry/metrics": "^0.8.3", "axios": "^0.19.0", "express": "^4.17.1" } diff --git a/getting-started/traced-example/package.json b/getting-started/traced-example/package.json index e1f5f6da58..5f7c34ebdb 100644 --- a/getting-started/traced-example/package.json +++ b/getting-started/traced-example/package.json @@ -9,13 +9,13 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/node": "^0.8.2", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/node": "^0.8.3", "@opentelemetry/plugin-express": "^0.7.0", - "@opentelemetry/plugin-http": "^0.8.2", - "@opentelemetry/plugin-https": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/plugin-http": "^0.8.3", + "@opentelemetry/plugin-https": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "axios": "^0.19.0", "express": "^4.17.1" } diff --git a/getting-started/ts-example/package.json b/getting-started/ts-example/package.json index a41e904abf..d4cfce9775 100644 --- a/getting-started/ts-example/package.json +++ b/getting-started/ts-example/package.json @@ -13,14 +13,14 @@ "ts-node": "^8.6.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/exporter-prometheus": "^0.8.2", - "@opentelemetry/exporter-zipkin": "^0.8.2", - "@opentelemetry/metrics": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/plugin-http": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/exporter-prometheus": "^0.8.3", + "@opentelemetry/exporter-zipkin": "^0.8.3", + "@opentelemetry/metrics": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/plugin-http": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "axios": "^0.19.1", "express": "^4.17.1" } diff --git a/lerna.json b/lerna.json index b903831656..683b1b81cd 100644 --- a/lerna.json +++ b/lerna.json @@ -6,7 +6,7 @@ "metapackages/*", "packages/*" ], - "version": "0.8.2", + "version": "0.8.3", "changelog": { "repo": "open-telemetry/opentelemetry-js", "labels": { diff --git a/metapackages/plugins-node-core/package.json b/metapackages/plugins-node-core/package.json index 9175c87567..35a1d661c0 100644 --- a/metapackages/plugins-node-core/package.json +++ b/metapackages/plugins-node-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugins-node-core", - "version": "0.8.2", + "version": "0.8.3", "description": "Metapackage which bundles all opentelemetry node core plugins", "author": "OpenTelemetry Authors", "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", @@ -16,8 +16,8 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/plugin-grpc": "^0.8.2", - "@opentelemetry/plugin-http": "^0.8.2", - "@opentelemetry/plugin-https": "^0.8.2" + "@opentelemetry/plugin-grpc": "^0.8.3", + "@opentelemetry/plugin-http": "^0.8.3", + "@opentelemetry/plugin-https": "^0.8.3" } } diff --git a/metapackages/plugins-web-core/package.json b/metapackages/plugins-web-core/package.json index 9476ea3531..3fa1a45594 100644 --- a/metapackages/plugins-web-core/package.json +++ b/metapackages/plugins-web-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugins-web-core", - "version": "0.8.2", + "version": "0.8.3", "description": "Metapackage which bundles all opentelemetry web core plugins", "author": "OpenTelemetry Authors", "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", @@ -16,6 +16,6 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/plugin-xml-http-request": "^0.8.2" + "@opentelemetry/plugin-xml-http-request": "^0.8.3" } } diff --git a/package.json b/package.json index 273db8acf3..cc4080916a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opentelemetry-base", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry is a distributed tracing and stats collection framework.", "main": "build/src/index.js", "types": "build/src/index.d.ts", diff --git a/packages/opentelemetry-api/README.md b/packages/opentelemetry-api/README.md index 46ca4fd212..2e965c0fd4 100644 --- a/packages/opentelemetry-api/README.md +++ b/packages/opentelemetry-api/README.md @@ -9,13 +9,14 @@ This package provides everything needed to interact with the OpenTelemetry API, ## Quick Start -To get started tracing you need to install the SDK and plugins, create a TracerProvider, and register it with the API. +To get started you need to install the SDK and plugins, create a TracerProvider and/or MeterProvider, and register it with the API. ### Install Dependencies ```sh $ # Install tracing dependencies $ npm install \ + @opentelemetry/api \ @opentelemetry/core \ @opentelemetry/node \ @opentelemetry/tracing \ @@ -28,6 +29,8 @@ $ npm install \ @opentelemetry/exporter-prometheus # add exporters as needed ``` +> Note: this example is for node.js. See [examples/tracer-web](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/tracer-web) for a browser example. + ### Initialize the SDK Before any other module in your application is loaded, you must initialize the global tracer and meter providers. If you fail to initialize a provider, no-op implementations will be provided to any library which acquires them from the API. @@ -50,9 +53,9 @@ const tracerProvider = new NodeTracerProvider(); */ tracerProvider.addSpanProcessor( new SimpleSpanProcessor( - new JaegerExporter( - /* export options */ - ) + new JaegerExporter({ + serviceName: 'my-service' + }) ) ); @@ -124,18 +127,18 @@ If you are writing an instrumentation library, or prefer to call the API methods ```javascript const api = require("@opentelemetry/api"); -/* Initialize TraceProvider */ -api.trace.setGlobalTracerProvider(traceProvider); -/* returns traceProvider (no-op if a working provider has not been initialized) */ +/* Initialize TracerProvider */ +api.trace.setGlobalTracerProvider(tracerProvider); +/* returns tracerProvider (no-op if a working provider has not been initialized) */ api.trace.getTracerProvider(); -/* returns a tracer from the registered global tracer provider (no-op if a working provider has not been initialized); */ +/* returns a tracer from the registered global tracer provider (no-op if a working provider has not been initialized) */ api.trace.getTracer(name, version); /* Initialize MeterProvider */ api.metrics.setGlobalMeterProvider(meterProvider); /* returns meterProvider (no-op if a working provider has not been initialized) */ api.metrics.getMeterProvider(); -/* returns a meter from the registered global meter provider (no-op if a working provider has not been initialized); */ +/* returns a meter from the registered global meter provider (no-op if a working provider has not been initialized) */ api.metrics.getMeter(name, version); /* Initialize Propagator */ @@ -172,7 +175,6 @@ async function doSomething() { } ``` - ## Useful links - For more information on OpenTelemetry, visit: - For more about OpenTelemetry JavaScript: diff --git a/packages/opentelemetry-api/package.json b/packages/opentelemetry-api/package.json index f15ca22678..386420ec24 100644 --- a/packages/opentelemetry-api/package.json +++ b/packages/opentelemetry-api/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/api", - "version": "0.8.2", + "version": "0.8.3", "description": "Public API for OpenTelemetry", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -51,12 +51,12 @@ "access": "public" }, "dependencies": { - "@opentelemetry/context-base": "^0.8.2" + "@opentelemetry/context-base": "^0.8.3" }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", - "@types/webpack-env": "1.13.9", + "@types/node": "^14.0.5", + "@types/webpack-env": "1.15.2", "codecov": "^3.6.1", "gts": "^2.0.0", "istanbul-instrumenter-loader": "^3.0.1", diff --git a/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts b/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts index 84c5dbd03e..a95a0a4384 100644 --- a/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts +++ b/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts @@ -19,20 +19,22 @@ import { SetterFunction } from './setter'; import { GetterFunction } from './getter'; /** - * Injects {@link Context} into and extracts it from carriers that travel + * Injects `Context` into and extracts it from carriers that travel * in-band across process boundaries. Encoding is expected to conform to the * HTTP Header Field semantics. Values are often encoded as RPC/HTTP request * headers. * * The carrier of propagated data on both the client (injector) and server - * (extractor) side is usually an object such as http headers. + * (extractor) side is usually an object such as http headers. Propagation is + * usually implemented via library-specific request interceptors, where the + * client-side injects values and the server-side extracts them. */ export interface HttpTextPropagator { /** - * Injects values from a given {@link Context} into a carrier. + * Injects values from a given `Context` into a carrier. * - * OpenTelemetry defines a common set of format values (HttpTextPropagator), and - * each has an expected `carrier` type. + * OpenTelemetry defines a common set of format values (HttpTextPropagator), + * and each has an expected `carrier` type. * * @param context the Context from which to extract values to transmit over * the wire. @@ -44,7 +46,7 @@ export interface HttpTextPropagator { inject(context: Context, carrier: unknown, setter: SetterFunction): void; /** - * Given a {@link Context} and a carrier, extract context values from a + * Given a `Context` and a carrier, extract context values from a * carrier and return a new context, created from the old context, with the * extracted values. * diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index a4a7406e71..6b77e9dd15 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -39,6 +39,7 @@ export * from './trace/NoopSpan'; export * from './trace/NoopTracer'; export * from './trace/NoopTracerProvider'; export * from './trace/Sampler'; +export * from './trace/SamplingResult'; export * from './trace/span_context'; export * from './trace/span_kind'; export * from './trace/span'; diff --git a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts index 07302bd22f..0be696d43a 100644 --- a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts +++ b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts @@ -26,15 +26,15 @@ export interface BoundCounter { add(value: number): void; } -/** Measure to report instantaneous measurement of a value. */ -export interface BoundMeasure { +/** ValueRecorder to report instantaneous measurement of a value. */ +export interface BoundValueRecorder { /** - * Records the given value to this measure. - * @param value the measurement to record. + * Records the given value to this value recorder. + * @param value to record. * @param correlationContext the correlationContext associated with the - * measurements. + * values. * @param spanContext the {@link SpanContext} that identifies the {@link Span} - * for which the measurements are associated with. + * which the values are associated with. */ record(value: number): void; record(value: number, correlationContext: CorrelationContext): void; diff --git a/packages/opentelemetry-api/src/metrics/Meter.ts b/packages/opentelemetry-api/src/metrics/Meter.ts index 0b43708c4d..5ed8bbf3a9 100644 --- a/packages/opentelemetry-api/src/metrics/Meter.ts +++ b/packages/opentelemetry-api/src/metrics/Meter.ts @@ -14,22 +14,22 @@ * limitations under the License. */ -import { MetricOptions, Counter, Measure, Observer } from './Metric'; +import { MetricOptions, Counter, ValueRecorder, Observer } from './Metric'; /** * An interface to allow the recording metrics. * * {@link Metric}s are used for recording pre-defined aggregation (`Counter`), - * or raw values (`Measure`) in which the aggregation and labels + * or raw values (`ValueRecorder`) in which the aggregation and labels * for the exported metric are deferred. */ export interface Meter { /** - * Creates and returns a new `Measure`. + * Creates and returns a new `ValueRecorder`. * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure(name: string, options?: MetricOptions): Measure; + createValueRecorder(name: string, options?: MetricOptions): ValueRecorder; /** * Creates a new `Counter` metric. Generally, this kind of metric when the diff --git a/packages/opentelemetry-api/src/metrics/MeterProvider.ts b/packages/opentelemetry-api/src/metrics/MeterProvider.ts index 8802acb615..465dff91fe 100644 --- a/packages/opentelemetry-api/src/metrics/MeterProvider.ts +++ b/packages/opentelemetry-api/src/metrics/MeterProvider.ts @@ -17,7 +17,7 @@ import { Meter } from './Meter'; /** - * MeterProvider provides an interface for creating {@link Meter}s + * A registry for creating named {@link Meter}s. */ export interface MeterProvider { /** diff --git a/packages/opentelemetry-api/src/metrics/Metric.ts b/packages/opentelemetry-api/src/metrics/Metric.ts index 3c44696cc8..00d4ef215e 100644 --- a/packages/opentelemetry-api/src/metrics/Metric.ts +++ b/packages/opentelemetry-api/src/metrics/Metric.ts @@ -17,7 +17,7 @@ import { CorrelationContext } from '../correlation_context/CorrelationContext'; import { SpanContext } from '../trace/span_context'; import { ObserverResult } from './ObserverResult'; -import { BoundCounter, BoundMeasure } from './BoundInstrument'; +import { BoundCounter, BoundValueRecorder } from './BoundInstrument'; /** * Options needed for metric creation @@ -56,7 +56,7 @@ export interface MetricOptions { monotonic?: boolean; /** - * (Measure only, default true) Asserts that this metric will only accept + * (ValueRecorder only, default true) Asserts that this metric will only accept * non-negative values (e.g. disk usage). */ absolute?: boolean; @@ -106,6 +106,21 @@ export interface UnboundMetric extends Metric { unbind(labels: Labels): void; } +/** + * Counter is the most common synchronous instrument. This instrument supports + * an `Add(increment)` function for reporting a sum, and is restricted to + * non-negative increments. The default aggregation is Sum, as for any additive + * instrument. + * + * Example uses for Counter: + *
    + *
  1. count the number of bytes received.
  2. + *
  3. count the number of requests completed.
  4. + *
  5. count the number of accounts created.
  6. + *
  7. count the number of checkpoints run.
  8. + *
  9. count the number of 5xx errors.
  10. + *
      + */ export interface Counter extends UnboundMetric { /** * Adds the given value to the current value. Values cannot be negative. @@ -113,9 +128,9 @@ export interface Counter extends UnboundMetric { add(value: number, labels?: Labels): void; } -export interface Measure extends UnboundMetric { +export interface ValueRecorder extends UnboundMetric { /** - * Records the given value to this measure. + * Records the given value to this value recorder. */ record(value: number, labels?: Labels): void; diff --git a/packages/opentelemetry-api/src/metrics/NoopMeter.ts b/packages/opentelemetry-api/src/metrics/NoopMeter.ts index dcd6a5dea1..eed8c4e9bf 100644 --- a/packages/opentelemetry-api/src/metrics/NoopMeter.ts +++ b/packages/opentelemetry-api/src/metrics/NoopMeter.ts @@ -20,10 +20,10 @@ import { UnboundMetric, Labels, Counter, - Measure, + ValueRecorder, Observer, } from './Metric'; -import { BoundMeasure, BoundCounter } from './BoundInstrument'; +import { BoundValueRecorder, BoundCounter } from './BoundInstrument'; import { CorrelationContext } from '../correlation_context/CorrelationContext'; import { SpanContext } from '../trace/span_context'; import { ObserverResult } from './ObserverResult'; @@ -36,12 +36,12 @@ export class NoopMeter implements Meter { constructor() {} /** - * Returns constant noop measure. + * Returns constant noop value recorder. * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure(name: string, options?: MetricOptions): Measure { - return NOOP_MEASURE_METRIC; + createValueRecorder(name: string, options?: MetricOptions): ValueRecorder { + return NOOP_VALUE_RECORDER_METRIC; } /** @@ -103,8 +103,8 @@ export class NoopCounterMetric extends NoopMetric } } -export class NoopMeasureMetric extends NoopMetric - implements Measure { +export class NoopValueRecorderMetric extends NoopMetric + implements ValueRecorder { record( value: number, labels: Labels, @@ -131,7 +131,7 @@ export class NoopBoundCounter implements BoundCounter { } } -export class NoopBoundMeasure implements BoundMeasure { +export class NoopBoundValueRecorder implements BoundValueRecorder { record( value: number, correlationContext?: CorrelationContext, @@ -145,7 +145,9 @@ export const NOOP_METER = new NoopMeter(); export const NOOP_BOUND_COUNTER = new NoopBoundCounter(); export const NOOP_COUNTER_METRIC = new NoopCounterMetric(NOOP_BOUND_COUNTER); -export const NOOP_BOUND_MEASURE = new NoopBoundMeasure(); -export const NOOP_MEASURE_METRIC = new NoopMeasureMetric(NOOP_BOUND_MEASURE); +export const NOOP_BOUND_VALUE_RECORDER = new NoopBoundValueRecorder(); +export const NOOP_VALUE_RECORDER_METRIC = new NoopValueRecorderMetric( + NOOP_BOUND_VALUE_RECORDER +); export const NOOP_OBSERVER_METRIC = new NoopObserverMetric(); diff --git a/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts b/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts index 9398d51608..4eb66c056b 100644 --- a/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts +++ b/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts @@ -19,8 +19,10 @@ import { Tracer } from './tracer'; import { TracerProvider } from './tracer_provider'; /** - * An implementation of the {@link TracerProvider} which returns an impotent Tracer - * for all calls to `getTracer` + * An implementation of the {@link TracerProvider} which returns an impotent + * Tracer for all calls to `getTracer`. + * + * All operations are no-op. */ export class NoopTracerProvider implements TracerProvider { getTracer(_name?: string, _version?: string): Tracer { diff --git a/packages/opentelemetry-api/src/trace/Sampler.ts b/packages/opentelemetry-api/src/trace/Sampler.ts index 798b5450f7..5e8621572f 100644 --- a/packages/opentelemetry-api/src/trace/Sampler.ts +++ b/packages/opentelemetry-api/src/trace/Sampler.ts @@ -15,6 +15,10 @@ */ import { SpanContext } from './span_context'; +import { SpanKind } from './span_kind'; +import { Attributes } from './attributes'; +import { Link } from './link'; +import { SamplingResult } from './SamplingResult'; /** * This interface represent a sampler. Sampling is a mechanism to control the @@ -25,12 +29,26 @@ export interface Sampler { /** * Checks whether span needs to be created and tracked. * - * TODO: Consider to add required arguments https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sampling-api.md#shouldsample - * @param [parentContext] Parent span context. Typically taken from the wire. + * @param parentContext Parent span context. Typically taken from the wire. * Can be null. - * @returns whether span should be sampled or not. + * @param traceId of the span to be created. It can be different from the + * traceId in the {@link SpanContext}. Typically in situations when the + * 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 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}. */ - shouldSample(parentContext?: SpanContext): boolean; + shouldSample( + parentContext: SpanContext | undefined, + traceId: string, + spanName: string, + spanKind: SpanKind, + attributes: Attributes, + links: Link[] + ): SamplingResult; /** Returns the sampler name or short description with the configuration. */ toString(): string; diff --git a/packages/opentelemetry-api/src/trace/SamplingResult.ts b/packages/opentelemetry-api/src/trace/SamplingResult.ts new file mode 100644 index 0000000000..84957f8297 --- /dev/null +++ b/packages/opentelemetry-api/src/trace/SamplingResult.ts @@ -0,0 +1,56 @@ +/*! + * Copyright 2020, 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 { Attributes } from './attributes'; + +/** + * A sampling decision that determines how a {@link Span} will be recorded + * and collected. + */ +export enum SamplingDecision { + /** + * `Span.isRecording() === false`, span will not be recorded and all events + * and attributes will be dropped. + */ + NOT_RECORD, + /** + * `Span.isRecording() === true`, but `Sampled` flag in {@link TraceFlags} + * MUST NOT be set. + */ + RECORD, + /** + * `Span.isRecording() === true` AND `Sampled` flag in {@link TraceFlags} + * MUST be set. + */ + RECORD_AND_SAMPLED, +} + +/** + * A sampling result contains a decision for a {@link Span} and additional + * attributes the sampler would like to added to the Span. + */ +export interface SamplingResult { + /** + * A sampling decision, refer to {@link SamplingDecision} for details. + */ + decision: SamplingDecision; + /** + * The list of attributes returned by SamplingResult MUST be immutable. + * Caller may call {@link Sampler}.shouldSample any number of times and + * can safely cache the returned value. + */ + attributes?: Readonly; +} diff --git a/packages/opentelemetry-api/src/trace/SpanOptions.ts b/packages/opentelemetry-api/src/trace/SpanOptions.ts index bfda7e001c..13a2c2f389 100644 --- a/packages/opentelemetry-api/src/trace/SpanOptions.ts +++ b/packages/opentelemetry-api/src/trace/SpanOptions.ts @@ -30,10 +30,10 @@ export interface SpanOptions { */ kind?: SpanKind; - /** A spans attributes */ + /** A span's attributes */ attributes?: Attributes; - /** A spans links */ + /** {@link Link}s span to other spans */ links?: Link[]; /** diff --git a/packages/opentelemetry-api/src/trace/attributes.ts b/packages/opentelemetry-api/src/trace/attributes.ts index 188b1e574a..e0f0e922e3 100644 --- a/packages/opentelemetry-api/src/trace/attributes.ts +++ b/packages/opentelemetry-api/src/trace/attributes.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -/** Defines a attributes interface. */ +/** + * Defines a attributes interface. + * These attributes provides additional data about the {@link Span}. + */ export interface Attributes { [attributeKey: string]: unknown; } diff --git a/packages/opentelemetry-api/src/trace/link.ts b/packages/opentelemetry-api/src/trace/link.ts index 2125b82b6c..4226bf1830 100644 --- a/packages/opentelemetry-api/src/trace/link.ts +++ b/packages/opentelemetry-api/src/trace/link.ts @@ -19,8 +19,18 @@ import { LinkContext } from './link_context'; /** * A pointer from the current {@link Span} to another span in the same trace or - * in a different trace. Used (for example) in batching operations, where a - * single batch handler processes multiple requests from different traces. + * in a different trace. + * Few examples of Link usage. + * 1. Batch Processing: A batch of elements may contain elements associated + * with one or more traces/spans. Since there can only be one parent + * SpanContext, Link is used to keep reference to SpanContext of all + * elements in the batch. + * 2. Public Endpoint: A SpanContext in incoming client request on a public + * endpoint is untrusted from service provider perspective. In such case it + * is advisable to start a new trace with appropriate sampling decision. + * However, it is desirable to associate incoming SpanContext to new trace + * initiated on service provider side so two traces (from Client and from + * Service Provider) can be correlated. */ export interface Link { /** The {@link LinkContext} of a linked span. */ diff --git a/packages/opentelemetry-api/src/trace/span.ts b/packages/opentelemetry-api/src/trace/span.ts index 2a725afdc2..8408a48d20 100644 --- a/packages/opentelemetry-api/src/trace/span.ts +++ b/packages/opentelemetry-api/src/trace/span.ts @@ -25,11 +25,17 @@ import { TimeInput } from '../common/Time'; * in-process function calls to sub-components. A Trace has a single, top-level * "root" Span that in turn may have zero or more child Spans, which in turn * may have children. + * + * Spans are created by the {@link Tracer.startSpan} method. */ export interface Span { /** * Returns the {@link SpanContext} object associated with this Span. * + * Get an immutable, serializable identifier for this span that can be used + * to create new child spans. Returned SpanContext is usable even after the + * span ends. + * * @returns the SpanContext object associated with this Span. */ context(): SpanContext; @@ -37,6 +43,8 @@ export interface Span { /** * Sets an attribute to the span. * + * Sets a single Attribute with the key and value passed as arguments. + * * @param key the key for this attribute. * @param value the value for this attribute. */ @@ -66,7 +74,8 @@ export interface Span { /** * Sets a status to the span. If used, this will override the default Span - * status. Default is {@link CanonicalCode.OK}. + * status. Default is {@link CanonicalCode.OK}. SetStatus overrides the value + * of previous calls to SetStatus on the Span. * * @param status the Status to set. */ @@ -75,6 +84,11 @@ export interface Span { /** * Updates the Span name. * + * This will override the name provided via {@link Tracer.startSpan}. + * + * Upon this update, any sampling behavior based on Span name will depend on + * the implementation. + * * @param name the Span name. */ updateName(name: string): this; @@ -97,7 +111,7 @@ export interface Span { * Returns the flag whether this span will be recorded. * * @returns true if this Span is active and recording information like events - * with the AddEvent operation and attributes using setAttributes. + * with the `AddEvent` operation and attributes using `setAttributes`. */ isRecording(): boolean; } diff --git a/packages/opentelemetry-api/src/trace/tracer.ts b/packages/opentelemetry-api/src/trace/tracer.ts index e57f2ee176..f7edc856a0 100644 --- a/packages/opentelemetry-api/src/trace/tracer.ts +++ b/packages/opentelemetry-api/src/trace/tracer.ts @@ -29,28 +29,48 @@ export interface Tracer { /** * Returns the current Span from the current context if available. * - * If there is no Span associated with the current context, null is returned. + * If there is no Span associated with the current context, `null` is + * returned. + * + * To install a {@link Span} to the current Context use + * {@link Tracer.withSpan}. * * @returns Span The currently active Span */ getCurrentSpan(): Span | undefined; /** - * Starts a new {@link Span}. + * Starts a new {@link Span}. Start the span without setting it as the current + * span in this tracer's context. + * + * This method do NOT modify the current Context. To install a {@link + * Span} to the current Context use {@link Tracer.withSpan}. + * * @param name The name of the span * @param [options] SpanOptions used for span creation * @param [context] Context to use to extract parent * @returns Span The newly created span + * @example + * const span = tracer.startSpan('op'); + * span.setAttribute('key', 'value'); + * span.end(); */ startSpan(name: string, options?: SpanOptions, context?: Context): Span; /** - * Executes the function given by fn within the context provided by Span + * Executes the function given by fn within the context provided by Span. + * + * This is a convenience method for creating spans attached to the tracer's + * context. Applications that need more control over the span lifetime should + * use {@link Tracer.startSpan} instead. * * @param span The span that provides the context * @param fn The function to be executed inside the provided context * @example - * tracer.withSpan(span, function() { ... }); + * tracer.withSpan(span, () => { + * tracer.getCurrentSpan().addEvent("parent's event"); + * doSomeOtherWork(); // Here "span" is the current Span. + * }); */ withSpan ReturnType>( span: Span, diff --git a/packages/opentelemetry-api/src/trace/tracer_provider.ts b/packages/opentelemetry-api/src/trace/tracer_provider.ts index 63c6c50285..df5e576e90 100644 --- a/packages/opentelemetry-api/src/trace/tracer_provider.ts +++ b/packages/opentelemetry-api/src/trace/tracer_provider.ts @@ -17,15 +17,15 @@ import { Tracer } from './tracer'; /** - * TracerProvider provides an interface for creating {@link Tracer}s + * A registry for creating named {@link Tracer}s. */ export interface TracerProvider { /** * Returns a Tracer, creating one if one with the given name and version is * not already created. * - * If there is no Span associated with the current context, `null` is - * returned. + * This function may return different Tracer types (e.g. + * {@link NoopTracerProvider} vs. a functional tracer). * * @param name The name of the tracer or instrumentation library. * @param version The version of the tracer or instrumentation library. diff --git a/packages/opentelemetry-api/src/version.ts b/packages/opentelemetry-api/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-api/src/version.ts +++ b/packages/opentelemetry-api/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts index 7b86f5d59d..8738708eba 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts @@ -18,9 +18,9 @@ import * as assert from 'assert'; import { NoopMeterProvider, NOOP_BOUND_COUNTER, - NOOP_BOUND_MEASURE, + NOOP_BOUND_VALUE_RECORDER, NOOP_COUNTER_METRIC, - NOOP_MEASURE_METRIC, + NOOP_VALUE_RECORDER_METRIC, } from '../../src'; describe('NoopMeter', () => { @@ -38,20 +38,23 @@ describe('NoopMeter', () => { assert.strictEqual(counter.bind(labels), NOOP_BOUND_COUNTER); counter.clear(); - const measure = meter.createMeasure('some-name'); - measure.bind(labels).record(1); + const valueRecorder = meter.createValueRecorder('some-name'); + valueRecorder.bind(labels).record(1); // ensure the correct noop const is returned - assert.strictEqual(measure, NOOP_MEASURE_METRIC); - assert.strictEqual(measure.bind(labels), NOOP_BOUND_MEASURE); + assert.strictEqual(valueRecorder, NOOP_VALUE_RECORDER_METRIC); + assert.strictEqual(valueRecorder.bind(labels), NOOP_BOUND_VALUE_RECORDER); const options = { component: 'tests', description: 'the testing package', }; - const measureWithOptions = meter.createMeasure('some-name', options); - assert.strictEqual(measureWithOptions, NOOP_MEASURE_METRIC); + const valueRecorderWithOptions = meter.createValueRecorder( + 'some-name', + options + ); + assert.strictEqual(valueRecorderWithOptions, NOOP_VALUE_RECORDER_METRIC); const counterWithOptions = meter.createCounter('some-name', options); assert.strictEqual(counterWithOptions, NOOP_COUNTER_METRIC); }); diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index e52dbb759e..76a4e5b792 100644 --- a/packages/opentelemetry-context-async-hooks/package.json +++ b/packages/opentelemetry-context-async-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-async-hooks", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry AsyncHooks-based Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -42,7 +42,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/shimmer": "^1.0.1", "codecov": "^3.6.1", "gts": "^2.0.0", @@ -54,6 +54,6 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/context-base": "^0.8.2" + "@opentelemetry/context-base": "^0.8.3" } } diff --git a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts index f970ab397d..adeef82c25 100644 --- a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts +++ b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts @@ -29,19 +29,6 @@ type PatchedEventEmitter = { __ot_listeners?: { [name: string]: WeakMap, Func> }; } & EventEmitter; -class Reference { - constructor(private _value: T) {} - - set(value: T) { - this._value = value; - return this; - } - - get() { - return this._value; - } -} - const ADD_LISTENER_METHODS = [ 'addListener' as 'addListener', 'on' as 'on', @@ -52,72 +39,36 @@ const ADD_LISTENER_METHODS = [ export class AsyncHooksContextManager implements ContextManager { private _asyncHook: asyncHooks.AsyncHook; - private _contextRefs: Map | undefined> = new Map(); + private _contexts: Map = new Map(); + private _stack: Array = []; constructor() { this._asyncHook = asyncHooks.createHook({ init: this._init.bind(this), + before: this._before.bind(this), + after: this._after.bind(this), destroy: this._destroy.bind(this), promiseResolve: this._destroy.bind(this), }); } active(): Context { - const ref = this._contextRefs.get(asyncHooks.executionAsyncId()); - return ref === undefined ? Context.ROOT_CONTEXT : ref.get(); + return this._stack[this._stack.length - 1] ?? Context.ROOT_CONTEXT; } with ReturnType>( context: Context, fn: T ): ReturnType { - const uid = asyncHooks.executionAsyncId(); - let ref = this._contextRefs.get(uid); - let oldContext: Context | undefined = undefined; - if (ref === undefined) { - ref = new Reference(context); - this._contextRefs.set(uid, ref); - } else { - oldContext = ref.get(); - ref.set(context); - } + this._enterContext(context); try { return fn(); } finally { - if (oldContext === undefined) { - this._destroy(uid); - } else { - ref.set(oldContext); - } - } - } - - async withAsync, U extends (...args: unknown[]) => T>( - context: Context, - fn: U - ): Promise { - const uid = asyncHooks.executionAsyncId(); - let ref = this._contextRefs.get(uid); - let oldContext: Context | undefined = undefined; - if (ref === undefined) { - ref = new Reference(context); - this._contextRefs.set(uid, ref); - } else { - oldContext = ref.get(); - ref.set(context); - } - try { - return await fn(); - } finally { - if (oldContext === undefined) { - this._destroy(uid); - } else { - ref.set(oldContext); - } + this._exitContext(); } } - bind(target: T, context: Context): T { + bind(target: T, context?: Context): T { // if no specific context to propagate is given, we use the current one if (context === undefined) { context = this.active(); @@ -137,7 +88,8 @@ export class AsyncHooksContextManager implements ContextManager { disable(): this { this._asyncHook.disable(); - this._contextRefs.clear(); + this._contexts.clear(); + this._stack = []; return this; } @@ -156,6 +108,7 @@ export class AsyncHooksContextManager implements ContextManager { * It isn't possible to tell Typescript that contextWrapper is the same as T * so we forced to cast as any here. */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any return contextWrapper as any; } @@ -271,9 +224,9 @@ export class AsyncHooksContextManager implements ContextManager { * @param uid id of the async context */ private _init(uid: number) { - const ref = this._contextRefs.get(asyncHooks.executionAsyncId()); - if (ref !== undefined) { - this._contextRefs.set(uid, ref); + const context = this._stack[this._stack.length - 1]; + if (context !== undefined) { + this._contexts.set(uid, context); } } @@ -283,6 +236,38 @@ export class AsyncHooksContextManager implements ContextManager { * @param uid uid of the async context */ private _destroy(uid: number) { - this._contextRefs.delete(uid); + this._contexts.delete(uid); + } + + /** + * Before hook is called just beforing executing a async context. + * @param uid uid of the async context + */ + private _before(uid: number) { + const context = this._contexts.get(uid); + if (context !== undefined) { + this._enterContext(context); + } + } + + /** + * After hook is called just after completing the execution of a async context. + */ + private _after() { + this._exitContext(); + } + + /** + * Set the given context as active + */ + private _enterContext(context: Context) { + this._stack.push(context); + } + + /** + * Remove the context at the root of the stack + */ + private _exitContext() { + this._stack.pop(); } } diff --git a/packages/opentelemetry-context-async-hooks/src/version.ts b/packages/opentelemetry-context-async-hooks/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-context-async-hooks/src/version.ts +++ b/packages/opentelemetry-context-async-hooks/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts index 1c2429694e..15f403d622 100644 --- a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts +++ b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts @@ -102,172 +102,105 @@ describe('AsyncHooksContextManager', () => { return done(); }); }); - }); - - describe('.withAsync()', () => { - it('should run the callback', async () => { - let done = false; - await contextManager.withAsync(Context.ROOT_CONTEXT, async () => { - done = true; - }); - - assert.ok(done); - }); - - it('should run the callback with active scope', async () => { - const test = Context.ROOT_CONTEXT.setValue(key1, 1); - await contextManager.withAsync(test, async () => { - assert.strictEqual(contextManager.active(), test, 'should have scope'); - }); - }); - - it('should run the callback (when disabled)', async () => { - contextManager.disable(); - let done = false; - await contextManager.withAsync(Context.ROOT_CONTEXT, async () => { - done = true; - }); - - assert.ok(done); - }); - it('should rethrow errors', async () => { - contextManager.disable(); - let done = false; - const err = new Error(); - - try { - await contextManager.withAsync(Context.ROOT_CONTEXT, async () => { - throw err; + it('should finally restore an old context', done => { + const ctx1 = Context.ROOT_CONTEXT.setValue(key1, 'ctx1'); + contextManager.with(ctx1, () => { + assert.strictEqual(contextManager.active(), ctx1); + setTimeout(() => { + assert.strictEqual(contextManager.active(), ctx1); + return done(); }); - } catch (e) { - assert.ok(e === err); - done = true; - } - - assert.ok(done); + }); }); - it('should finally restore an old scope', async () => { + it('async function called from nested "with" sync function should return nested context', done => { const scope1 = '1' as any; const scope2 = '2' as any; - let done = false; - await contextManager.withAsync(scope1, async () => { + const asyncFuncCalledDownstreamFromSync = async () => { + await (async () => {})(); + assert.strictEqual(contextManager.active(), scope2); + return done(); + }; + + contextManager.with(scope1, () => { assert.strictEqual(contextManager.active(), scope1); - await contextManager.withAsync(scope2, async () => { - assert.strictEqual(contextManager.active(), scope2); - done = true; - }); + contextManager.with(scope2, () => asyncFuncCalledDownstreamFromSync()); assert.strictEqual(contextManager.active(), scope1); }); - - assert.ok(done); + assert.strictEqual(contextManager.active(), Context.ROOT_CONTEXT); }); - }); - describe('.withAsync/with()', () => { - it('with() inside withAsync() should correctly restore context', async () => { + it('should not loose the context', done => { const scope1 = '1' as any; - const scope2 = '2' as any; - let done = false; - await contextManager.withAsync(scope1, async () => { + contextManager.with(scope1, async () => { assert.strictEqual(contextManager.active(), scope1); - contextManager.with(scope2, () => { - assert.strictEqual(contextManager.active(), scope2); - done = true; - }); + await new Promise(resolve => setTimeout(resolve, 100)); assert.strictEqual(contextManager.active(), scope1); + return done(); }); - - assert.ok(done); + assert.strictEqual(contextManager.active(), Context.ROOT_CONTEXT); }); - it('withAsync() inside with() should correctly restore conxtext', done => { + it('should correctly restore context using async/await', async () => { const scope1 = '1' as any; const scope2 = '2' as any; + const scope3 = '3' as any; + const scope4 = '4' as any; - contextManager.with(scope1, async () => { + await contextManager.with(scope1, async () => { assert.strictEqual(contextManager.active(), scope1); - await contextManager.withAsync(scope2, async () => { + await contextManager.with(scope2, async () => { + assert.strictEqual(contextManager.active(), scope2); + await contextManager.with(scope3, async () => { + assert.strictEqual(contextManager.active(), scope3); + await contextManager.with(scope4, async () => { + assert.strictEqual(contextManager.active(), scope4); + }); + assert.strictEqual(contextManager.active(), scope3); + }); assert.strictEqual(contextManager.active(), scope2); }); assert.strictEqual(contextManager.active(), scope1); - return done(); }); assert.strictEqual(contextManager.active(), Context.ROOT_CONTEXT); }); - it('not awaited withAsync() inside with() should not restore context', done => { + it('should works with multiple concurrent operations', done => { const scope1 = '1' as any; const scope2 = '2' as any; - let _done = false; + const scope3 = '3' as any; + const scope4 = '4' as any; + let scope4Called = false; - contextManager.with(scope1, () => { + contextManager.with(scope1, async () => { assert.strictEqual(contextManager.active(), scope1); - contextManager - .withAsync(scope2, async () => { - assert.strictEqual(contextManager.active(), scope2); - }) - .then(() => { - assert.strictEqual(contextManager.active(), scope1); - _done = true; + setTimeout(async () => { + await contextManager.with(scope3, async () => { + assert.strictEqual(contextManager.active(), scope3); }); - // in this case the current scope is 2 since we - // didnt waited the withAsync call - assert.strictEqual(contextManager.active(), scope2); - setTimeout(() => { assert.strictEqual(contextManager.active(), scope1); - assert(_done); + assert.strictEqual(scope4Called, true); return done(); }, 100); + assert.strictEqual(contextManager.active(), scope1); }); assert.strictEqual(contextManager.active(), Context.ROOT_CONTEXT); - }); - - it('withAsync() inside a setTimeout inside a with() should correctly restore context', done => { - const scope1 = '1' as any; - const scope2 = '2' as any; - - contextManager.with(scope1, () => { - assert.strictEqual(contextManager.active(), scope1); + contextManager.with(scope2, async () => { + assert.strictEqual(contextManager.active(), scope2); setTimeout(() => { - assert.strictEqual(contextManager.active(), scope1); - contextManager - .withAsync(scope2, async () => { - assert.strictEqual(contextManager.active(), scope2); - }) - .then(() => { - assert.strictEqual(contextManager.active(), scope1); - return done(); - }); - }, 5); - assert.strictEqual(contextManager.active(), scope1); + contextManager.with(scope4, async () => { + assert.strictEqual(contextManager.active(), scope4); + scope4Called = true; + }); + assert.strictEqual(contextManager.active(), scope2); + }, 20); + assert.strictEqual(contextManager.active(), scope2); }); assert.strictEqual(contextManager.active(), Context.ROOT_CONTEXT); }); - - it('with() inside a setTimeout inside withAsync() should correctly restore context', done => { - const scope1 = '1' as any; - const scope2 = '2' as any; - - contextManager - .withAsync(scope1, async () => { - assert.strictEqual(contextManager.active(), scope1); - setTimeout(() => { - assert.strictEqual(contextManager.active(), scope1); - contextManager.with(scope2, () => { - assert.strictEqual(contextManager.active(), scope2); - return done(); - }); - }, 5); - assert.strictEqual(contextManager.active(), scope1); - }) - .then(() => { - assert.strictEqual(contextManager.active(), scope1); - }); - }); }); describe('.bind(function)', () => { @@ -320,31 +253,15 @@ describe('AsyncHooksContextManager', () => { fn(); }); - it('should fail to return current context (when disabled + async op)', done => { - contextManager.disable(); - const context = Context.ROOT_CONTEXT.setValue(key1, 1); - const fn = contextManager.bind(() => { - setTimeout(() => { - assert.strictEqual( - contextManager.active(), - Context.ROOT_CONTEXT, - 'should have no context' - ); - return done(); - }, 100); - }, context); - fn(); - }); - - it('should return current context (when re-enabled + async op)', done => { - contextManager.enable(); + it('should fail to return current context with async op', done => { const context = Context.ROOT_CONTEXT.setValue(key1, 1); const fn = contextManager.bind(() => { + assert.strictEqual(contextManager.active(), context); setTimeout(() => { assert.strictEqual( contextManager.active(), context, - 'should have context' + 'should have no context' ); return done(); }, 100); @@ -363,7 +280,6 @@ describe('AsyncHooksContextManager', () => { const ee = new EventEmitter(); contextManager.disable(); assert.deepStrictEqual(contextManager.bind(ee, Context.ROOT_CONTEXT), ee); - contextManager.enable(); }); it('should return current context and removeListener (when enabled)', done => { @@ -409,7 +325,6 @@ describe('AsyncHooksContextManager', () => { assert.deepStrictEqual(contextManager.active(), context); patchedEe.removeListener('test', handler); assert.strictEqual(patchedEe.listeners('test').length, 0); - contextManager.enable(); return done(); }; patchedEe.on('test', handler); @@ -417,30 +332,12 @@ describe('AsyncHooksContextManager', () => { patchedEe.emit('test'); }); - it('should not return current context (when disabled + async op)', done => { - contextManager.disable(); - const ee = new EventEmitter(); - const context = Context.ROOT_CONTEXT.setValue(key1, 1); - const patchedEe = contextManager.bind(ee, context); - const handler = () => { - setImmediate(() => { - assert.deepStrictEqual(contextManager.active(), Context.ROOT_CONTEXT); - patchedEe.removeAllListeners('test'); - assert.strictEqual(patchedEe.listeners('test').length, 0); - return done(); - }); - }; - patchedEe.on('test', handler); - assert.strictEqual(patchedEe.listeners('test').length, 1); - patchedEe.emit('test'); - }); - - it('should return current context (when enabled + async op)', done => { - contextManager.enable(); + it('should not return current context with async op', done => { const ee = new EventEmitter(); const context = Context.ROOT_CONTEXT.setValue(key1, 1); const patchedEe = contextManager.bind(ee, context); const handler = () => { + assert.deepStrictEqual(contextManager.active(), context); setImmediate(() => { assert.deepStrictEqual(contextManager.active(), context); patchedEe.removeAllListeners('test'); diff --git a/packages/opentelemetry-context-base/package.json b/packages/opentelemetry-context-base/package.json index 09d6b82ea6..9a50b03657 100644 --- a/packages/opentelemetry-context-base/package.json +++ b/packages/opentelemetry-context-base/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-base", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Base Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -44,7 +44,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "codecov": "^3.6.1", "gts": "^2.0.0", "mocha": "^7.1.2", diff --git a/packages/opentelemetry-context-base/src/version.ts b/packages/opentelemetry-context-base/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-context-base/src/version.ts +++ b/packages/opentelemetry-context-base/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index 0b6e768f34..eae4690edc 100644 --- a/packages/opentelemetry-context-zone-peer-dep/package.json +++ b/packages/opentelemetry-context-zone-peer-dep/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone-peer-dep", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Context Zone with peer dependency for zone.js", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -43,9 +43,9 @@ "devDependencies": { "@babel/core": "^7.6.0", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "@types/zone.js": "^0.5.12", "babel-loader": "^8.0.6", "codecov": "^3.6.1", @@ -70,7 +70,7 @@ "zone.js": "^0.10.2" }, "dependencies": { - "@opentelemetry/context-base": "^0.8.2" + "@opentelemetry/context-base": "^0.8.3" }, "peerDependencies": { "zone.js": "^0.10.2" diff --git a/packages/opentelemetry-context-zone-peer-dep/src/version.ts b/packages/opentelemetry-context-zone-peer-dep/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/version.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-context-zone-peer-dep/tsconfig.json b/packages/opentelemetry-context-zone-peer-dep/tsconfig.json index ab49dd3fbd..33ecce9d6d 100644 --- a/packages/opentelemetry-context-zone-peer-dep/tsconfig.json +++ b/packages/opentelemetry-context-zone-peer-dep/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.base", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "skipLibCheck": true }, "files": [ "node_modules/zone.js/dist/zone.js.d.ts"], "include": [ diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index 777e8dd2cd..6b09dfc59d 100644 --- a/packages/opentelemetry-context-zone/package.json +++ b/packages/opentelemetry-context-zone/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Context Zone", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -40,9 +40,9 @@ "devDependencies": { "@babel/core": "^7.6.0", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "babel-loader": "^8.0.6", "codecov": "^3.6.1", "gts": "^2.0.0", @@ -64,7 +64,7 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/context-zone-peer-dep": "^0.8.2", + "@opentelemetry/context-zone-peer-dep": "^0.8.3", "zone.js": "^0.10.2" }, "sideEffects": true diff --git a/packages/opentelemetry-context-zone/src/version.ts b/packages/opentelemetry-context-zone/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-context-zone/src/version.ts +++ b/packages/opentelemetry-context-zone/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-context-zone/tsconfig.json b/packages/opentelemetry-context-zone/tsconfig.json index ab49dd3fbd..33ecce9d6d 100644 --- a/packages/opentelemetry-context-zone/tsconfig.json +++ b/packages/opentelemetry-context-zone/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.base", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "skipLibCheck": true }, "files": [ "node_modules/zone.js/dist/zone.js.d.ts"], "include": [ diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 138ccdb527..25778b9309 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/core", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Core provides default and no-op implementations of the OpenTelemetry types for trace and metrics", "main": "build/src/index.js", "browser": { @@ -52,10 +52,10 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/semver": "^6.2.0", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "codecov": "^3.6.1", "gts": "^2.0.0", "istanbul-instrumenter-loader": "^3.0.1", @@ -76,8 +76,8 @@ "webpack": "^4.35.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", "semver": "^7.1.3" } } diff --git a/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts index 398ebb58df..04e455e889 100644 --- a/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts +++ b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { Sampler, SpanContext, TraceFlags } from '@opentelemetry/api'; +import { + Sampler, + SpanContext, + TraceFlags, + SamplingDecision, +} from '@opentelemetry/api'; /** Sampler that samples a given fraction of traces. */ export class ProbabilitySampler implements Sampler { @@ -25,13 +30,19 @@ export class ProbabilitySampler implements Sampler { shouldSample(parentContext?: SpanContext) { // Respect the parent sampling decision if there is one if (parentContext && typeof parentContext.traceFlags !== 'undefined') { - return ( - (TraceFlags.SAMPLED & parentContext.traceFlags) === TraceFlags.SAMPLED - ); + return { + decision: + (TraceFlags.SAMPLED & parentContext.traceFlags) === TraceFlags.SAMPLED + ? SamplingDecision.RECORD_AND_SAMPLED + : SamplingDecision.NOT_RECORD, + }; } - if (this._probability >= 1.0) return true; - else if (this._probability <= 0) return false; - return Math.random() < this._probability; + return { + decision: + Math.random() < this._probability + ? SamplingDecision.RECORD_AND_SAMPLED + : SamplingDecision.NOT_RECORD, + }; } toString(): string { diff --git a/packages/opentelemetry-core/src/version.ts b/packages/opentelemetry-core/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-core/src/version.ts +++ b/packages/opentelemetry-core/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts index b0426899a2..c6d7baed45 100644 --- a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts +++ b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts @@ -15,6 +15,7 @@ */ import * as assert from 'assert'; +import * as api from '@opentelemetry/api'; import { ProbabilitySampler, ALWAYS_SAMPLER, @@ -24,60 +25,82 @@ import { describe('ProbabilitySampler', () => { it('should return a always sampler for 1', () => { const sampler = new ProbabilitySampler(1); - assert.strictEqual(sampler.shouldSample(), true); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.RECORD_AND_SAMPLED, + }); }); it('should return a always sampler for >1', () => { const sampler = new ProbabilitySampler(100); - assert.strictEqual(sampler.shouldSample(), true); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.RECORD_AND_SAMPLED, + }); assert.strictEqual(sampler.toString(), 'ProbabilitySampler{1}'); }); it('should return a never sampler for 0', () => { const sampler = new ProbabilitySampler(0); - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); }); it('should return a never sampler for <0', () => { const sampler = new ProbabilitySampler(-1); - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); }); it('should sample according to the probability', () => { Math.random = () => 1 / 10; const sampler = new ProbabilitySampler(0.2); - assert.strictEqual(sampler.shouldSample(), true); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.RECORD_AND_SAMPLED, + }); assert.strictEqual(sampler.toString(), 'ProbabilitySampler{0.2}'); Math.random = () => 5 / 10; - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); }); - it('should return true for ALWAYS_SAMPLER', () => { - assert.strictEqual(ALWAYS_SAMPLER.shouldSample(), true); + it('should return api.SamplingDecision.RECORD_AND_SAMPLED for ALWAYS_SAMPLER', () => { + assert.deepStrictEqual(ALWAYS_SAMPLER.shouldSample(), { + decision: api.SamplingDecision.RECORD_AND_SAMPLED, + }); assert.strictEqual(ALWAYS_SAMPLER.toString(), 'ProbabilitySampler{1}'); }); - it('should return false for NEVER_SAMPLER', () => { - assert.strictEqual(NEVER_SAMPLER.shouldSample(), false); + it('should return decision: api.SamplingDecision.NOT_RECORD for NEVER_SAMPLER', () => { + assert.deepStrictEqual(NEVER_SAMPLER.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); assert.strictEqual(NEVER_SAMPLER.toString(), 'ProbabilitySampler{0}'); }); it('should handle NaN', () => { const sampler = new ProbabilitySampler(NaN); - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); assert.strictEqual(sampler.toString(), 'ProbabilitySampler{0}'); }); it('should handle -NaN', () => { const sampler = new ProbabilitySampler(-NaN); - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); assert.strictEqual(sampler.toString(), 'ProbabilitySampler{0}'); }); it('should handle undefined', () => { const sampler = new ProbabilitySampler(undefined); - assert.strictEqual(sampler.shouldSample(), false); + assert.deepStrictEqual(sampler.shouldSample(), { + decision: api.SamplingDecision.NOT_RECORD, + }); assert.strictEqual(sampler.toString(), 'ProbabilitySampler{0}'); }); }); diff --git a/packages/opentelemetry-exporter-collector/package.json b/packages/opentelemetry-exporter-collector/package.json index 07cbe3eb42..4cb6bb73a2 100644 --- a/packages/opentelemetry-exporter-collector/package.json +++ b/packages/opentelemetry-exporter-collector/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-collector", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -55,9 +55,9 @@ "devDependencies": { "@babel/core": "^7.6.0", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "babel-loader": "^8.0.6", "codecov": "^3.1.0", "cpx": "^1.5.0", @@ -83,10 +83,10 @@ }, "dependencies": { "@grpc/proto-loader": "^0.5.3", - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/resources": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/resources": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "google-protobuf": "^3.11.4", "grpc": "^1.24.2" } diff --git a/packages/opentelemetry-exporter-collector/src/transform.ts b/packages/opentelemetry-exporter-collector/src/transform.ts index 0d945fe979..1e60930c38 100644 --- a/packages/opentelemetry-exporter-collector/src/transform.ts +++ b/packages/opentelemetry-exporter-collector/src/transform.ts @@ -28,7 +28,7 @@ import { CollectorExporterBase, CollectorExporterConfigBase, } from './CollectorExporterBase'; -import { COLLETOR_SPAN_KIND_MAPPING, opentelemetryProto } from './types'; +import { COLLECTOR_SPAN_KIND_MAPPING, opentelemetryProto } from './types'; import ValueType = opentelemetryProto.common.v1.ValueType; /** @@ -172,7 +172,7 @@ export function toCollectorResource( export function toCollectorKind( kind: SpanKind ): opentelemetryProto.trace.v1.Span.SpanKind { - const collectorKind = COLLETOR_SPAN_KIND_MAPPING[kind]; + const collectorKind = COLLECTOR_SPAN_KIND_MAPPING[kind]; return typeof collectorKind === 'number' ? collectorKind : opentelemetryProto.trace.v1.Span.SpanKind.SPAN_KIND_UNSPECIFIED; diff --git a/packages/opentelemetry-exporter-collector/src/types.ts b/packages/opentelemetry-exporter-collector/src/types.ts index 81a6b908ea..96fc2e13c0 100644 --- a/packages/opentelemetry-exporter-collector/src/types.ts +++ b/packages/opentelemetry-exporter-collector/src/types.ts @@ -173,7 +173,7 @@ export interface CollectorExporterError { /** * Mapping between api SpanKind and proto SpanKind */ -export const COLLETOR_SPAN_KIND_MAPPING = { +export const COLLECTOR_SPAN_KIND_MAPPING = { [SpanKind.INTERNAL]: opentelemetryProto.trace.v1.Span.SpanKind.INTERNAL, [SpanKind.SERVER]: opentelemetryProto.trace.v1.Span.SpanKind.SERVER, [SpanKind.CLIENT]: opentelemetryProto.trace.v1.Span.SpanKind.CLIENT, diff --git a/packages/opentelemetry-exporter-collector/src/version.ts b/packages/opentelemetry-exporter-collector/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-exporter-collector/src/version.ts +++ b/packages/opentelemetry-exporter-collector/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index e87194d7fe..8723e39d3d 100644 --- a/packages/opentelemetry-exporter-jaeger/package.json +++ b/packages/opentelemetry-exporter-jaeger/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-jaeger", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Exporter Jaeger allows user to send collected traces to Jaeger", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,9 +41,9 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/resources": "^0.8.2", + "@opentelemetry/resources": "^0.8.3", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "codecov": "^3.6.1", "gts": "^2.0.0", "mocha": "^7.1.2", @@ -55,9 +55,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "jaeger-client": "^3.15.0" } } diff --git a/packages/opentelemetry-exporter-jaeger/src/version.ts b/packages/opentelemetry-exporter-jaeger/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-exporter-jaeger/src/version.ts +++ b/packages/opentelemetry-exporter-jaeger/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-exporter-prometheus/package.json b/packages/opentelemetry-exporter-prometheus/package.json index 9a15cf9241..6bd21df008 100644 --- a/packages/opentelemetry-exporter-prometheus/package.json +++ b/packages/opentelemetry-exporter-prometheus/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-prometheus", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Exporter Prometheus provides a metrics endpoint for Prometheus", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,7 +41,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "codecov": "^3.6.1", "gts": "^2.0.0", "mocha": "^7.1.2", @@ -52,9 +52,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/metrics": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/metrics": "^0.8.3", "prom-client": "^11.5.3" } } diff --git a/packages/opentelemetry-exporter-prometheus/src/version.ts b/packages/opentelemetry-exporter-prometheus/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-exporter-prometheus/src/version.ts +++ b/packages/opentelemetry-exporter-prometheus/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index a587ca1471..8143c9b94c 100644 --- a/packages/opentelemetry-exporter-zipkin/package.json +++ b/packages/opentelemetry-exporter-zipkin/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-zipkin", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Zipkin Exporter allows the user to send collected traces to Zipkin.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -40,7 +40,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "codecov": "^3.6.1", "gts": "^2.0.0", "mocha": "^7.1.2", @@ -52,9 +52,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/resources": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/resources": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" } } diff --git a/packages/opentelemetry-exporter-zipkin/src/version.ts b/packages/opentelemetry-exporter-zipkin/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-exporter-zipkin/src/version.ts +++ b/packages/opentelemetry-exporter-zipkin/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-metrics/README.md b/packages/opentelemetry-metrics/README.md index 1de26eab56..340f3ee657 100644 --- a/packages/opentelemetry-metrics/README.md +++ b/packages/opentelemetry-metrics/README.md @@ -73,8 +73,11 @@ setInterval(()=> { See [examples/prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/prometheus) for a short example. -### Measure -***Work in progress*** +### Value Recorder + +`ValueRecorder` is a non-additive synchronous instrument useful for recording any non-additive number, positive or negative. +Values captured by `ValueRecorder.record(value)` are treated as individual events belonging to a distribution that is being summarized. +`ValueRecorder` should be chosen either when capturing measurements that do not contribute meaningfully to a sum, or when capturing numbers that are additive in nature, but where the distribution of individual increments is considered interesting. ## Useful links - For more information on OpenTelemetry, visit: diff --git a/packages/opentelemetry-metrics/package.json b/packages/opentelemetry-metrics/package.json index fcddbfc616..65d06c8a51 100644 --- a/packages/opentelemetry-metrics/package.json +++ b/packages/opentelemetry-metrics/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/metrics", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry metrics SDK", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -42,7 +42,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", "codecov": "^3.6.1", "gts": "^2.0.0", @@ -55,8 +55,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/resources": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/resources": "^0.8.3" } } diff --git a/packages/opentelemetry-metrics/src/BoundInstrument.ts b/packages/opentelemetry-metrics/src/BoundInstrument.ts index d451bcb601..8f660c3722 100644 --- a/packages/opentelemetry-metrics/src/BoundInstrument.ts +++ b/packages/opentelemetry-metrics/src/BoundInstrument.ts @@ -93,10 +93,10 @@ export class BoundCounter extends BaseBoundInstrument } /** - * BoundMeasure is an implementation of the {@link BoundMeasure} interface. + * BoundValueRecorder is an implementation of the {@link BoundValueRecorder} interface. */ -export class BoundMeasure extends BaseBoundInstrument - implements api.BoundMeasure { +export class BoundValueRecorder extends BaseBoundInstrument + implements api.BoundValueRecorder { private readonly _absolute: boolean; constructor( @@ -119,7 +119,7 @@ export class BoundMeasure extends BaseBoundInstrument ): void { if (this._absolute && value < 0) { this._logger.error( - `Absolute measure cannot contain negative values for $${Object.values( + `Absolute ValueRecorder cannot contain negative values for $${Object.values( this._labels )}` ); diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts index a13679aeb6..dd760cc5a2 100644 --- a/packages/opentelemetry-metrics/src/Meter.ts +++ b/packages/opentelemetry-metrics/src/Meter.ts @@ -18,7 +18,12 @@ import * as api from '@opentelemetry/api'; import { ConsoleLogger } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { BaseBoundInstrument } from './BoundInstrument'; -import { Metric, CounterMetric, MeasureMetric, ObserverMetric } from './Metric'; +import { + Metric, + CounterMetric, + ValueRecorderMetric, + ObserverMetric, +} from './Metric'; import { MetricOptions, DEFAULT_METRIC_OPTIONS, @@ -52,28 +57,36 @@ export class Meter implements api.Meter { } /** - * Creates and returns a new {@link Measure}. + * Creates and returns a new {@link ValueRecorder}. * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure(name: string, options?: api.MetricOptions): api.Measure { + createValueRecorder( + name: string, + options?: api.MetricOptions + ): api.ValueRecorder { if (!this._isValidName(name)) { this._logger.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return api.NOOP_MEASURE_METRIC; + return api.NOOP_VALUE_RECORDER_METRIC; } const opt: MetricOptions = { - absolute: true, // Measures are defined as absolute by default - monotonic: false, // not applicable to measure, set to false + absolute: true, // value recorders are defined as absolute by default + monotonic: false, // not applicable to value recorder, set to false logger: this._logger, ...DEFAULT_METRIC_OPTIONS, ...options, }; - const measure = new MeasureMetric(name, opt, this._batcher, this._resource); - this._registerMetric(name, measure); - return measure; + const valueRecorder = new ValueRecorderMetric( + name, + opt, + this._batcher, + this._resource + ); + this._registerMetric(name, valueRecorder); + return valueRecorder; } /** diff --git a/packages/opentelemetry-metrics/src/Metric.ts b/packages/opentelemetry-metrics/src/Metric.ts index 9547d210e3..dd52fd9f3c 100644 --- a/packages/opentelemetry-metrics/src/Metric.ts +++ b/packages/opentelemetry-metrics/src/Metric.ts @@ -19,7 +19,7 @@ import { Resource } from '@opentelemetry/resources'; import { BoundCounter, BaseBoundInstrument, - BoundMeasure, + BoundValueRecorder, BoundObserver, } from './BoundInstrument'; import { ObserverResult } from './ObserverResult'; @@ -139,7 +139,8 @@ export class CounterMetric extends Metric implements api.Counter { } } -export class MeasureMetric extends Metric implements api.Measure { +export class ValueRecorderMetric extends Metric + implements api.ValueRecorder { protected readonly _absolute: boolean; constructor( @@ -148,12 +149,12 @@ export class MeasureMetric extends Metric implements api.Measure { private readonly _batcher: Batcher, resource: Resource ) { - super(name, options, MetricKind.MEASURE, resource); + super(name, options, MetricKind.VALUE_RECORDER, resource); this._absolute = options.absolute !== undefined ? options.absolute : true; // Absolute default is true } - protected _makeInstrument(labels: api.Labels): BoundMeasure { - return new BoundMeasure( + protected _makeInstrument(labels: api.Labels): BoundValueRecorder { + return new BoundValueRecorder( labels, this._disabled, this._monotonic, diff --git a/packages/opentelemetry-metrics/src/export/Batcher.ts b/packages/opentelemetry-metrics/src/export/Batcher.ts index 7b2fbd417f..2bb6eb9d1a 100644 --- a/packages/opentelemetry-metrics/src/export/Batcher.ts +++ b/packages/opentelemetry-metrics/src/export/Batcher.ts @@ -16,7 +16,7 @@ import { CounterSumAggregator, - MeasureExactAggregator, + ValueRecorderExactAggregator, ObserverAggregator, } from './aggregators'; import { @@ -59,7 +59,7 @@ export class UngroupedBatcher extends Batcher { case MetricKind.OBSERVER: return new ObserverAggregator(); default: - return new MeasureExactAggregator(); + return new ValueRecorderExactAggregator(); } } diff --git a/packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts b/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts similarity index 95% rename from packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts rename to packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts index abbad0b430..0e70a5792e 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts @@ -20,7 +20,7 @@ import { hrTime } from '@opentelemetry/core'; import { Distribution } from '../types'; /** Basic aggregator keeping all raw values (events, sum, max and min). */ -export class MeasureExactAggregator implements Aggregator { +export class ValueRecorderExactAggregator implements Aggregator { private _distribution: Distribution; private _lastUpdateTime: HrTime = [0, 0]; diff --git a/packages/opentelemetry-metrics/src/export/aggregators/index.ts b/packages/opentelemetry-metrics/src/export/aggregators/index.ts index 938e1ad6e3..7d1bd01d7d 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/index.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/index.ts @@ -16,5 +16,5 @@ export * from './countersum'; export * from './observer'; -export * from './measureexact'; +export * from './ValueRecorderExact'; export * from './histogram'; diff --git a/packages/opentelemetry-metrics/src/export/types.ts b/packages/opentelemetry-metrics/src/export/types.ts index 0fe741905e..8a34a34d1b 100644 --- a/packages/opentelemetry-metrics/src/export/types.ts +++ b/packages/opentelemetry-metrics/src/export/types.ts @@ -21,7 +21,7 @@ import { Resource } from '@opentelemetry/resources'; /** The kind of metric. */ export enum MetricKind { COUNTER, - MEASURE, + VALUE_RECORDER, OBSERVER, } diff --git a/packages/opentelemetry-metrics/src/types.ts b/packages/opentelemetry-metrics/src/types.ts index 8927a80830..b5ba841e68 100644 --- a/packages/opentelemetry-metrics/src/types.ts +++ b/packages/opentelemetry-metrics/src/types.ts @@ -43,7 +43,7 @@ export interface MetricOptions { /** Monotonic metrics may only increase. */ monotonic: boolean; - /** (Measure only) Asserts that this metric will only accept non-negative values. */ + /** (ValueRecorder only) Asserts that this metric will only accept non-negative values. */ absolute: boolean; /** User provided logger. */ diff --git a/packages/opentelemetry-metrics/src/version.ts b/packages/opentelemetry-metrics/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-metrics/src/version.ts +++ b/packages/opentelemetry-metrics/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-metrics/test/Meter.test.ts b/packages/opentelemetry-metrics/test/Meter.test.ts index 5826f09a90..93244aca35 100644 --- a/packages/opentelemetry-metrics/test/Meter.test.ts +++ b/packages/opentelemetry-metrics/test/Meter.test.ts @@ -22,7 +22,7 @@ import { MetricKind, Sum, MeterProvider, - MeasureMetric, + ValueRecorderMetric, Distribution, ObserverMetric, MetricRecord, @@ -268,82 +268,94 @@ describe('Meter', () => { }); }); - describe('#measure', () => { - it('should create a measure', () => { - const measure = meter.createMeasure('name'); - assert.ok(measure instanceof Metric); + describe('#ValueRecorder', () => { + it('should create a valueRecorder', () => { + const valueRecorder = meter.createValueRecorder('name'); + assert.ok(valueRecorder instanceof Metric); }); - it('should create a measure with options', () => { - const measure = meter.createMeasure('name', { + it('should create a valueRecorder with options', () => { + const valueRecorder = meter.createValueRecorder('name', { description: 'desc', unit: '1', disabled: false, }); - assert.ok(measure instanceof Metric); + assert.ok(valueRecorder instanceof Metric); }); it('should be absolute by default', () => { - const measure = meter.createMeasure('name', { + const valueRecorder = meter.createValueRecorder('name', { description: 'desc', unit: '1', disabled: false, }); - assert.strictEqual((measure as MeasureMetric)['_absolute'], true); + assert.strictEqual( + (valueRecorder as ValueRecorderMetric)['_absolute'], + true + ); }); it('should be able to set absolute to false', () => { - const measure = meter.createMeasure('name', { + const valueRecorder = meter.createValueRecorder('name', { description: 'desc', unit: '1', disabled: false, absolute: false, }); - assert.strictEqual((measure as MeasureMetric)['_absolute'], false); + assert.strictEqual( + (valueRecorder as ValueRecorderMetric)['_absolute'], + false + ); }); it('should pipe through resource', () => { - const measure = meter.createMeasure('name') as MeasureMetric; - assert.ok(measure.resource instanceof Resource); + const valueRecorder = meter.createValueRecorder( + 'name' + ) as ValueRecorderMetric; + assert.ok(valueRecorder.resource instanceof Resource); - measure.record(1, { foo: 'bar' }); + valueRecorder.record(1, { foo: 'bar' }); - const [record] = measure.getMetricRecord(); + const [record] = valueRecorder.getMetricRecord(); assert.ok(record.resource instanceof Resource); }); describe('names', () => { it('should return no op metric if name is an empty string', () => { - const measure = meter.createMeasure(''); - assert.ok(measure instanceof api.NoopMetric); + const valueRecorder = meter.createValueRecorder(''); + assert.ok(valueRecorder instanceof api.NoopMetric); }); it('should return no op metric if name does not start with a letter', () => { - const measure1 = meter.createMeasure('1name'); - const measure_ = meter.createMeasure('_name'); - assert.ok(measure1 instanceof api.NoopMetric); - assert.ok(measure_ instanceof api.NoopMetric); + const valueRecorder1 = meter.createValueRecorder('1name'); + const valueRecorder_ = meter.createValueRecorder('_name'); + assert.ok(valueRecorder1 instanceof api.NoopMetric); + assert.ok(valueRecorder_ instanceof api.NoopMetric); }); it('should return no op metric if name is an empty string contain only letters, numbers, ".", "_", and "-"', () => { - const measure = meter.createMeasure('name with invalid characters^&*('); - assert.ok(measure instanceof api.NoopMetric); + const valueRecorder = meter.createValueRecorder( + 'name with invalid characters^&*(' + ); + assert.ok(valueRecorder instanceof api.NoopMetric); }); }); describe('.bind()', () => { const performanceTimeOrigin = hrTime(); - it('should create a measure instrument', () => { - const measure = meter.createMeasure('name') as MeasureMetric; - const boundMeasure = measure.bind(labels); - assert.doesNotThrow(() => boundMeasure.record(10)); + it('should create a valueRecorder instrument', () => { + const valueRecorder = meter.createValueRecorder( + 'name' + ) as ValueRecorderMetric; + const boundValueRecorder = valueRecorder.bind(labels); + assert.doesNotThrow(() => boundValueRecorder.record(10)); }); it('should not accept negative values by default', () => { - const measure = meter.createMeasure('name'); - const boundMeasure = measure.bind(labels); - boundMeasure.record(-10); + const valueRecorder = meter.createValueRecorder('name'); + const boundValueRecorder = valueRecorder.bind(labels); + boundValueRecorder.record(-10); meter.collect(); const [record1] = meter.getBatcher().checkPointSet(); @@ -359,11 +371,11 @@ describe('Meter', () => { }); it('should not set the instrument data when disabled', () => { - const measure = meter.createMeasure('name', { + const valueRecorder = meter.createValueRecorder('name', { disabled: true, - }) as MeasureMetric; - const boundMeasure = measure.bind(labels); - boundMeasure.record(10); + }) as ValueRecorderMetric; + const boundValueRecorder = valueRecorder.bind(labels); + boundValueRecorder.record(10); meter.collect(); const [record1] = meter.getBatcher().checkPointSet(); @@ -379,12 +391,12 @@ describe('Meter', () => { }); it('should accept negative (and positive) values when absolute is set to false', () => { - const measure = meter.createMeasure('name', { + const valueRecorder = meter.createValueRecorder('name', { absolute: false, }); - const boundMeasure = measure.bind(labels); - boundMeasure.record(-10); - boundMeasure.record(50); + const boundValueRecorder = valueRecorder.bind(labels); + boundValueRecorder.record(-10); + boundValueRecorder.record(50); meter.collect(); const [record1] = meter.getBatcher().checkPointSet(); @@ -404,11 +416,13 @@ describe('Meter', () => { }); it('should return same instrument on same label values', () => { - const measure = meter.createMeasure('name') as MeasureMetric; - const boundMeasure1 = measure.bind(labels); - boundMeasure1.record(10); - const boundMeasure2 = measure.bind(labels); - boundMeasure2.record(100); + const valueRecorder = meter.createValueRecorder( + 'name' + ) as ValueRecorderMetric; + const boundValueRecorder1 = valueRecorder.bind(labels); + boundValueRecorder1.record(10); + const boundValueRecorder2 = valueRecorder.bind(labels); + boundValueRecorder2.record(100); meter.collect(); const [record1] = meter.getBatcher().checkPointSet(); assert.deepStrictEqual( @@ -420,54 +434,58 @@ describe('Meter', () => { sum: 110, } ); - assert.strictEqual(boundMeasure1, boundMeasure2); + assert.strictEqual(boundValueRecorder1, boundValueRecorder2); }); }); describe('.unbind()', () => { - it('should remove the measure instrument', () => { - const measure = meter.createMeasure('name') as MeasureMetric; - const boundMeasure = measure.bind(labels); - assert.strictEqual(measure['_instruments'].size, 1); - measure.unbind(labels); - assert.strictEqual(measure['_instruments'].size, 0); - const boundMeasure2 = measure.bind(labels); - assert.strictEqual(measure['_instruments'].size, 1); - assert.notStrictEqual(boundMeasure, boundMeasure2); + it('should remove the valueRecorder instrument', () => { + const valueRecorder = meter.createValueRecorder( + 'name' + ) as ValueRecorderMetric; + const boundValueRecorder = valueRecorder.bind(labels); + assert.strictEqual(valueRecorder['_instruments'].size, 1); + valueRecorder.unbind(labels); + assert.strictEqual(valueRecorder['_instruments'].size, 0); + const boundValueRecorder2 = valueRecorder.bind(labels); + assert.strictEqual(valueRecorder['_instruments'].size, 1); + assert.notStrictEqual(boundValueRecorder, boundValueRecorder2); }); it('should not fail when removing non existing instrument', () => { - const measure = meter.createMeasure('name'); - measure.unbind({}); + const valueRecorder = meter.createValueRecorder('name'); + valueRecorder.unbind({}); }); it('should clear all instruments', () => { - const measure = meter.createMeasure('name') as MeasureMetric; - measure.bind(labels); - assert.strictEqual(measure['_instruments'].size, 1); - measure.clear(); - assert.strictEqual(measure['_instruments'].size, 0); + const valueRecorder = meter.createValueRecorder( + 'name' + ) as ValueRecorderMetric; + valueRecorder.bind(labels); + assert.strictEqual(valueRecorder['_instruments'].size, 1); + valueRecorder.clear(); + assert.strictEqual(valueRecorder['_instruments'].size, 0); }); }); }); describe('#observer', () => { it('should create an observer', () => { - const measure = meter.createObserver('name') as ObserverMetric; - assert.ok(measure instanceof Metric); + const valueRecorder = meter.createObserver('name') as ObserverMetric; + assert.ok(valueRecorder instanceof Metric); }); it('should create observer with options', () => { - const measure = meter.createObserver('name', { + const valueRecorder = meter.createObserver('name', { description: 'desc', unit: '1', disabled: false, }) as ObserverMetric; - assert.ok(measure instanceof Metric); + assert.ok(valueRecorder instanceof Metric); }); it('should set callback and observe value ', () => { - const measure = meter.createObserver('name', { + const valueRecorder = meter.createObserver('name', { description: 'desc', labelKeys: ['pid', 'core'], }) as ObserverMetric; @@ -478,7 +496,7 @@ describe('Meter', () => { const metricObservable = new MetricObservable(); - measure.setCallback((observerResult: api.ObserverResult) => { + valueRecorder.setCallback((observerResult: api.ObserverResult) => { observerResult.observe(getCpuUsage, { pid: '123', core: '1' }); observerResult.observe(getCpuUsage, { pid: '123', core: '2' }); observerResult.observe(getCpuUsage, { pid: '123', core: '3' }); @@ -488,7 +506,7 @@ describe('Meter', () => { metricObservable.next(0.123); - const metricRecords: MetricRecord[] = measure.getMetricRecord(); + const metricRecords: MetricRecord[] = valueRecorder.getMetricRecord(); assert.strictEqual(metricRecords.length, 5); const metric5 = metricRecords[0]; @@ -587,8 +605,8 @@ describe('Meter', () => { batcher: new CustomBatcher(), }); assert.throws(() => { - const measure = customMeter.createMeasure('myMeasure'); - measure.bind({}).record(1); + const valueRecorder = customMeter.createValueRecorder('myValueRecorder'); + valueRecorder.bind({}).record(1); }, /aggregatorFor method not implemented/); }); }); diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 05a194c83b..8d2db882ff 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/node", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Node SDK provides automatic telemetry (tracing, metrics, etc) for Node.js applications", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,10 +41,10 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/resources": "^0.8.2", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/resources": "^0.8.3", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/semver": "^6.0.1", "@types/shimmer": "^1.0.1", "codecov": "^3.6.1", @@ -58,10 +58,10 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/context-async-hooks": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/context-async-hooks": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "require-in-the-middle": "^5.0.0", "semver": "^7.1.3" } diff --git a/packages/opentelemetry-node/src/version.ts b/packages/opentelemetry-node/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-node/src/version.ts +++ b/packages/opentelemetry-node/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-grpc/package.json b/packages/opentelemetry-plugin-grpc/package.json index bdddc970fc..9f60263ffa 100644 --- a/packages/opentelemetry-plugin-grpc/package.json +++ b/packages/opentelemetry-plugin-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugin-grpc", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry grpc automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,12 +41,12 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/context-async-hooks": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/semver": "^7.1.0", "@types/shimmer": "^1.0.1", "@types/sinon": "^7.0.13", @@ -64,8 +64,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", "shimmer": "^1.2.1" } } diff --git a/packages/opentelemetry-plugin-grpc/src/version.ts b/packages/opentelemetry-plugin-grpc/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-plugin-grpc/src/version.ts +++ b/packages/opentelemetry-plugin-grpc/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-http/package.json b/packages/opentelemetry-plugin-http/package.json index deecba25c2..0cb80e7e45 100644 --- a/packages/opentelemetry-plugin-http/package.json +++ b/packages/opentelemetry-plugin-http/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugin-http", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry http automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,13 +41,13 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/context-async-hooks": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "@types/got": "^9.6.7", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/request-promise-native": "^1.0.17", "@types/semver": "^6.0.2", "@types/shimmer": "^1.0.1", @@ -71,8 +71,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", "semver": "^7.1.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-http/src/version.ts b/packages/opentelemetry-plugin-http/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-plugin-http/src/version.ts +++ b/packages/opentelemetry-plugin-http/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-https/package.json b/packages/opentelemetry-plugin-https/package.json index 09c29c1efd..b842f52d42 100644 --- a/packages/opentelemetry-plugin-https/package.json +++ b/packages/opentelemetry-plugin-https/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugin-https", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry https automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,13 +41,13 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/node": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/context-async-hooks": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "@types/got": "^9.6.7", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/request-promise-native": "^1.0.17", "@types/semver": "^6.0.2", "@types/shimmer": "^1.0.1", @@ -70,9 +70,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/plugin-http": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/plugin-http": "^0.8.3", "semver": "^7.1.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-https/src/version.ts b/packages/opentelemetry-plugin-https/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-plugin-https/src/version.ts +++ b/packages/opentelemetry-plugin-https/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-xml-http-request/package.json b/packages/opentelemetry-plugin-xml-http-request/package.json index 3166e09cc1..5c0bda5fd3 100644 --- a/packages/opentelemetry-plugin-xml-http-request/package.json +++ b/packages/opentelemetry-plugin-xml-http-request/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/plugin-xml-http-request", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry XMLHttpRequest automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -44,13 +44,13 @@ }, "devDependencies": { "@babel/core": "^7.6.0", - "@opentelemetry/context-zone": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/context-zone": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/shimmer": "^1.0.1", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "babel-loader": "^8.0.6", "codecov": "^3.1.0", "gts": "^2.0.0", @@ -74,9 +74,9 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/web": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/web": "^0.8.3", "shimmer": "^1.2.1" } } diff --git a/packages/opentelemetry-plugin-xml-http-request/src/version.ts b/packages/opentelemetry-plugin-xml-http-request/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/version.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index 73e57b4812..eb6a55cbfe 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -256,7 +256,8 @@ export class XMLHttpRequestPlugin extends BasePlugin { // then OBSERVER_WAIT_TIME_MS and observer didn't collect enough // information resources = otperformance.getEntriesByType( - 'resource' + // ts thinks this is the perf_hooks module, but it is the browser performance api + 'resource' as any ) as PerformanceResourceTiming[]; } diff --git a/packages/opentelemetry-plugin-xml-http-request/tsconfig.json b/packages/opentelemetry-plugin-xml-http-request/tsconfig.json index a2042cd68b..71661a842e 100644 --- a/packages/opentelemetry-plugin-xml-http-request/tsconfig.json +++ b/packages/opentelemetry-plugin-xml-http-request/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.base", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "skipLibCheck": true }, "include": [ "src/**/*.ts", diff --git a/packages/opentelemetry-resources/README.md b/packages/opentelemetry-resources/README.md new file mode 100644 index 0000000000..1cc1785c2d --- /dev/null +++ b/packages/opentelemetry-resources/README.md @@ -0,0 +1,42 @@ +# OpenTelemetry Resources Util +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + +The OpenTelemetry Resource is an immutable representation of the entity producing telemetry. For example, a process producing telemetry that is running in a container on Kubernetes has a Pod name, it is in a namespace and possibly is part of a Deployment which also has a name. All three of these attributes can be included in the `Resource`. + +[This document][resource-semantic_conventions] defines standard attributes for resources. + +## Installation + +```bash +npm install --save @opentelemetry/resources +``` + +## Usage + +> TODO + +## Useful links +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us on [gitter][gitter-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-resources +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-resources +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/resources +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fresources.svg + +[resource-semantic_conventions]: https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/resource/semantic_conventions diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json index ac9267eca8..0efe9f8b0e 100644 --- a/packages/opentelemetry-resources/package.json +++ b/packages/opentelemetry-resources/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/resources", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry SDK resources", "main": "build/src/index.js", "browser": { @@ -45,7 +45,7 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", "codecov": "^3.6.1", "gts": "^2.0.0", @@ -59,8 +59,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", "gcp-metadata": "^3.5.0" } } diff --git a/packages/opentelemetry-resources/src/version.ts b/packages/opentelemetry-resources/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-resources/src/version.ts +++ b/packages/opentelemetry-resources/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-shim-opentracing/package.json b/packages/opentelemetry-shim-opentracing/package.json index 40b00235e0..7535f32bd2 100644 --- a/packages/opentelemetry-shim-opentracing/package.json +++ b/packages/opentelemetry-shim-opentracing/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/shim-opentracing", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTracing to OpenTelemetry shim", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -39,9 +39,9 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/tracing": "^0.8.2", + "@opentelemetry/tracing": "^0.8.3", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "codecov": "^3.6.1", "gts": "^2.0.0", "mocha": "^7.1.2", @@ -54,8 +54,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/core": "^0.8.2", + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", "opentracing": "^0.14.4" } } diff --git a/packages/opentelemetry-shim-opentracing/src/version.ts b/packages/opentelemetry-shim-opentracing/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-shim-opentracing/src/version.ts +++ b/packages/opentelemetry-shim-opentracing/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-tracing/package.json b/packages/opentelemetry-tracing/package.json index cc2533224d..adac117a98 100644 --- a/packages/opentelemetry-tracing/package.json +++ b/packages/opentelemetry-tracing/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/tracing", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Tracing", "main": "build/src/index.js", "browser": { @@ -50,9 +50,9 @@ }, "devDependencies": { "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "codecov": "^3.6.1", "gts": "^2.0.0", "istanbul-instrumenter-loader": "^3.0.1", @@ -73,9 +73,9 @@ "webpack": "^4.35.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/resources": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/resources": "^0.8.3" } } diff --git a/packages/opentelemetry-tracing/src/Tracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts index 24408d80e4..dbedb8949c 100644 --- a/packages/opentelemetry-tracing/src/Tracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -66,8 +66,6 @@ export class Tracer implements api.Tracer { context = api.context.active() ): api.Span { const parentContext = getParent(options, context); - // make sampling decision - const samplingDecision = this._sampler.shouldSample(parentContext); const spanId = randomSpanId(); let traceId; let traceState; @@ -79,12 +77,26 @@ export class Tracer implements api.Tracer { traceId = parentContext.traceId; traceState = parentContext.traceState; } - const traceFlags = samplingDecision - ? api.TraceFlags.SAMPLED - : api.TraceFlags.NONE; + const spanKind = options.kind ?? api.SpanKind.INTERNAL; + const links = options.links ?? []; + const attributes = { ...this._defaultAttributes, ...options.attributes }; + // make sampling decision + const samplingResult = this._sampler.shouldSample( + parentContext, + traceId, + name, + spanKind, + attributes, + links + ); + + const traceFlags = + samplingResult.decision === api.SamplingDecision.RECORD_AND_SAMPLED + ? api.TraceFlags.SAMPLED + : api.TraceFlags.NONE; const spanContext = { traceId, spanId, traceFlags, traceState }; - if (!samplingDecision) { - this.logger.debug('Sampling is off, starting no recording span'); + if (samplingResult.decision === api.SamplingDecision.NOT_RECORD) { + this.logger.debug('Recording is off, starting no recording span'); return new NoRecordingSpan(spanContext); } @@ -92,15 +104,13 @@ export class Tracer implements api.Tracer { this, name, spanContext, - options.kind || api.SpanKind.INTERNAL, + spanKind, parentContext ? parentContext.spanId : undefined, - options.links || [], + links, options.startTime ); // Set default attributes - span.setAttributes( - Object.assign({}, this._defaultAttributes, options.attributes) - ); + span.setAttributes(Object.assign(attributes, samplingResult.attributes)); return span; } diff --git a/packages/opentelemetry-tracing/src/version.ts b/packages/opentelemetry-tracing/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-tracing/src/version.ts +++ b/packages/opentelemetry-tracing/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-tracing/test/Tracer.test.ts b/packages/opentelemetry-tracing/test/Tracer.test.ts new file mode 100644 index 0000000000..71b6aa569d --- /dev/null +++ b/packages/opentelemetry-tracing/test/Tracer.test.ts @@ -0,0 +1,63 @@ +/*! + * Copyright 2020, 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 * as assert from 'assert'; +import { NoopSpan, Sampler, SamplingDecision } from '@opentelemetry/api'; +import { BasicTracerProvider, Tracer, Span } from '../src'; +import { NoopLogger, ALWAYS_SAMPLER, NEVER_SAMPLER } from '@opentelemetry/core'; + +describe('Tracer', () => { + const tracerProvider = new BasicTracerProvider({ + logger: new NoopLogger(), + }); + + class TestSampler implements Sampler { + shouldSample() { + return { + decision: SamplingDecision.RECORD_AND_SAMPLED, + attributes: { + testAttribute: 'foobar', + }, + }; + } + } + + it('should create a Tracer instance', () => { + const tracer = new Tracer({}, tracerProvider); + assert.ok(tracer instanceof Tracer); + }); + + it('should respect NO_RECORD sampling result', () => { + const tracer = new Tracer({ sampler: NEVER_SAMPLER }, tracerProvider); + const span = tracer.startSpan('span1'); + assert.ok(span instanceof NoopSpan); + span.end(); + }); + + it('should respect RECORD_AND_SAMPLE sampling result', () => { + const tracer = new Tracer({ sampler: ALWAYS_SAMPLER }, tracerProvider); + const span = tracer.startSpan('span2'); + assert.ok(!(span instanceof NoopSpan)); + span.end(); + }); + + it('should start a span with attributes in sampling result', () => { + const tracer = new Tracer({ sampler: new TestSampler() }, tracerProvider); + const span = tracer.startSpan('span3'); + assert.strictEqual((span as Span).attributes.testAttribute, 'foobar'); + span.end(); + }); +}); diff --git a/packages/opentelemetry-web/package.json b/packages/opentelemetry-web/package.json index 3e1c8e1843..d6dbfb874d 100644 --- a/packages/opentelemetry-web/package.json +++ b/packages/opentelemetry-web/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/web", - "version": "0.8.2", + "version": "0.8.3", "description": "OpenTelemetry Web Tracer", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -43,13 +43,13 @@ }, "devDependencies": { "@babel/core": "^7.6.0", - "@opentelemetry/context-zone": "^0.8.2", - "@opentelemetry/resources": "^0.8.2", + "@opentelemetry/context-zone": "^0.8.3", + "@opentelemetry/resources": "^0.8.3", "@types/jquery": "^3.3.31", "@types/mocha": "^7.0.0", - "@types/node": "12.12.35", + "@types/node": "^14.0.5", "@types/sinon": "^7.0.13", - "@types/webpack-env": "1.13.9", + "@types/webpack-env": "1.15.2", "babel-loader": "^8.0.6", "codecov": "^3.6.1", "gts": "^2.0.0", @@ -74,9 +74,9 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/api": "^0.8.2", - "@opentelemetry/context-base": "^0.8.2", - "@opentelemetry/core": "^0.8.2", - "@opentelemetry/tracing": "^0.8.2" + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3" } } diff --git a/packages/opentelemetry-web/src/version.ts b/packages/opentelemetry-web/src/version.ts index d34e2cff6d..90d0ab01d0 100644 --- a/packages/opentelemetry-web/src/version.ts +++ b/packages/opentelemetry-web/src/version.ts @@ -15,4 +15,4 @@ */ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.8.2'; +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-web/tsconfig.json b/packages/opentelemetry-web/tsconfig.json index a2042cd68b..71661a842e 100644 --- a/packages/opentelemetry-web/tsconfig.json +++ b/packages/opentelemetry-web/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.base", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "skipLibCheck": true }, "include": [ "src/**/*.ts",