diff --git a/.circleci/config.yml b/.circleci/config.yml index 177e915a7fa..e1dc9feb5b4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,6 @@ cache_1: &cache_1 - ./node_modules - ./package-lock.json - packages/opentelemetry-api/node_modules - - packages/opentelemetry-base/node_modules - packages/opentelemetry-context-async-hooks/node_modules - packages/opentelemetry-context-base/node_modules - packages/opentelemetry-context-zone/node_modules @@ -190,6 +189,11 @@ jobs: - image: node:13 environment: *node_test_env <<: *node_unit_tests + node14: + docker: + - image: node:14 + environment: *node_test_env + <<: *node_unit_tests node12-browsers: docker: - image: circleci/node:12-browsers @@ -215,5 +219,6 @@ workflows: - node10 - node12 - node13 + - node14 - node12-browsers diff --git a/.gitmodules b/.gitmodules index 50b83a59cdb..bebf3ea829e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "packages/opentelemetry-exporter-collector/src/platform/node/protos"] path = packages/opentelemetry-exporter-collector/src/platform/node/protos - url = git@github.com:open-telemetry/opentelemetry-proto.git + url = https://github.com/open-telemetry/opentelemetry-proto.git diff --git a/CHANGELOG.md b/CHANGELOG.md index 51a03889d38..d4efa616c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,35 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 0.7.0 + +Released 2020-04-23 + +#### :boom: Breaking Change +* `opentelemetry-exporter-collector` + * [#901](https://github.com/open-telemetry/opentelemetry-js/pull/901) grpc for node and support for new proto format for node and browser ([@obecny](https://github.com/obecny)) +* `opentelemetry-api`, `opentelemetry-metrics` + * [#964](https://github.com/open-telemetry/opentelemetry-js/pull/964) chore: adding metric observable to be able to support async update ([@obecny](https://github.com/obecny)) + +#### :bug: (Bug Fix) +* `opentelemetry-plugin-http` + * [#960](https://github.com/open-telemetry/opentelemetry-js/pull/960) [http] fix: use url.URL ([@naseemkullah](https://github.com/naseemkullah)) +* `opentelemetry-core` + * [#977](https://github.com/open-telemetry/opentelemetry-js/pull/977) fix(B3Propagator): B3 sampled causing gRPC error ([@mayurkale22](https://github.com/mayurkale22)) + +#### :rocket: (Enhancement) +* `opentelemetry-resources` + * [#899](https://github.com/open-telemetry/opentelemetry-js/pull/899) feat: resource auto-detection ([@mwear](https://github.com/mwear)) +* `opentelemetry-metrics` + * [#930](https://github.com/open-telemetry/opentelemetry-js/pull/930) feat(aggregators): implement histogram aggregator ([@vmarchaud](https://github.com/vmarchaud)) + +#### Committers: 5 +- Naseem ([@naseemkullah](https://github.com/naseemkullah)) +- Matthew Wear ([@mwear](https://github.com/mwear)) +- Bartlomiej Obecny ([@obecny](https://github.com/obecny)) +- Mayur Kale ([@mayurkale22](https://github.com/mayurkale22)) +- Valentin Marchaud ([@vmarchaud](https://github.com/vmarchaud)) + ## 0.6.1 Released 2020-04-08 diff --git a/README.md b/README.md index 84a4fab324c..46ba523ad74 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,26 @@ To get started tracing your own application, see the [Getting Started Guide](get If you are a library author looking to build OpenTelemetry into your library, please see [the documentation][docs]. As a library author, it is important that you only depend on properties and methods published on the public API. If you use any properties or methods from the SDK that are not officially a part of the public API, your library may break if an [Application Owner](#application-owner) uses a different SDK implementation. +## Supported Runtimes + +Platform Version | Supported +---------------- | --------- +Node.JS `v14` | ✅ +Node.JS `v13` | ✅ +Node.JS `v12` | ✅ +Node.JS `v10` | ✅ +Node.JS `v8` | See [Node Support](#node-support) below +Web Browsers | ✅ See [Browser Support](#browser-support) below + +### Node Support +Automated tests are run using the latest release of each currently active version of Node.JS. +While Node.JS v8 is no longer supported by the Node.JS team, the latest version of Node.JS v8 is still included in our testing suite. +Please note that versions of Node.JS v8 prior to `v8.5.0` will NOT work, because OpenTelemetry Node depends on the `perf_hooks` module introduced in `v8.5.0` + +### Browser Support +Automated browser tests are run in the latest version of Headless Chrome. +There is currently no list of officially supported browsers, but OpenTelemetry is developed using standard web technologies with wide support and should work in currently supported versions of major browsers. + ## Release Schedule OpenTelemetry JS is under active development. @@ -142,7 +162,6 @@ Maintainers ([@open-telemetry/js-maintainers](https://github.com/orgs/open-telem | [@opentelemetry/metrics][otel-metrics] | This module provides instruments and meters for reporting of time series data. | | [@opentelemetry/node][otel-node] | This module provides automatic tracing for Node.js applications. It is intended for use on the server only. | | [@opentelemetry/web][otel-web] | This module provides automated instrumentation and tracing for Web applications. It is intended for use in the browser only. | -| [@opentelemetry/base][otel-base] | This package provides base code for the SDK packages (tracing and metrics). | ### Compatible Exporters @@ -202,7 +221,6 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [docs]: https://open-telemetry.github.io/opentelemetry-js -[otel-base]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-base [otel-metrics]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-metrics [otel-node]: https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-node diff --git a/examples/basic-tracer-node/package.json b/examples/basic-tracer-node/package.json index b74da11b077..cb7aadba81b 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.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-jaeger": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/exporter-jaeger": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" }, "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 861b5076b44..e69c72ea593 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.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-collector": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/exporter-collector": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/examples/grpc/package.json b/examples/grpc/package.json index 9de46ad9621..7855d31dc12 100644 --- a/examples/grpc/package.json +++ b/examples/grpc/package.json @@ -1,7 +1,7 @@ { "name": "grpc-example", "private": true, - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-jaeger": "^0.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/plugin-grpc": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/exporter-jaeger": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/plugin-grpc": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "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 139dae4639d..c47fd562fad 100644 --- a/examples/http/package.json +++ b/examples/http/package.json @@ -1,7 +1,7 @@ { "name": "http-example", "private": true, - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-jaeger": "^0.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/plugin-http": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/exporter-jaeger": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/plugin-http": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", "devDependencies": { diff --git a/examples/https/package.json b/examples/https/package.json index 25df8768b16..33570c1853c 100644 --- a/examples/https/package.json +++ b/examples/https/package.json @@ -1,7 +1,7 @@ { "name": "https-example", "private": true, - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-jaeger": "^0.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/plugin-https": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/exporter-jaeger": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/plugin-https": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", "devDependencies": { diff --git a/examples/metrics/metrics/observer.js b/examples/metrics/metrics/observer.js index bb398bb95aa..6cced2142c2 100644 --- a/examples/metrics/metrics/observer.js +++ b/examples/metrics/metrics/observer.js @@ -1,6 +1,6 @@ 'use strict'; -const { MeterProvider } = require('@opentelemetry/metrics'); +const { MeterProvider, MetricObservable } = require('@opentelemetry/metrics'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); const exporter = new PrometheusExporter( @@ -14,7 +14,7 @@ const exporter = new PrometheusExporter( const meter = new MeterProvider({ exporter, - interval: 1000, + interval: 2000, }).getMeter('example-observer'); const otelCpuUsage = meter.createObserver('metric_observer', { @@ -27,9 +27,16 @@ function getCpuUsage() { return Math.random(); } +const observable = new MetricObservable(); + +setInterval(() => { + observable.next(getCpuUsage()); +}, 5000); + otelCpuUsage.setCallback((observerResult) => { observerResult.observe(getCpuUsage, { pid: process.pid, core: '1' }); observerResult.observe(getCpuUsage, { pid: process.pid, core: '2' }); observerResult.observe(getCpuUsage, { pid: process.pid, core: '3' }); observerResult.observe(getCpuUsage, { pid: process.pid, core: '4' }); + observerResult.observe(observable, { pid: process.pid, core: '5' }); }); diff --git a/examples/metrics/metrics/observer.png b/examples/metrics/metrics/observer.png index 7a9184af13f..79f77b0c1c3 100644 Binary files a/examples/metrics/metrics/observer.png and b/examples/metrics/metrics/observer.png differ diff --git a/examples/metrics/package.json b/examples/metrics/package.json index fea2183bfd6..b5a5db81bda 100644 --- a/examples/metrics/package.json +++ b/examples/metrics/package.json @@ -1,7 +1,7 @@ { "name": "example-metrics", "private": true, - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/metrics": "^0.6.1" + "@opentelemetry/exporter-prometheus": "^0.7.0", + "@opentelemetry/metrics": "^0.7.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" } diff --git a/examples/opentracing-shim/client.js b/examples/opentracing-shim/client.js index 6f98c2efc50..451467e3ef9 100644 --- a/examples/opentracing-shim/client.js +++ b/examples/opentracing-shim/client.js @@ -4,7 +4,7 @@ const http = require('http'); const opentracing = require('opentracing'); const shim = require('./shim').shim('http_client_service'); -opentracing.setGlobalTracer(shim); +opentracing.initGlobalTracer(shim); const tracer = opentracing.globalTracer(); makeRequest(); diff --git a/examples/opentracing-shim/package.json b/examples/opentracing-shim/package.json index d5be857137d..ceb3d297e9e 100644 --- a/examples/opentracing-shim/package.json +++ b/examples/opentracing-shim/package.json @@ -1,7 +1,7 @@ { "name": "opentracing-shim", "private": true, - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/shim-opentracing": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/exporter-jaeger": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/shim-opentracing": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "opentracing": "^0.14.4" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", diff --git a/examples/opentracing-shim/server.js b/examples/opentracing-shim/server.js index 23661667e95..66c0803ccda 100644 --- a/examples/opentracing-shim/server.js +++ b/examples/opentracing-shim/server.js @@ -5,7 +5,7 @@ const opentracing = require('opentracing'); const utils = require('./utils'); const shim = require('./shim').shim('http_server_service'); -opentracing.setGlobalTracer(shim); +opentracing.initGlobalTracer(shim); const tracer = opentracing.globalTracer(); startServer(3000); diff --git a/examples/opentracing-shim/shim.js b/examples/opentracing-shim/shim.js index 993445ab268..38e6db223d6 100644 --- a/examples/opentracing-shim/shim.js +++ b/examples/opentracing-shim/shim.js @@ -10,6 +10,8 @@ function shim(serviceName) { const provider = new NodeTracerProvider(); provider.addSpanProcessor(new SimpleSpanProcessor(getExporter(serviceName))); + // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings + provider.register(); return new TracerShim(provider.getTracer('opentracing-shim')); } diff --git a/examples/prometheus/package.json b/examples/prometheus/package.json index e5bb3227777..9d0baa9446c 100644 --- a/examples/prometheus/package.json +++ b/examples/prometheus/package.json @@ -1,6 +1,6 @@ { "name": "prometheus-example", - "version": "0.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/metrics": "^0.6.1" + "@opentelemetry/exporter-prometheus": "^0.7.0", + "@opentelemetry/metrics": "^0.7.0" } } diff --git a/examples/tracer-web/package.json b/examples/tracer-web/package.json index 6953494e0ec..598a9ee7cd2 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.6.1", + "version": "0.7.0", "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.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/exporter-collector": "^0.6.1", + "@opentelemetry/context-zone": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/exporter-collector": "^0.7.0", "@opentelemetry/plugin-document-load": "^0.6.1", "@opentelemetry/plugin-user-interaction": "^0.6.1", - "@opentelemetry/plugin-xml-http-request": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", - "@opentelemetry/web": "^0.6.1" + "@opentelemetry/plugin-xml-http-request": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", + "@opentelemetry/web": "^0.7.0" }, "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 b7e87655c5e..b4b6a7ff0ea 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.6.1", + "@opentelemetry/metrics": "^0.7.0", "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 fd690d0062c..9675f7d105d 100644 --- a/getting-started/traced-example/package.json +++ b/getting-started/traced-example/package.json @@ -9,11 +9,11 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/plugin-http": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/plugin-http": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "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 681ffeae323..16eff7a16f5 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.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/exporter-prometheus": "^0.6.1", - "@opentelemetry/exporter-zipkin": "^0.6.1", - "@opentelemetry/metrics": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/plugin-http": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/exporter-prometheus": "^0.7.0", + "@opentelemetry/exporter-zipkin": "^0.7.0", + "@opentelemetry/metrics": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/plugin-http": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "axios": "^0.19.1", "express": "^4.17.1" } diff --git a/lerna.json b/lerna.json index 0ffc1914b38..07bd971258d 100644 --- a/lerna.json +++ b/lerna.json @@ -5,7 +5,7 @@ "benchmark/*", "packages/*" ], - "version": "0.6.1", + "version": "0.7.0", "changelog": { "repo": "open-telemetry/opentelemetry-js", "labels": { diff --git a/package.json b/package.json index 2ec08f85bc9..329e6c16fac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opentelemetry-base", - "version": "0.6.1", + "version": "0.7.0", "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 2e8d75cd41e..46ca4fd212e 100644 --- a/packages/opentelemetry-api/README.md +++ b/packages/opentelemetry-api/README.md @@ -91,6 +91,10 @@ const meterProvider = new MeterProvider({ api.metrics.setGlobalMeterProvider(meterProvider); ``` +## Version Compatibility + +Because the npm installer and node module resolution algorithm could potentially allow two or more copies of any given package to exist within the same `node_modules` structure, the OpenTelemetry API takes advantage of a variable on the `global` object to store the global API. When an API method in the API package is called, it checks if this `global` API exists and proxies calls to it if and only if it is a compatible API version. This means if a package has a dependency on an OpenTelemetry API version which is not compatible with the API used by the end user, the package will receive a no-op implementation of the API. + ## Advanced Use ### API Registration Options diff --git a/packages/opentelemetry-api/package.json b/packages/opentelemetry-api/package.json index d3a5b5e2878..68eca898e61 100644 --- a/packages/opentelemetry-api/package.json +++ b/packages/opentelemetry-api/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/api", - "version": "0.6.1", + "version": "0.7.0", "description": "Public API for OpenTelemetry", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -47,7 +47,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/context-base": "^0.6.1" + "@opentelemetry/context-base": "^0.7.0" }, "devDependencies": { "@types/mocha": "^7.0.0", diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index 3c5f7f0ea7c..b127917990b 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -15,17 +15,24 @@ */ import { + Context, ContextManager, NoopContextManager, - Context, } from '@opentelemetry/context-base'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_CONTEXT_MANAGER_API_KEY, + makeGetter, + _global, +} from './global-utils'; + +const NOOP_CONTEXT_MANAGER = new NoopContextManager(); /** * Singleton object which represents the entry point to the OpenTelemetry Context API */ export class ContextAPI { private static _instance?: ContextAPI; - private _contextManager: ContextManager = new NoopContextManager(); /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -45,7 +52,17 @@ export class ContextAPI { public setGlobalContextManager( contextManager: ContextManager ): ContextManager { - this._contextManager = contextManager; + if (_global[GLOBAL_CONTEXT_MANAGER_API_KEY]) { + // global context manager has already been set + return this._getContextManager(); + } + + _global[GLOBAL_CONTEXT_MANAGER_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + contextManager, + NOOP_CONTEXT_MANAGER + ); + return contextManager; } @@ -53,7 +70,7 @@ export class ContextAPI { * Get the currently active context */ public active(): Context { - return this._contextManager.active(); + return this._getContextManager().active(); } /** @@ -66,7 +83,7 @@ export class ContextAPI { context: Context, fn: T ): ReturnType { - return this._contextManager.with(context, fn); + return this._getContextManager().with(context, fn); } /** @@ -76,6 +93,20 @@ export class ContextAPI { * @param context context to bind to the event emitter or function. Defaults to the currently active context */ public bind(target: T, context: Context = this.active()): T { - return this._contextManager.bind(target, context); + return this._getContextManager().bind(target, context); + } + + private _getContextManager(): ContextManager { + return ( + _global[GLOBAL_CONTEXT_MANAGER_API_KEY]?.( + API_BACKWARDS_COMPATIBILITY_VERSION + ) ?? NOOP_CONTEXT_MANAGER + ); + } + + /** Disable and remove the global context manager */ + public disable() { + this._getContextManager().disable(); + delete _global[GLOBAL_CONTEXT_MANAGER_API_KEY]; } } diff --git a/packages/opentelemetry-api/src/api/global-utils.ts b/packages/opentelemetry-api/src/api/global-utils.ts new file mode 100644 index 00000000000..3114d1b6d02 --- /dev/null +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -0,0 +1,67 @@ +/*! + * 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 { ContextManager } from '@opentelemetry/context-base'; +import { HttpTextPropagator } from '../context/propagation/HttpTextPropagator'; +import { MeterProvider } from '../metrics/MeterProvider'; +import { TracerProvider } from '../trace/tracer_provider'; + +export const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.context' +); +export const GLOBAL_METRICS_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.metrics' +); +export const GLOBAL_PROPAGATION_API_KEY = Symbol.for( + 'io.opentelemetry.js.api.propagation' +); +export const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace'); + +type Get = (version: number) => T; +type MyGlobals = Partial<{ + [GLOBAL_CONTEXT_MANAGER_API_KEY]: Get; + [GLOBAL_METRICS_API_KEY]: Get; + [GLOBAL_PROPAGATION_API_KEY]: Get; + [GLOBAL_TRACE_API_KEY]: Get; +}>; + +export const _global = global as typeof global & MyGlobals; + +/** + * Make a function which accepts a version integer and returns the instance of an API if the version + * is compatible, or a fallback version (usually NOOP) if it is not. + * + * @param requiredVersion Backwards compatibility version which is required to return the instance + * @param instance Instance which should be returned if the required version is compatible + * @param fallback Fallback instance, usually NOOP, which will be returned if the required version is not compatible + */ +export function makeGetter( + requiredVersion: number, + instance: T, + fallback: T +): Get { + return (version: number): T => + version === requiredVersion ? instance : fallback; +} + +/** + * A number which should be incremented each time a backwards incompatible + * change is made to the API. This number is used when an API package + * attempts to access the global API to ensure it is getting a compatible + * version. If the global API is not compatible with the API package + * attempting to get it, a NOOP API implementation will be returned. + */ +export const API_BACKWARDS_COMPATIBILITY_VERSION = 0; diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index 118c20db996..dedf58be54b 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -17,13 +17,18 @@ import { Meter } from '../metrics/Meter'; import { MeterProvider } from '../metrics/MeterProvider'; import { NOOP_METER_PROVIDER } from '../metrics/NoopMeterProvider'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_METRICS_API_KEY, + makeGetter, + _global, +} from './global-utils'; /** * Singleton object which represents the entry point to the OpenTelemetry Metrics API */ export class MetricsAPI { private static _instance?: MetricsAPI; - private _meterProvider: MeterProvider = NOOP_METER_PROVIDER; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -41,7 +46,17 @@ export class MetricsAPI { * Set the current global meter. Returns the initialized global meter provider. */ public setGlobalMeterProvider(provider: MeterProvider): MeterProvider { - this._meterProvider = provider; + if (_global[GLOBAL_METRICS_API_KEY]) { + // global meter provider has already been set + return this.getMeterProvider(); + } + + _global[GLOBAL_METRICS_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + provider, + NOOP_METER_PROVIDER + ); + return provider; } @@ -49,7 +64,10 @@ export class MetricsAPI { * Returns the global meter provider. */ public getMeterProvider(): MeterProvider { - return this._meterProvider; + return ( + _global[GLOBAL_METRICS_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_METER_PROVIDER + ); } /** @@ -58,4 +76,9 @@ export class MetricsAPI { public getMeter(name: string, version?: string): Meter { return this.getMeterProvider().getMeter(name, version); } + + /** Remove the global meter provider */ + public disable() { + delete _global[GLOBAL_METRICS_API_KEY]; + } } diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index f26c3c6f805..a8af5242448 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -20,6 +20,12 @@ import { HttpTextPropagator } from '../context/propagation/HttpTextPropagator'; import { NOOP_HTTP_TEXT_PROPAGATOR } from '../context/propagation/NoopHttpTextPropagator'; import { defaultSetter, SetterFunction } from '../context/propagation/setter'; import { ContextAPI } from './context'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_PROPAGATION_API_KEY, + makeGetter, + _global, +} from './global-utils'; const contextApi = ContextAPI.getInstance(); @@ -28,7 +34,6 @@ const contextApi = ContextAPI.getInstance(); */ export class PropagationAPI { private static _instance?: PropagationAPI; - private _propagator: HttpTextPropagator = NOOP_HTTP_TEXT_PROPAGATOR; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -48,7 +53,17 @@ export class PropagationAPI { public setGlobalPropagator( propagator: HttpTextPropagator ): HttpTextPropagator { - this._propagator = propagator; + if (_global[GLOBAL_PROPAGATION_API_KEY]) { + // global propagator has already been set + return this._getGlobalPropagator(); + } + + _global[GLOBAL_PROPAGATION_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + propagator, + NOOP_HTTP_TEXT_PROPAGATOR + ); + return propagator; } @@ -64,7 +79,7 @@ export class PropagationAPI { setter: SetterFunction = defaultSetter, context = contextApi.active() ): void { - return this._propagator.inject(context, carrier, setter); + return this._getGlobalPropagator().inject(context, carrier, setter); } /** @@ -79,6 +94,19 @@ export class PropagationAPI { getter: GetterFunction = defaultGetter, context = contextApi.active() ): Context { - return this._propagator.extract(context, carrier, getter); + return this._getGlobalPropagator().extract(context, carrier, getter); + } + + /** Remove the global propagator */ + public disable() { + delete _global[GLOBAL_PROPAGATION_API_KEY]; + } + + private _getGlobalPropagator(): HttpTextPropagator { + return ( + _global[GLOBAL_PROPAGATION_API_KEY]?.( + API_BACKWARDS_COMPATIBILITY_VERSION + ) ?? NOOP_HTTP_TEXT_PROPAGATOR + ); } } diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index 4af88e70e6a..bae7353e08f 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -15,15 +15,20 @@ */ import { NOOP_TRACER_PROVIDER } from '../trace/NoopTracerProvider'; -import { TracerProvider } from '../trace/tracer_provider'; import { Tracer } from '../trace/tracer'; +import { TracerProvider } from '../trace/tracer_provider'; +import { + API_BACKWARDS_COMPATIBILITY_VERSION, + GLOBAL_TRACE_API_KEY, + makeGetter, + _global, +} from './global-utils'; /** * Singleton object which represents the entry point to the OpenTelemetry Tracing API */ export class TraceAPI { private static _instance?: TraceAPI; - private _tracerProvider: TracerProvider = NOOP_TRACER_PROVIDER; /** Empty private constructor prevents end users from constructing a new instance of the API */ private constructor() {} @@ -41,15 +46,28 @@ export class TraceAPI { * Set the current global tracer. Returns the initialized global tracer provider */ public setGlobalTracerProvider(provider: TracerProvider): TracerProvider { - this._tracerProvider = provider; - return provider; + if (_global[GLOBAL_TRACE_API_KEY]) { + // global tracer provider has already been set + return this.getTracerProvider(); + } + + _global[GLOBAL_TRACE_API_KEY] = makeGetter( + API_BACKWARDS_COMPATIBILITY_VERSION, + provider, + NOOP_TRACER_PROVIDER + ); + + return this.getTracerProvider(); } /** * Returns the global tracer provider. */ public getTracerProvider(): TracerProvider { - return this._tracerProvider; + return ( + _global[GLOBAL_TRACE_API_KEY]?.(API_BACKWARDS_COMPATIBILITY_VERSION) ?? + NOOP_TRACER_PROVIDER + ); } /** @@ -58,4 +76,9 @@ export class TraceAPI { public getTracer(name: string, version?: string): Tracer { return this.getTracerProvider().getTracer(name, version); } + + /** Remove the global tracer provider */ + public disable() { + delete _global[GLOBAL_TRACE_API_KEY]; + } } diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index 070ed01c052..a4a7406e716 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -26,6 +26,7 @@ export * from './metrics/BoundInstrument'; export * from './metrics/Meter'; export * from './metrics/MeterProvider'; export * from './metrics/Metric'; +export * from './metrics/MetricObservable'; export * from './metrics/NoopMeter'; export * from './metrics/NoopMeterProvider'; export * from './metrics/ObserverResult'; diff --git a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts index 87defee0dcf..07302bd22fb 100644 --- a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts +++ b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts @@ -16,7 +16,6 @@ import { CorrelationContext } from '../correlation_context/CorrelationContext'; import { SpanContext } from '../trace/span_context'; -import { ObserverResult } from './ObserverResult'; /** An Instrument for Counter Metric. */ export interface BoundCounter { @@ -45,14 +44,3 @@ export interface BoundMeasure { spanContext: SpanContext ): void; } - -/** Base interface for the Observer metrics. */ -export interface BoundObserver { - /** - * Sets callback for the observer. The callback is called once and then it - * sets observers for values. The observers are called periodically to - * retrieve the value. - * @param callback - */ - setCallback(callback: (observerResult: ObserverResult) => void): void; -} diff --git a/packages/opentelemetry-api/src/metrics/Meter.ts b/packages/opentelemetry-api/src/metrics/Meter.ts index 5231629c910..0b43708c4d0 100644 --- a/packages/opentelemetry-api/src/metrics/Meter.ts +++ b/packages/opentelemetry-api/src/metrics/Meter.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { Metric, MetricOptions } from './Metric'; -import { BoundCounter, BoundMeasure, BoundObserver } from './BoundInstrument'; +import { MetricOptions, Counter, Measure, Observer } from './Metric'; /** * An interface to allow the recording metrics. @@ -30,7 +29,7 @@ export interface Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure(name: string, options?: MetricOptions): Metric; + createMeasure(name: string, options?: MetricOptions): Measure; /** * Creates a new `Counter` metric. Generally, this kind of metric when the @@ -39,12 +38,12 @@ export interface Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createCounter(name: string, options?: MetricOptions): Metric; + createCounter(name: string, options?: MetricOptions): Counter; /** * Creates a new `Observer` metric. * @param name the name of the metric. * @param [options] the metric options. */ - createObserver(name: string, options?: MetricOptions): Metric; + createObserver(name: string, options?: MetricOptions): Observer; } diff --git a/packages/opentelemetry-api/src/metrics/Metric.ts b/packages/opentelemetry-api/src/metrics/Metric.ts index d57896a1d32..4b02812723e 100644 --- a/packages/opentelemetry-api/src/metrics/Metric.ts +++ b/packages/opentelemetry-api/src/metrics/Metric.ts @@ -17,6 +17,7 @@ import { CorrelationContext } from '../correlation_context/CorrelationContext'; import { SpanContext } from '../trace/span_context'; import { ObserverResult } from './ObserverResult'; +import { BoundCounter, BoundMeasure } from './BoundInstrument'; /** * Options needed for metric creation @@ -77,7 +78,18 @@ export enum ValueType { * Metric represents a base class for different types of metric * pre aggregations. */ -export interface Metric { +export interface Metric { + /** + * Clears all bound instruments from the Metric. + */ + clear(): void; +} + +/** + * UnboundMetric represents a base class for different types of metric + * pre aggregations without label value bound yet. + */ +export interface UnboundMetric extends Metric { /** * Returns a Instrument associated with specified Labels. * It is recommended to keep a reference to the Instrument instead of always @@ -92,31 +104,16 @@ export interface Metric { * @param labels key-values pairs that are associated with a specific metric. */ unbind(labels: Labels): void; - - /** - * Clears all timeseries from the Metric. - */ - clear(): void; } -export interface MetricUtils { +export interface Counter extends UnboundMetric { /** * Adds the given value to the current value. Values cannot be negative. */ add(value: number, labels: Labels): void; +} - /** - * Sets a callback where user can observe value for certain labels - * @param callback a function that will be called once to set observers - * for values - */ - setCallback(callback: (observerResult: ObserverResult) => void): void; - - /** - * Sets the given value. Values can be negative. - */ - set(value: number, labels: Labels): void; - +export interface Measure extends UnboundMetric { /** * Records the given value to this measure. */ @@ -136,6 +133,17 @@ export interface MetricUtils { ): void; } +/** Base interface for the Observer metrics. */ +export interface Observer extends Metric { + /** + * Sets a callback where user can observe value for certain labels. The + * observers are called periodically to retrieve the value. + * @param callback a function that will be called once to set observers + * for values + */ + setCallback(callback: (observerResult: ObserverResult) => void): void; +} + /** * key-value pairs passed by the user. */ diff --git a/packages/opentelemetry-base/src/platform/index.ts b/packages/opentelemetry-api/src/metrics/MetricObservable.ts similarity index 56% rename from packages/opentelemetry-base/src/platform/index.ts rename to packages/opentelemetry-api/src/metrics/MetricObservable.ts index 6c6d039c914..4e25dce4e57 100644 --- a/packages/opentelemetry-base/src/platform/index.ts +++ b/packages/opentelemetry-api/src/metrics/MetricObservable.ts @@ -14,7 +14,23 @@ * limitations under the License. */ -// Use the node platform by default. The "browser" field of package.json is used -// to override this file to use `./browser/index.ts` when packaged with -// webpack, Rollup, etc. -export * from './node'; +/** + * Metric Observable class to handle asynchronous metrics + */ +export interface MetricObservable { + /** + * Sets the next value for observable metric + * @param value + */ + next: (value: number) => void; + /** + * Subscribes for every value change + * @param callback + */ + subscribe: (callback: (value: number) => void) => void; + /** + * Removes the subscriber + * @param [callback] + */ + unsubscribe: (callback?: (value: number) => void) => void; +} diff --git a/packages/opentelemetry-api/src/metrics/NoopMeter.ts b/packages/opentelemetry-api/src/metrics/NoopMeter.ts index bfc2e70a930..dcd6a5dea1f 100644 --- a/packages/opentelemetry-api/src/metrics/NoopMeter.ts +++ b/packages/opentelemetry-api/src/metrics/NoopMeter.ts @@ -15,8 +15,15 @@ */ import { Meter } from './Meter'; -import { MetricOptions, Metric, Labels, MetricUtils } from './Metric'; -import { BoundMeasure, BoundCounter, BoundObserver } from './BoundInstrument'; +import { + MetricOptions, + UnboundMetric, + Labels, + Counter, + Measure, + Observer, +} from './Metric'; +import { BoundMeasure, BoundCounter } from './BoundInstrument'; import { CorrelationContext } from '../correlation_context/CorrelationContext'; import { SpanContext } from '../trace/span_context'; import { ObserverResult } from './ObserverResult'; @@ -33,7 +40,7 @@ export class NoopMeter implements Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure(name: string, options?: MetricOptions): Metric { + createMeasure(name: string, options?: MetricOptions): Measure { return NOOP_MEASURE_METRIC; } @@ -42,7 +49,7 @@ export class NoopMeter implements Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createCounter(name: string, options?: MetricOptions): Metric { + createCounter(name: string, options?: MetricOptions): Counter { return NOOP_COUNTER_METRIC; } @@ -51,12 +58,12 @@ export class NoopMeter implements Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createObserver(name: string, options?: MetricOptions): Metric { + createObserver(name: string, options?: MetricOptions): Observer { return NOOP_OBSERVER_METRIC; } } -export class NoopMetric implements Metric { +export class NoopMetric implements UnboundMetric { private readonly _instrument: T; constructor(instrument: T) { @@ -90,14 +97,14 @@ export class NoopMetric implements Metric { } export class NoopCounterMetric extends NoopMetric - implements Pick { + implements Counter { add(value: number, labels: Labels) { this.bind(labels).add(value); } } export class NoopMeasureMetric extends NoopMetric - implements Pick { + implements Measure { record( value: number, labels: Labels, @@ -114,8 +121,7 @@ export class NoopMeasureMetric extends NoopMetric } } -export class NoopObserverMetric extends NoopMetric - implements Pick { +export class NoopObserverMetric extends NoopMetric implements Observer { setCallback(callback: (observerResult: ObserverResult) => void): void {} } @@ -135,10 +141,6 @@ export class NoopBoundMeasure implements BoundMeasure { } } -export class NoopBoundObserver implements BoundObserver { - setCallback(callback: (observerResult: ObserverResult) => void): void {} -} - export const NOOP_METER = new NoopMeter(); export const NOOP_BOUND_COUNTER = new NoopBoundCounter(); export const NOOP_COUNTER_METRIC = new NoopCounterMetric(NOOP_BOUND_COUNTER); @@ -146,5 +148,4 @@ 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_OBSERVER = new NoopBoundObserver(); -export const NOOP_OBSERVER_METRIC = new NoopObserverMetric(NOOP_BOUND_OBSERVER); +export const NOOP_OBSERVER_METRIC = new NoopObserverMetric(); diff --git a/packages/opentelemetry-api/src/metrics/ObserverResult.ts b/packages/opentelemetry-api/src/metrics/ObserverResult.ts index 6fb4edba70f..47c3d595c43 100644 --- a/packages/opentelemetry-api/src/metrics/ObserverResult.ts +++ b/packages/opentelemetry-api/src/metrics/ObserverResult.ts @@ -15,11 +15,11 @@ */ import { Labels } from './Metric'; +import { MetricObservable } from './MetricObservable'; /** * Interface that is being used in function setCallback for Observer Metric */ export interface ObserverResult { - observers: Map; - observe(callback: Function, labels: Labels): void; + observe(callback: Function | MetricObservable, labels: Labels): void; } diff --git a/packages/opentelemetry-api/src/version.ts b/packages/opentelemetry-api/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index e9994038cc9..d02453d2528 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -22,6 +22,10 @@ import api, { NoopTracer, SpanOptions, Span, + context, + trace, + propagation, + metrics, } from '../../src'; describe('API', () => { @@ -41,8 +45,11 @@ describe('API', () => { }; const dummySpan = new NoopSpan(spanContext); - afterEach(() => { - api.trace.setGlobalTracerProvider(new NoopTracerProvider()); + beforeEach(() => { + context.disable(); + trace.disable(); + propagation.disable(); + metrics.disable(); }); it('should not crash', () => { diff --git a/packages/opentelemetry-api/test/api/global.test.ts b/packages/opentelemetry-api/test/api/global.test.ts new file mode 100644 index 00000000000..5ff4e25a2bf --- /dev/null +++ b/packages/opentelemetry-api/test/api/global.test.ts @@ -0,0 +1,81 @@ +/*! + * 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 { NoopContextManager } from '@opentelemetry/context-base'; +import { + _global, + GLOBAL_CONTEXT_MANAGER_API_KEY, +} from '../../src/api/global-utils'; + +const api1 = require('../../src') as typeof import('../../src'); + +// clear cache and load a second instance of the api +for (const key of Object.keys(require.cache)) { + delete require.cache[key]; +} +const api2 = require('../../src') as typeof import('../../src'); + +describe('Global Utils', () => { + // prove they are separate instances + assert.notEqual(api1, api2); + // that return separate noop instances to start + assert.notStrictEqual( + api1.context['_getContextManager'](), + api2.context['_getContextManager']() + ); + + beforeEach(() => { + api1.context.disable(); + api1.propagation.disable(); + api1.trace.disable(); + api1.metrics.disable(); + }); + + it('should change the global context manager', () => { + const original = api1.context['_getContextManager'](); + const newContextManager = new NoopContextManager(); + api1.context.setGlobalContextManager(newContextManager); + assert.notStrictEqual(api1.context['_getContextManager'](), original); + assert.strictEqual(api1.context['_getContextManager'](), newContextManager); + }); + + it('should load an instance from one which was set in the other', () => { + api1.context.setGlobalContextManager(new NoopContextManager()); + assert.strictEqual( + api1.context['_getContextManager'](), + api2.context['_getContextManager']() + ); + }); + + it('should disable both if one is disabled', () => { + const original = api1.context['_getContextManager'](); + + api1.context.setGlobalContextManager(new NoopContextManager()); + + assert.notStrictEqual(original, api1.context['_getContextManager']()); + api2.context.disable(); + assert.strictEqual(original, api1.context['_getContextManager']()); + }); + + it('should return the module NoOp implementation if the version is a mismatch', () => { + const original = api1.context['_getContextManager'](); + api1.context.setGlobalContextManager(new NoopContextManager()); + const afterSet = _global[GLOBAL_CONTEXT_MANAGER_API_KEY]!(-1); + + assert.strictEqual(original, afterSet); + }); +}); diff --git a/packages/opentelemetry-base/LICENSE b/packages/opentelemetry-base/LICENSE deleted file mode 100644 index 261eeb9e9f8..00000000000 --- a/packages/opentelemetry-base/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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 - - http://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. diff --git a/packages/opentelemetry-base/README.md b/packages/opentelemetry-base/README.md deleted file mode 100644 index 9cf3819ca4e..00000000000 --- a/packages/opentelemetry-base/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# OpenTelemetry Base -[![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] - -This package provides base code for the SDK packages. - -## 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-base -[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-base -[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-base -[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-base&type=dev -[npm-url]: https://www.npmjs.com/package/@opentelemetry/base -[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fbase.svg diff --git a/packages/opentelemetry-base/package.json b/packages/opentelemetry-base/package.json deleted file mode 100644 index 8072e38ee6b..00000000000 --- a/packages/opentelemetry-base/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@opentelemetry/base", - "version": "0.6.1", - "description": "OpenTelemetry base provides base code for the SDK packages", - "main": "build/src/index.js", - "browser": { - "./src/platform/index.ts": "./src/platform/browser/index.ts", - "./build/src/platform/index.js": "./build/src/platform/browser/index.js" - }, - "types": "build/src/index.d.ts", - "repository": "open-telemetry/opentelemetry-js", - "scripts": { - "test": "nyc ts-mocha -p tsconfig.json test/**/*.test.ts", - "tdd": "npm run tdd:node", - "tdd:node": "npm run test -- --watch-extensions ts --watch", - "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", - "clean": "rimraf build/*", - "lint": "gts check", - "lint:fix": "gts fix", - "precompile": "tsc --version", - "version:update": "node ../../scripts/version-update.js", - "compile": "npm run version:update && tsc -p .", - "prepare": "npm run compile" - }, - "keywords": [ - "opentelemetry", - "nodejs", - "tracing", - "profiling", - "metrics", - "stats" - ], - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - }, - "files": [ - "build/src/**/*.js", - "build/src/**/*.d.ts", - "doc", - "LICENSE", - "README.md" - ], - "publishConfig": { - "access": "public" - }, - "devDependencies": { - "@types/mocha": "^7.0.0", - "@types/node": "^12.6.8", - "codecov": "^3.6.1", - "gts": "^1.1.0", - "mocha": "^6.1.0", - "nyc": "^15.0.0", - "rimraf": "^3.0.0", - "ts-mocha": "^6.0.0", - "ts-node": "^8.6.2", - "tslint-consistent-codestyle": "^1.16.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.7.2" - } -} diff --git a/packages/opentelemetry-base/src/index.ts b/packages/opentelemetry-base/src/index.ts deleted file mode 100644 index 1c2e67e6b78..00000000000 --- a/packages/opentelemetry-base/src/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Copyright 2019, 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. - */ - -export * from './ExportResult'; -export * from './platform'; diff --git a/packages/opentelemetry-base/src/version.ts b/packages/opentelemetry-base/src/version.ts deleted file mode 100644 index 74e9e923376..00000000000 --- a/packages/opentelemetry-base/src/version.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Copyright 2019, 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. - */ - -// this is autogenerated file, see scripts/version-update.js -export const VERSION = '0.6.1'; diff --git a/packages/opentelemetry-base/tsconfig.json b/packages/opentelemetry-base/tsconfig.json deleted file mode 100644 index a2042cd68b1..00000000000 --- a/packages/opentelemetry-base/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../tsconfig.base", - "compilerOptions": { - "rootDir": ".", - "outDir": "build" - }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ] -} diff --git a/packages/opentelemetry-base/tslint.json b/packages/opentelemetry-base/tslint.json deleted file mode 100644 index 0710b135d07..00000000000 --- a/packages/opentelemetry-base/tslint.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "rulesDirectory": ["node_modules/tslint-microsoft-contrib"], - "extends": ["../../tslint.base.js", "./node_modules/tslint-consistent-codestyle"] -} diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index ce54c7ccfdb..2efdf987321 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry AsyncHooks-based Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -56,6 +56,6 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/context-base": "^0.6.1" + "@opentelemetry/context-base": "^0.7.0" } } diff --git a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts index 138ab5e2f0e..4ea8fe78d4a 100644 --- a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts +++ b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts @@ -29,6 +29,19 @@ 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', @@ -39,9 +52,7 @@ const ADD_LISTENER_METHODS = [ export class AsyncHooksContextManager implements ContextManager { private _asyncHook: asyncHooks.AsyncHook; - private _contexts: { - [uid: number]: Context | undefined | null; - } = Object.create(null); + private _contextRefs: Map | undefined> = new Map(); constructor() { this._asyncHook = asyncHooks.createHook({ @@ -52,9 +63,8 @@ export class AsyncHooksContextManager implements ContextManager { } active(): Context { - return ( - this._contexts[asyncHooks.executionAsyncId()] || Context.ROOT_CONTEXT - ); + const ref = this._contextRefs.get(asyncHooks.executionAsyncId()); + return ref === undefined ? Context.ROOT_CONTEXT : ref.get(); } with ReturnType>( @@ -62,8 +72,15 @@ export class AsyncHooksContextManager implements ContextManager { fn: T ): ReturnType { const uid = asyncHooks.executionAsyncId(); - const oldContext = this._contexts[uid]; - this._contexts[uid] = context; + 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 fn(); } catch (err) { @@ -72,7 +89,34 @@ export class AsyncHooksContextManager implements ContextManager { if (oldContext === undefined) { this._destroy(uid); } else { - this._contexts[uid] = oldContext; + 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(); + } catch (err) { + throw err; + } finally { + if (oldContext === undefined) { + this._destroy(uid); + } else { + ref.set(oldContext); } } } @@ -97,7 +141,7 @@ export class AsyncHooksContextManager implements ContextManager { disable(): this { this._asyncHook.disable(); - this._contexts = {}; + this._contextRefs.clear(); return this; } @@ -232,7 +276,10 @@ export class AsyncHooksContextManager implements ContextManager { * @param uid id of the async context */ private _init(uid: number) { - this._contexts[uid] = this._contexts[asyncHooks.executionAsyncId()]; + const ref = this._contextRefs.get(asyncHooks.executionAsyncId()); + if (ref !== undefined) { + this._contextRefs.set(uid, ref); + } } /** @@ -241,6 +288,6 @@ export class AsyncHooksContextManager implements ContextManager { * @param uid uid of the async context */ private _destroy(uid: number) { - delete this._contexts[uid]; + this._contextRefs.delete(uid); } } diff --git a/packages/opentelemetry-context-async-hooks/src/version.ts b/packages/opentelemetry-context-async-hooks/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts index 5bc4b99edec..8c6c648a883 100644 --- a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts +++ b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts @@ -104,6 +104,172 @@ describe('AsyncHooksContextManager', () => { }); }); + 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; + }); + } catch (e) { + assert.ok(e === err); + done = true; + } + + assert.ok(done); + }); + + it('should finally restore an old scope', async () => { + const scope1 = '1' as any; + const scope2 = '2' as any; + let done = false; + + await contextManager.withAsync(scope1, async () => { + assert.strictEqual(contextManager.active(), scope1); + await contextManager.withAsync(scope2, async () => { + assert.strictEqual(contextManager.active(), scope2); + done = true; + }); + assert.strictEqual(contextManager.active(), scope1); + }); + + assert.ok(done); + }); + }); + + describe('.withAsync/with()', () => { + it('with() inside withAsync() should correctly restore context', async () => { + const scope1 = '1' as any; + const scope2 = '2' as any; + let done = false; + + await contextManager.withAsync(scope1, async () => { + assert.strictEqual(contextManager.active(), scope1); + contextManager.with(scope2, () => { + assert.strictEqual(contextManager.active(), scope2); + done = true; + }); + assert.strictEqual(contextManager.active(), scope1); + }); + + assert.ok(done); + }); + + it('withAsync() inside with() should correctly restore conxtext', done => { + const scope1 = '1' as any; + const scope2 = '2' as any; + + contextManager.with(scope1, async () => { + assert.strictEqual(contextManager.active(), scope1); + await contextManager.withAsync(scope2, async () => { + 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 => { + const scope1 = '1' as any; + const scope2 = '2' as any; + let _done: boolean = false; + + contextManager.with(scope1, () => { + assert.strictEqual(contextManager.active(), scope1); + contextManager + .withAsync(scope2, async () => { + assert.strictEqual(contextManager.active(), scope2); + }) + .then(() => { + assert.strictEqual(contextManager.active(), scope1); + _done = true; + }); + // 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); + return done(); + }, 100); + }); + 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); + 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); + }); + 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)', () => { it('should return the same target (when enabled)', () => { const test = { a: 1 }; diff --git a/packages/opentelemetry-context-base/package.json b/packages/opentelemetry-context-base/package.json index 52cd58348e1..58700ecf849 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Base Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", diff --git a/packages/opentelemetry-context-base/src/version.ts b/packages/opentelemetry-context-base/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index 1171b269b02..328422eaf0d 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Context Zone with peer dependency for zone.js", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -72,7 +72,7 @@ "zone.js": "^0.10.2" }, "dependencies": { - "@opentelemetry/context-base": "^0.6.1" + "@opentelemetry/context-base": "^0.7.0" }, "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 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index 134a63333c4..7b128655ce0 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Context Zone", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -66,7 +66,7 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/context-zone-peer-dep": "^0.6.1", + "@opentelemetry/context-zone-peer-dep": "^0.7.0", "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 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 0b1b3cee36b..149e6f2824b 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/core", - "version": "0.6.1", + "version": "0.7.0", "description": "OpenTelemetry Core provides default and no-op implementations of the OpenTelemetry types for trace and metrics", "main": "build/src/index.js", "browser": { @@ -78,8 +78,8 @@ "webpack": "^4.35.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", "semver": "^7.1.3" } } diff --git a/packages/opentelemetry-base/src/ExportResult.ts b/packages/opentelemetry-core/src/ExportResult.ts similarity index 94% rename from packages/opentelemetry-base/src/ExportResult.ts rename to packages/opentelemetry-core/src/ExportResult.ts index 3f94eddd57b..1306c98b046 100644 --- a/packages/opentelemetry-base/src/ExportResult.ts +++ b/packages/opentelemetry-core/src/ExportResult.ts @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * 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. diff --git a/packages/opentelemetry-core/src/common/time.ts b/packages/opentelemetry-core/src/common/time.ts index 13416ca2d79..13fdec0450f 100644 --- a/packages/opentelemetry-core/src/common/time.ts +++ b/packages/opentelemetry-core/src/common/time.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { otperformance as performance } from '../platform'; import { TimeOriginLegacy } from './types'; @@ -25,7 +25,7 @@ const SECOND_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS); * Converts a number to HrTime * @param epochMillis */ -function numberToHrtime(epochMillis: number): types.HrTime { +function numberToHrtime(epochMillis: number): api.HrTime { const epochSeconds = epochMillis / 1000; // Decimals only. const seconds = Math.trunc(epochSeconds); @@ -49,7 +49,7 @@ function getTimeOrigin(): number { * Returns an hrtime calculated via performance component. * @param performanceNow */ -export function hrTime(performanceNow?: number): types.HrTime { +export function hrTime(performanceNow?: number): api.HrTime { const timeOrigin = numberToHrtime(getTimeOrigin()); const now = numberToHrtime( typeof performanceNow === 'number' ? performanceNow : performance.now() @@ -72,10 +72,10 @@ export function hrTime(performanceNow?: number): types.HrTime { * Converts a TimeInput to an HrTime, defaults to _hrtime(). * @param time */ -export function timeInputToHrTime(time: types.TimeInput): types.HrTime { +export function timeInputToHrTime(time: api.TimeInput): api.HrTime { // process.hrtime if (isTimeInputHrTime(time)) { - return time as types.HrTime; + return time as api.HrTime; } else if (typeof time === 'number') { // Must be a performance.now() if it's smaller than process start time. if (time < getTimeOrigin()) { @@ -97,9 +97,9 @@ export function timeInputToHrTime(time: types.TimeInput): types.HrTime { * @param endTime */ export function hrTimeDuration( - startTime: types.HrTime, - endTime: types.HrTime -): types.HrTime { + startTime: api.HrTime, + endTime: api.HrTime +): api.HrTime { let seconds = endTime[0] - startTime[0]; let nanos = endTime[1] - startTime[1]; @@ -117,7 +117,7 @@ export function hrTimeDuration( * Convert hrTime to timestamp, for example "2019-05-14T17:00:00.000123456Z" * @param hrTime */ -export function hrTimeToTimeStamp(hrTime: types.HrTime): string { +export function hrTimeToTimeStamp(hrTime: api.HrTime): string { const precision = NANOSECOND_DIGITS; const tmp = `${'0'.repeat(precision)}${hrTime[1]}Z`; const nanoString = tmp.substr(tmp.length - precision - 1); @@ -129,7 +129,7 @@ export function hrTimeToTimeStamp(hrTime: types.HrTime): string { * Convert hrTime to nanoseconds. * @param hrTime */ -export function hrTimeToNanoseconds(hrTime: types.HrTime): number { +export function hrTimeToNanoseconds(hrTime: api.HrTime): number { return hrTime[0] * SECOND_TO_NANOSECONDS + hrTime[1]; } @@ -137,7 +137,7 @@ export function hrTimeToNanoseconds(hrTime: types.HrTime): number { * Convert hrTime to milliseconds. * @param hrTime */ -export function hrTimeToMilliseconds(hrTime: types.HrTime): number { +export function hrTimeToMilliseconds(hrTime: api.HrTime): number { return Math.round(hrTime[0] * 1e3 + hrTime[1] / 1e6); } @@ -145,7 +145,7 @@ export function hrTimeToMilliseconds(hrTime: types.HrTime): number { * Convert hrTime to microseconds. * @param hrTime */ -export function hrTimeToMicroseconds(hrTime: types.HrTime): number { +export function hrTimeToMicroseconds(hrTime: api.HrTime): number { return Math.round(hrTime[0] * 1e6 + hrTime[1] / 1e3); } diff --git a/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts b/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts index ce68edc3e2f..27689c5de9f 100644 --- a/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts +++ b/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts @@ -26,7 +26,7 @@ import { getParentSpanContext, setExtractedSpanContext } from '../context'; export const X_B3_TRACE_ID = 'x-b3-traceid'; export const X_B3_SPAN_ID = 'x-b3-spanid'; export const X_B3_SAMPLED = 'x-b3-sampled'; -const VALID_TRACEID_REGEX = /^[0-9a-f]{32}$/i; +const VALID_TRACEID_REGEX = /^([0-9a-f]{16}){1,2}$/i; const VALID_SPANID_REGEX = /^[0-9a-f]{16}$/i; const INVALID_ID_REGEX = /^0+$/i; @@ -57,7 +57,13 @@ export class B3Propagator implements HttpTextPropagator { // We set the header only if there is an existing sampling decision. // Otherwise we will omit it => Absent. if (spanContext.traceFlags !== undefined) { - setter(carrier, X_B3_SAMPLED, Number(spanContext.traceFlags)); + setter( + carrier, + X_B3_SAMPLED, + (TraceFlags.SAMPLED & spanContext.traceFlags) === TraceFlags.SAMPLED + ? '1' + : '0' + ); } } } @@ -66,16 +72,21 @@ export class B3Propagator implements HttpTextPropagator { const traceIdHeader = getter(carrier, X_B3_TRACE_ID); const spanIdHeader = getter(carrier, X_B3_SPAN_ID); const sampledHeader = getter(carrier, X_B3_SAMPLED); - const traceId = Array.isArray(traceIdHeader) + + const traceIdHeaderValue = Array.isArray(traceIdHeader) ? traceIdHeader[0] : traceIdHeader; const spanId = Array.isArray(spanIdHeader) ? spanIdHeader[0] : spanIdHeader; + const options = Array.isArray(sampledHeader) ? sampledHeader[0] : sampledHeader; - if (typeof traceId !== 'string' || typeof spanId !== 'string') + if (typeof traceIdHeaderValue !== 'string' || typeof spanId !== 'string') { return context; + } + + const traceId = traceIdHeaderValue.padStart(32, '0'); if (isValidTraceId(traceId) && isValidSpanId(spanId)) { return setExtractedSpanContext(context, { diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index 60b8b04f925..46f1baf8be1 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -18,6 +18,7 @@ export * from './common/ConsoleLogger'; export * from './common/NoopLogger'; export * from './common/time'; export * from './common/types'; +export * from './ExportResult'; export * from './version'; export * from './context/context'; export * from './context/propagation/B3Propagator'; diff --git a/packages/opentelemetry-core/src/platform/browser/index.ts b/packages/opentelemetry-core/src/platform/browser/index.ts index 4668bb35aa2..36164efce55 100644 --- a/packages/opentelemetry-core/src/platform/browser/index.ts +++ b/packages/opentelemetry-core/src/platform/browser/index.ts @@ -14,7 +14,8 @@ * limitations under the License. */ +export * from './hex-to-base64'; export * from './id'; export * from './performance'; +export * from './sdk-info'; export * from './timer-util'; -export * from './hex-to-base64'; diff --git a/packages/opentelemetry-base/src/platform/browser/constants.ts b/packages/opentelemetry-core/src/platform/browser/sdk-info.ts similarity index 100% rename from packages/opentelemetry-base/src/platform/browser/constants.ts rename to packages/opentelemetry-core/src/platform/browser/sdk-info.ts diff --git a/packages/opentelemetry-core/src/platform/node/index.ts b/packages/opentelemetry-core/src/platform/node/index.ts index 4668bb35aa2..47a879b04dd 100644 --- a/packages/opentelemetry-core/src/platform/node/index.ts +++ b/packages/opentelemetry-core/src/platform/node/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './sdk-info'; export * from './id'; export * from './performance'; export * from './timer-util'; diff --git a/packages/opentelemetry-base/src/platform/node/constants.ts b/packages/opentelemetry-core/src/platform/node/sdk-info.ts similarity index 100% rename from packages/opentelemetry-base/src/platform/node/constants.ts rename to packages/opentelemetry-core/src/platform/node/sdk-info.ts diff --git a/packages/opentelemetry-core/src/trace/TraceState.ts b/packages/opentelemetry-core/src/trace/TraceState.ts index cb42e83b64d..951b04964be 100644 --- a/packages/opentelemetry-core/src/trace/TraceState.ts +++ b/packages/opentelemetry-core/src/trace/TraceState.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { validateKey, validateValue } from '../internal/validators'; const MAX_TRACE_STATE_ITEMS = 32; @@ -31,7 +31,7 @@ const LIST_MEMBER_KEY_VALUE_SPLITTER = '='; * - The value of any key can be updated. Modified keys MUST be moved to the * beginning of the list. */ -export class TraceState implements types.TraceState { +export class TraceState implements api.TraceState { private _internalState: Map = new Map(); constructor(rawTraceState?: string) { diff --git a/packages/opentelemetry-core/src/version.ts b/packages/opentelemetry-core/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-core/test/common/time.test.ts b/packages/opentelemetry-core/test/common/time.test.ts index 54bfa6e09e3..07c404c8c98 100644 --- a/packages/opentelemetry-core/test/common/time.test.ts +++ b/packages/opentelemetry-core/test/common/time.test.ts @@ -17,7 +17,7 @@ import * as assert from 'assert'; import { otperformance as performance } from '../../src/platform'; import * as sinon from 'sinon'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { hrTime, timeInputToHrTime, @@ -141,16 +141,16 @@ describe('time', () => { describe('#hrTimeDuration', () => { it('should return duration', () => { - const startTime: types.HrTime = [22, 400000000]; - const endTime: types.HrTime = [32, 800000000]; + const startTime: api.HrTime = [22, 400000000]; + const endTime: api.HrTime = [32, 800000000]; const output = hrTimeDuration(startTime, endTime); assert.deepStrictEqual(output, [10, 400000000]); }); it('should handle nanosecond overflow', () => { - const startTime: types.HrTime = [22, 400000000]; - const endTime: types.HrTime = [32, 200000000]; + const startTime: api.HrTime = [22, 400000000]; + const endTime: api.HrTime = [32, 200000000]; const output = hrTimeDuration(startTime, endTime); assert.deepStrictEqual(output, [9, 800000000]); @@ -159,7 +159,7 @@ describe('time', () => { describe('#hrTimeToTimeStamp', () => { it('should return timestamp', () => { - const time: types.HrTime = [1573513121, 123456]; + const time: api.HrTime = [1573513121, 123456]; const output = hrTimeToTimeStamp(time); assert.deepStrictEqual(output, '2019-11-11T22:58:41.000123456Z'); diff --git a/packages/opentelemetry-core/test/context/B3Propagator.test.ts b/packages/opentelemetry-core/test/context/B3Propagator.test.ts index 1eb6759c16f..7b779c3b949 100644 --- a/packages/opentelemetry-core/test/context/B3Propagator.test.ts +++ b/packages/opentelemetry-core/test/context/B3Propagator.test.ts @@ -60,7 +60,7 @@ describe('B3Propagator', () => { 'd4cda95b652f4a1592b449d5929fda1b' ); assert.deepStrictEqual(carrier[X_B3_SPAN_ID], '6e0c63257de34c92'); - assert.deepStrictEqual(carrier[X_B3_SAMPLED], TraceFlags.SAMPLED); + assert.deepStrictEqual(carrier[X_B3_SAMPLED], '1'); }); it('should set b3 traceId and spanId headers - ignore tracestate', () => { @@ -82,7 +82,7 @@ describe('B3Propagator', () => { 'd4cda95b652f4a1592b449d5929fda1b' ); assert.deepStrictEqual(carrier[X_B3_SPAN_ID], '6e0c63257de34c92'); - assert.deepStrictEqual(carrier[X_B3_SAMPLED], TraceFlags.NONE); + assert.deepStrictEqual(carrier[X_B3_SAMPLED], '0'); }); it('should not inject empty spancontext', () => { @@ -289,5 +289,21 @@ describe('B3Propagator', () => { assert.ok(ctx2 === Context.ROOT_CONTEXT); assert.ok(ctx3 === Context.ROOT_CONTEXT); }); + + it('should left-pad 64 bit trace ids with 0', () => { + carrier[X_B3_TRACE_ID] = '8448eb211c80319c'; + carrier[X_B3_SPAN_ID] = 'b7ad6b7169203331'; + carrier[X_B3_SAMPLED] = '1'; + const extractedSpanContext = getExtractedSpanContext( + b3Propagator.extract(Context.ROOT_CONTEXT, carrier, defaultGetter) + ); + + assert.deepStrictEqual(extractedSpanContext, { + spanId: 'b7ad6b7169203331', + traceId: '00000000000000008448eb211c80319c', + isRemote: true, + traceFlags: TraceFlags.SAMPLED, + }); + }); }); }); diff --git a/packages/opentelemetry-core/test/context/composite.test.ts b/packages/opentelemetry-core/test/context/composite.test.ts index 10a21af1f32..080b8021549 100644 --- a/packages/opentelemetry-core/test/context/composite.test.ts +++ b/packages/opentelemetry-core/test/context/composite.test.ts @@ -80,7 +80,7 @@ describe('Composite Propagator', () => { assert.strictEqual(carrier[X_B3_TRACE_ID], traceId); assert.strictEqual(carrier[X_B3_SPAN_ID], spanId); - assert.strictEqual(carrier[X_B3_SAMPLED], 1); + assert.strictEqual(carrier[X_B3_SAMPLED], '1'); assert.strictEqual( carrier[TRACE_PARENT_HEADER], `00-${traceId}-${spanId}-01` diff --git a/packages/opentelemetry-exporter-collector/package.json b/packages/opentelemetry-exporter-collector/package.json index 5b1e97497d2..27a209fa1a6 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.6.1", + "version": "0.7.0", "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", @@ -77,18 +77,17 @@ "ts-node": "^8.6.2", "tslint-consistent-codestyle": "^1.16.0", "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.4", + "typescript": "3.7.2", "webpack": "^4.35.2", "webpack-cli": "^3.3.9", "webpack-merge": "^4.2.2" }, "dependencies": { - "@grpc/proto-loader": "^0.5.3", - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/resources": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@grpc/proto-loader": "^0.5.3", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/resources": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "google-protobuf": "^3.11.4", "grpc": "^1.24.2" } diff --git a/packages/opentelemetry-exporter-collector/src/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/CollectorExporter.ts index 7199848da8e..070042b121b 100644 --- a/packages/opentelemetry-exporter-collector/src/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/CollectorExporter.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { ExportResult } from '@opentelemetry/base'; -import { NoopLogger } from '@opentelemetry/core'; +import { ExportResult, NoopLogger } from '@opentelemetry/core'; import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing'; import { Attributes, Logger } from '@opentelemetry/api'; import { onInit, onShutdown, sendSpans } from './platform/index'; diff --git a/packages/opentelemetry-exporter-collector/src/transform.ts b/packages/opentelemetry-exporter-collector/src/transform.ts index 580434c9908..3f67635ce67 100644 --- a/packages/opentelemetry-exporter-collector/src/transform.ts +++ b/packages/opentelemetry-exporter-collector/src/transform.ts @@ -21,7 +21,6 @@ import { TimedEvent, TraceState, } from '@opentelemetry/api'; -import { SDK_INFO } from '@opentelemetry/base'; import * as core from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/tracing'; @@ -218,8 +217,8 @@ export function toCollectorExportTraceServiceRequest( const instrumentationLibrarySpans: opentelemetryProto.trace.v1.InstrumentationLibrarySpans = { spans: spansToBeSent, instrumentationLibrary: { - name: name || `${SDK_INFO.NAME} - ${SDK_INFO.LANGUAGE}`, - version: SDK_INFO.VERSION, + name: name || `${core.SDK_INFO.NAME} - ${core.SDK_INFO.LANGUAGE}`, + version: core.SDK_INFO.VERSION, }, }; const resourceSpan: opentelemetryProto.trace.v1.ResourceSpans = { diff --git a/packages/opentelemetry-exporter-collector/src/version.ts b/packages/opentelemetry-exporter-collector/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts index 175222f0e48..749de6b2175 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { ExportResult } from '@opentelemetry/base'; -import { NoopLogger } from '@opentelemetry/core'; +import { ExportResult, NoopLogger } from '@opentelemetry/core'; import { ReadableSpan } from '@opentelemetry/tracing'; import * as assert from 'assert'; import * as sinon from 'sinon'; diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index 2cf7d799e1b..f02c158c0cd 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Exporter Jaeger allows user to send collected traces to Jaeger", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,7 +41,7 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/resources": "^0.6.1", + "@opentelemetry/resources": "^0.7.0", "@types/mocha": "^7.0.0", "@types/node": "^12.6.9", "codecov": "^3.6.1", @@ -57,10 +57,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "jaeger-client": "^3.15.0" } } diff --git a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts index acca9faa013..c64d4ba1189 100644 --- a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts +++ b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts @@ -15,8 +15,7 @@ */ import * as api from '@opentelemetry/api'; -import { ExportResult } from '@opentelemetry/base'; -import { NoopLogger } from '@opentelemetry/core'; +import { ExportResult, NoopLogger } from '@opentelemetry/core'; import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing'; import { Socket } from 'dgram'; import { spanToThrift } from './transform'; diff --git a/packages/opentelemetry-exporter-jaeger/src/types.ts b/packages/opentelemetry-exporter-jaeger/src/types.ts index 31c9bc82f0d..b99ef12e410 100644 --- a/packages/opentelemetry-exporter-jaeger/src/types.ts +++ b/packages/opentelemetry-exporter-jaeger/src/types.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; /** * Options for Jaeger configuration */ export interface ExporterConfig { - logger?: types.Logger; + logger?: api.Logger; serviceName: string; tags?: Tag[]; host?: string; // default: 'localhost' diff --git a/packages/opentelemetry-exporter-jaeger/src/version.ts b/packages/opentelemetry-exporter-jaeger/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts index 9c81c82dc6a..4ce9f5c748a 100644 --- a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts @@ -16,11 +16,10 @@ import * as assert from 'assert'; import { JaegerExporter } from '../src'; -import { NoopLogger } from '@opentelemetry/core'; -import * as types from '@opentelemetry/api'; +import { ExportResult, NoopLogger } from '@opentelemetry/core'; +import * as api from '@opentelemetry/api'; import { ThriftProcess } from '../src/types'; import { ReadableSpan } from '@opentelemetry/tracing'; -import { ExportResult } from '@opentelemetry/base'; import { TraceFlags } from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { OT_REQUEST_HEADER } from '../src/utils'; @@ -133,13 +132,13 @@ describe('JaegerExporter', () => { }; const readableSpan: ReadableSpan = { name: 'my-span1', - kind: types.SpanKind.CLIENT, + kind: api.SpanKind.CLIENT, spanContext, startTime: [1566156729, 709], endTime: [1566156731, 709], ended: true, status: { - code: types.CanonicalCode.DATA_LOSS, + code: api.CanonicalCode.DATA_LOSS, }, attributes: {}, links: [], diff --git a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts index c79fb6d1b65..58477ad0fb4 100644 --- a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts @@ -18,7 +18,7 @@ import * as assert from 'assert'; import { spanToThrift } from '../src/transform'; import { ReadableSpan } from '@opentelemetry/tracing'; import { Resource } from '@opentelemetry/resources'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { ThriftUtils, Utils, ThriftReferenceType } from '../src/types'; import { hrTimeToMicroseconds } from '@opentelemetry/core'; import { TraceFlags } from '@opentelemetry/api'; @@ -34,13 +34,13 @@ describe('transform', () => { it('should convert an OpenTelemetry span to a Thrift', () => { const readableSpan: ReadableSpan = { name: 'my-span', - kind: types.SpanKind.INTERNAL, + kind: api.SpanKind.INTERNAL, spanContext, startTime: [1566156729, 709], endTime: [1566156731, 709], ended: true, status: { - code: types.CanonicalCode.OK, + code: api.CanonicalCode.OK, }, attributes: { testBool: true, @@ -155,13 +155,13 @@ describe('transform', () => { it('should convert an OpenTelemetry span to a Thrift when links, events and attributes are empty', () => { const readableSpan: ReadableSpan = { name: 'my-span1', - kind: types.SpanKind.CLIENT, + kind: api.SpanKind.CLIENT, spanContext, startTime: [1566156729, 709], endTime: [1566156731, 709], ended: true, status: { - code: types.CanonicalCode.DATA_LOSS, + code: api.CanonicalCode.DATA_LOSS, message: 'data loss', }, attributes: {}, @@ -213,13 +213,13 @@ describe('transform', () => { it('should convert an OpenTelemetry span to a Thrift with ThriftReference', () => { const readableSpan: ReadableSpan = { name: 'my-span', - kind: types.SpanKind.INTERNAL, + kind: api.SpanKind.INTERNAL, spanContext, startTime: [1566156729, 709], endTime: [1566156731, 709], ended: true, status: { - code: types.CanonicalCode.OK, + code: api.CanonicalCode.OK, }, attributes: {}, parentSpanId: '3e0c63257de34c92', @@ -255,7 +255,7 @@ describe('transform', () => { it('should left pad trace ids', () => { const readableSpan: ReadableSpan = { name: 'my-span1', - kind: types.SpanKind.CLIENT, + kind: api.SpanKind.CLIENT, spanContext: { traceId: '92b449d5929fda1b', spanId: '6e0c63257de34c92', @@ -265,7 +265,7 @@ describe('transform', () => { endTime: [1566156731, 709], ended: true, status: { - code: types.CanonicalCode.DATA_LOSS, + code: api.CanonicalCode.DATA_LOSS, message: 'data loss', }, attributes: {}, diff --git a/packages/opentelemetry-exporter-prometheus/package.json b/packages/opentelemetry-exporter-prometheus/package.json index c2f69dc1714..d8c759f1be5 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Exporter Prometheus provides a metrics endpoint for Prometheus", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -54,10 +54,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/metrics": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/metrics": "^0.7.0", "prom-client": "^11.5.3" } } diff --git a/packages/opentelemetry-exporter-prometheus/src/export/types.ts b/packages/opentelemetry-exporter-prometheus/src/export/types.ts index bfdc74cc19f..c3a04f5d531 100644 --- a/packages/opentelemetry-exporter-prometheus/src/export/types.ts +++ b/packages/opentelemetry-exporter-prometheus/src/export/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; /** * Configuration interface for prometheus exporter @@ -49,5 +49,5 @@ export interface ExporterConfig { startServer?: boolean; /** Standard logging interface */ - logger?: types.Logger; + logger?: api.Logger; } diff --git a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts index 9d266ecdc17..9e745f62669 100644 --- a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts +++ b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import { ExportResult } from '@opentelemetry/base'; -import { NoopLogger, hrTimeToMilliseconds } from '@opentelemetry/core'; +import { + ExportResult, + NoopLogger, + hrTimeToMilliseconds, +} from '@opentelemetry/core'; import { CounterSumAggregator, LastValue, @@ -26,7 +29,7 @@ import { ObserverAggregator, Sum, } from '@opentelemetry/metrics'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { createServer, IncomingMessage, Server, ServerResponse } from 'http'; import { Counter, Gauge, labelValues, Metric, Registry } from 'prom-client'; import * as url from 'url'; @@ -41,7 +44,7 @@ export class PrometheusExporter implements MetricExporter { }; private readonly _registry = new Registry(); - private readonly _logger: types.Logger; + private readonly _logger: api.Logger; private readonly _port: number; private readonly _endpoint: string; private readonly _server: Server; @@ -156,7 +159,7 @@ export class PrometheusExporter implements MetricExporter { // TODO: only counter and gauge are implemented in metrics so far } - private _getLabelValues(keys: string[], labels: types.Labels) { + private _getLabelValues(keys: string[], labels: api.Labels) { const labelValues: labelValues = {}; for (let i = 0; i < keys.length; i++) { if (labels[keys[i]] !== null) { diff --git a/packages/opentelemetry-exporter-prometheus/src/version.ts b/packages/opentelemetry-exporter-prometheus/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts index 2ed9852a542..6475d69cfbb 100644 --- a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts +++ b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts @@ -522,8 +522,5 @@ describe('PrometheusExporter', () => { }); function errorHandler(done: Mocha.Done): (err: Error) => void { - return () => { - assert.ok(false, 'error getting metrics'); - done(); - }; + return err => done(err); } diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index f36753df11c..5dea64a4fb6 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry Zipkin Exporter allows the user to send collected traces to Zipkin.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -54,10 +54,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/resources": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/resources": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" } } diff --git a/packages/opentelemetry-exporter-zipkin/src/transform.ts b/packages/opentelemetry-exporter-zipkin/src/transform.ts index b52e152f7af..b92d3e2f231 100644 --- a/packages/opentelemetry-exporter-zipkin/src/transform.ts +++ b/packages/opentelemetry-exporter-zipkin/src/transform.ts @@ -14,19 +14,19 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { ReadableSpan } from '@opentelemetry/tracing'; import { hrTimeToMicroseconds } from '@opentelemetry/core'; import * as zipkinTypes from './types'; import { Resource } from '@opentelemetry/resources'; const ZIPKIN_SPAN_KIND_MAPPING = { - [types.SpanKind.CLIENT]: zipkinTypes.SpanKind.CLIENT, - [types.SpanKind.SERVER]: zipkinTypes.SpanKind.SERVER, - [types.SpanKind.CONSUMER]: zipkinTypes.SpanKind.CONSUMER, - [types.SpanKind.PRODUCER]: zipkinTypes.SpanKind.PRODUCER, + [api.SpanKind.CLIENT]: zipkinTypes.SpanKind.CLIENT, + [api.SpanKind.SERVER]: zipkinTypes.SpanKind.SERVER, + [api.SpanKind.CONSUMER]: zipkinTypes.SpanKind.CONSUMER, + [api.SpanKind.PRODUCER]: zipkinTypes.SpanKind.PRODUCER, // When absent, the span is local. - [types.SpanKind.INTERNAL]: undefined, + [api.SpanKind.INTERNAL]: undefined, }; export const statusCodeTagName = 'ot.status_code'; @@ -68,8 +68,8 @@ export function toZipkinSpan( /** Converts OpenTelemetry Attributes and Status to Zipkin Tags format. */ export function _toZipkinTags( - attributes: types.Attributes, - status: types.Status, + attributes: api.Attributes, + status: api.Status, statusCodeTagName: string, statusDescriptionTagName: string, resource: Resource @@ -78,7 +78,7 @@ export function _toZipkinTags( for (const key of Object.keys(attributes)) { tags[key] = String(attributes[key]); } - tags[statusCodeTagName] = String(types.CanonicalCode[status.code]); + tags[statusCodeTagName] = String(api.CanonicalCode[status.code]); if (status.message) { tags[statusDescriptionTagName] = status.message; } @@ -94,7 +94,7 @@ export function _toZipkinTags( * Converts OpenTelemetry Events to Zipkin Annotations format. */ export function _toZipkinAnnotations( - events: types.TimedEvent[] + events: api.TimedEvent[] ): zipkinTypes.Annotation[] { return events.map(event => ({ timestamp: hrTimeToMicroseconds(event.time), diff --git a/packages/opentelemetry-exporter-zipkin/src/types.ts b/packages/opentelemetry-exporter-zipkin/src/types.ts index 343faf09b64..051673d5829 100644 --- a/packages/opentelemetry-exporter-zipkin/src/types.ts +++ b/packages/opentelemetry-exporter-zipkin/src/types.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; /** * Exporter config */ export interface ExporterConfig { - logger?: types.Logger; + logger?: api.Logger; serviceName: string; url?: string; // Optional mapping overrides for OpenTelemetry status code and description. diff --git a/packages/opentelemetry-exporter-zipkin/src/version.ts b/packages/opentelemetry-exporter-zipkin/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts index 56a06469f20..39906b3d76d 100644 --- a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts +++ b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import * as http from 'http'; import * as https from 'https'; import * as url from 'url'; -import { NoopLogger } from '@opentelemetry/core'; +import { ExportResult, NoopLogger } from '@opentelemetry/core'; import { SpanExporter, ReadableSpan } from '@opentelemetry/tracing'; -import { ExportResult } from '@opentelemetry/base'; import * as zipkinTypes from './types'; import { toZipkinSpan, @@ -33,7 +32,7 @@ import { OT_REQUEST_HEADER } from './utils'; */ export class ZipkinExporter implements SpanExporter { static readonly DEFAULT_URL = 'http://localhost:9411/api/v2/spans'; - private readonly _logger: types.Logger; + private readonly _logger: api.Logger; private readonly _serviceName: string; private readonly _statusCodeTagName: string; private readonly _statusDescriptionTagName: string; diff --git a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts index 6f5854d2e6b..0bb180c1800 100644 --- a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts @@ -15,7 +15,7 @@ */ import * as assert from 'assert'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { Span, BasicTracerProvider } from '@opentelemetry/tracing'; import { NoopLogger, @@ -38,10 +38,10 @@ const tracer = new BasicTracerProvider({ logger, }).getTracer('default'); const parentId = '5c1c63257de34c67'; -const spanContext: types.SpanContext = { +const spanContext: api.SpanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', spanId: '6e0c63257de34c92', - traceFlags: types.TraceFlags.SAMPLED, + traceFlags: api.TraceFlags.SAMPLED, }; const DUMMY_RESOUCE = new Resource({ @@ -57,7 +57,7 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER, + api.SpanKind.SERVER, parentId ); span.setAttributes({ @@ -68,7 +68,7 @@ describe('transform', () => { span.end(); const zipkinSpan = toZipkinSpan( - span.toReadableSpan(), + span, 'my-service', statusCodeTagName, statusDescriptionTagName @@ -107,12 +107,12 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER + api.SpanKind.SERVER ); span.end(); const zipkinSpan = toZipkinSpan( - span.toReadableSpan(), + span, 'my-service', statusCodeTagName, statusDescriptionTagName @@ -141,20 +141,20 @@ describe('transform', () => { }); // SpanKind mapping tests [ - { ot: types.SpanKind.CLIENT, zipkin: 'CLIENT' }, - { ot: types.SpanKind.SERVER, zipkin: 'SERVER' }, - { ot: types.SpanKind.CONSUMER, zipkin: 'CONSUMER' }, - { ot: types.SpanKind.PRODUCER, zipkin: 'PRODUCER' }, - { ot: types.SpanKind.INTERNAL, zipkin: undefined }, + { ot: api.SpanKind.CLIENT, zipkin: 'CLIENT' }, + { ot: api.SpanKind.SERVER, zipkin: 'SERVER' }, + { ot: api.SpanKind.CONSUMER, zipkin: 'CONSUMER' }, + { ot: api.SpanKind.PRODUCER, zipkin: 'PRODUCER' }, + { ot: api.SpanKind.INTERNAL, zipkin: undefined }, ].forEach(item => it(`should map OpenTelemetry SpanKind ${ - types.SpanKind[item.ot] + api.SpanKind[item.ot] } to Zipkin ${item.zipkin}`, () => { const span = new Span(tracer, 'my-span', spanContext, item.ot); span.end(); const zipkinSpan = toZipkinSpan( - span.toReadableSpan(), + span, 'my-service', statusCodeTagName, statusDescriptionTagName @@ -190,7 +190,7 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER, + api.SpanKind.SERVER, parentId ); span.setAttributes({ @@ -219,11 +219,11 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER, + api.SpanKind.SERVER, parentId ); - const status: types.Status = { - code: types.CanonicalCode.ABORTED, + const status: api.Status = { + code: api.CanonicalCode.ABORTED, }; span.setStatus(status); span.setAttributes({ @@ -249,11 +249,11 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER, + api.SpanKind.SERVER, parentId ); - const status: types.Status = { - code: types.CanonicalCode.ABORTED, + const status: api.Status = { + code: api.CanonicalCode.ABORTED, message: 'my-message', }; span.setStatus(status); @@ -284,7 +284,7 @@ describe('transform', () => { tracer, 'my-span', spanContext, - types.SpanKind.SERVER, + api.SpanKind.SERVER, parentId ); span.addEvent('my-event1'); diff --git a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts index bd0105e5536..2adbca51e58 100644 --- a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts @@ -17,9 +17,12 @@ import * as assert from 'assert'; import * as nock from 'nock'; import { ReadableSpan } from '@opentelemetry/tracing'; -import { ExportResult } from '@opentelemetry/base'; -import { NoopLogger, hrTimeToMicroseconds } from '@opentelemetry/core'; -import * as types from '@opentelemetry/api'; +import { + ExportResult, + NoopLogger, + hrTimeToMicroseconds, +} from '@opentelemetry/core'; +import * as api from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { ZipkinExporter } from '../src'; import * as zipkinTypes from '../src/types'; @@ -33,7 +36,7 @@ function getReadableSpan() { const duration = 2000; const readableSpan: ReadableSpan = { name: 'my-span', - kind: types.SpanKind.INTERNAL, + kind: api.SpanKind.INTERNAL, spanContext: { traceId: 'd4cda95b652f4a1592b449d5929fda1b', spanId: '6e0c63257de34c92', @@ -44,7 +47,7 @@ function getReadableSpan() { ended: true, duration: [duration, 0], status: { - code: types.CanonicalCode.OK, + code: api.CanonicalCode.OK, }, attributes: {}, links: [], @@ -130,7 +133,7 @@ describe('ZipkinExporter', () => { const span1: ReadableSpan = { name: 'my-span', - kind: types.SpanKind.INTERNAL, + kind: api.SpanKind.INTERNAL, parentSpanId, spanContext: { traceId: 'd4cda95b652f4a1592b449d5929fda1b', @@ -142,7 +145,7 @@ describe('ZipkinExporter', () => { ended: true, duration: [duration, 0], status: { - code: types.CanonicalCode.OK, + code: api.CanonicalCode.OK, }, attributes: { key1: 'value1', @@ -160,7 +163,7 @@ describe('ZipkinExporter', () => { }; const span2: ReadableSpan = { name: 'my-span', - kind: types.SpanKind.SERVER, + kind: api.SpanKind.SERVER, spanContext: { traceId: 'd4cda95b652f4a1592b449d5929fda1b', spanId: '6e0c63257de34c92', @@ -171,7 +174,7 @@ describe('ZipkinExporter', () => { ended: true, duration: [duration, 0], status: { - code: types.CanonicalCode.OK, + code: api.CanonicalCode.OK, }, attributes: {}, links: [], diff --git a/packages/opentelemetry-metrics/README.md b/packages/opentelemetry-metrics/README.md index eb516f6948d..1de26eab567 100644 --- a/packages/opentelemetry-metrics/README.md +++ b/packages/opentelemetry-metrics/README.md @@ -25,8 +25,8 @@ const { MeterProvider } = require('@opentelemetry/metrics'); const meter = new MeterProvider().getMeter('your-meter-name'); const counter = meter.createCounter('metric_name', { - labelKeys: ["pid"], - description: "Example of a counter" + labelKeys: ['pid'], + description: 'Example of a counter' }); const labels = { pid: process.pid }; @@ -34,6 +34,41 @@ const labels = { pid: process.pid }; // Create a BoundInstrument associated with specified label values. const boundCounter = counter.bind(labels); boundCounter.add(10); + +``` + +### Observable +Choose this kind of metric when only last value is important without worry about aggregation + +```js +const { MeterProvider, MetricObservable } = require('@opentelemetry/metrics'); + +// Initialize the Meter to capture measurements in various ways. +const meter = new MeterProvider().getMeter('your-meter-name'); + +const observer = meter.createObserver('metric_name', { + labelKeys: ['pid', 'core'], + description: 'Example of a observer' +}); + +function getCpuUsage() { + return Math.random(); +} + +const metricObservable = new MetricObservable(); + +observer.setCallback((observerResult) => { + // synchronous callback + observerResult.observe(getCpuUsage, { pid: process.pid, core: '1' }); + // asynchronous callback + observerResult.observe(metricObservable, { pid: process.pid, core: '2' }); +}); + +// simulate asynchronous operation +setInterval(()=> { + metricObservable.next(getCpuUsage()); +}, 2000) + ``` See [examples/prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/prometheus) for a short example. diff --git a/packages/opentelemetry-metrics/package.json b/packages/opentelemetry-metrics/package.json index a4c02a7a9e7..9ea621828e7 100644 --- a/packages/opentelemetry-metrics/package.json +++ b/packages/opentelemetry-metrics/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/metrics", - "version": "0.6.1", + "version": "0.7.0", "description": "OpenTelemetry metrics SDK", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -57,9 +57,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/resources": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/resources": "^0.7.0" } } diff --git a/packages/opentelemetry-metrics/src/BoundInstrument.ts b/packages/opentelemetry-metrics/src/BoundInstrument.ts index e7db73dd401..d451bcb6011 100644 --- a/packages/opentelemetry-metrics/src/BoundInstrument.ts +++ b/packages/opentelemetry-metrics/src/BoundInstrument.ts @@ -14,25 +14,24 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { Aggregator } from './export/types'; -import { ObserverResult } from './ObserverResult'; /** * This class represent the base to BoundInstrument, which is responsible for generating * the TimeSeries. */ export class BaseBoundInstrument { - protected _labels: types.Labels; - protected _logger: types.Logger; + protected _labels: api.Labels; + protected _logger: api.Logger; protected _monotonic: boolean; constructor( - labels: types.Labels, - logger: types.Logger, + labels: api.Labels, + logger: api.Logger, monotonic: boolean, private readonly _disabled: boolean, - private readonly _valueType: types.ValueType, + private readonly _valueType: api.ValueType, private readonly _aggregator: Aggregator ) { this._labels = labels; @@ -43,7 +42,7 @@ export class BaseBoundInstrument { update(value: number): void { if (this._disabled) return; - if (this._valueType === types.ValueType.INT && !Number.isInteger(value)) { + if (this._valueType === api.ValueType.INT && !Number.isInteger(value)) { this._logger.warn( `INT value type cannot accept a floating-point value for ${Object.values( this._labels @@ -55,7 +54,7 @@ export class BaseBoundInstrument { this._aggregator.update(value); } - getLabels(): types.Labels { + getLabels(): api.Labels { return this._labels; } @@ -69,13 +68,13 @@ export class BaseBoundInstrument { * value of single instrument in the `Counter` associated with specified Labels. */ export class BoundCounter extends BaseBoundInstrument - implements types.BoundCounter { + implements api.BoundCounter { constructor( - labels: types.Labels, + labels: api.Labels, disabled: boolean, monotonic: boolean, - valueType: types.ValueType, - logger: types.Logger, + valueType: api.ValueType, + logger: api.Logger, aggregator: Aggregator ) { super(labels, logger, monotonic, disabled, valueType, aggregator); @@ -97,16 +96,16 @@ export class BoundCounter extends BaseBoundInstrument * BoundMeasure is an implementation of the {@link BoundMeasure} interface. */ export class BoundMeasure extends BaseBoundInstrument - implements types.BoundMeasure { + implements api.BoundMeasure { private readonly _absolute: boolean; constructor( - labels: types.Labels, + labels: api.Labels, disabled: boolean, monotonic: boolean, absolute: boolean, - valueType: types.ValueType, - logger: types.Logger, + valueType: api.ValueType, + logger: api.Logger, aggregator: Aggregator ) { super(labels, logger, monotonic, disabled, valueType, aggregator); @@ -115,8 +114,8 @@ export class BoundMeasure extends BaseBoundInstrument record( value: number, - correlationContext?: types.CorrelationContext, - spanContext?: types.SpanContext + correlationContext?: api.CorrelationContext, + spanContext?: api.SpanContext ): void { if (this._absolute && value < 0) { this._logger.error( @@ -134,21 +133,15 @@ export class BoundMeasure extends BaseBoundInstrument /** * BoundObserver is an implementation of the {@link BoundObserver} interface. */ -export class BoundObserver extends BaseBoundInstrument - implements types.BoundObserver { +export class BoundObserver extends BaseBoundInstrument { constructor( - labels: types.Labels, + labels: api.Labels, disabled: boolean, monotonic: boolean, - valueType: types.ValueType, - logger: types.Logger, + valueType: api.ValueType, + logger: api.Logger, aggregator: Aggregator ) { super(labels, logger, monotonic, disabled, valueType, aggregator); } - - setCallback(callback: (observerResult: types.ObserverResult) => void): void { - const observerResult = new ObserverResult(); - callback(observerResult); - } } diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts index 091a96b435d..ee2d5a5427c 100644 --- a/packages/opentelemetry-metrics/src/Meter.ts +++ b/packages/opentelemetry-metrics/src/Meter.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { ConsoleLogger } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { BaseBoundInstrument } from './BoundInstrument'; @@ -32,8 +32,8 @@ import { NoopExporter } from './export/NoopExporter'; /** * Meter is an implementation of the {@link Meter} interface. */ -export class Meter implements types.Meter { - private readonly _logger: types.Logger; +export class Meter implements api.Meter { + private readonly _logger: api.Logger; private readonly _metrics = new Map>(); private readonly _batcher: Batcher; private readonly _resource: Resource; @@ -56,15 +56,12 @@ export class Meter implements types.Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createMeasure( - name: string, - options?: types.MetricOptions - ): types.Metric { + createMeasure(name: string, options?: api.MetricOptions): api.Measure { if (!this._isValidName(name)) { this._logger.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return types.NOOP_MEASURE_METRIC; + return api.NOOP_MEASURE_METRIC; } const opt: MetricOptions = { absolute: true, // Measures are defined as absolute by default @@ -86,15 +83,12 @@ export class Meter implements types.Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createCounter( - name: string, - options?: types.MetricOptions - ): types.Metric { + createCounter(name: string, options?: api.MetricOptions): api.Counter { if (!this._isValidName(name)) { this._logger.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return types.NOOP_COUNTER_METRIC; + return api.NOOP_COUNTER_METRIC; } const opt: MetricOptions = { monotonic: true, // Counters are defined as monotonic by default @@ -113,15 +107,12 @@ export class Meter implements types.Meter { * @param name the name of the metric. * @param [options] the metric options. */ - createObserver( - name: string, - options?: types.MetricOptions - ): types.Metric { + createObserver(name: string, options?: api.MetricOptions): api.Observer { if (!this._isValidName(name)) { this._logger.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return types.NOOP_OBSERVER_METRIC; + return api.NOOP_OBSERVER_METRIC; } const opt: MetricOptions = { monotonic: false, // Observers are defined as non-monotonic by default diff --git a/packages/opentelemetry-metrics/src/MeterProvider.ts b/packages/opentelemetry-metrics/src/MeterProvider.ts index 09bd9f8e66a..0315a76e35d 100644 --- a/packages/opentelemetry-metrics/src/MeterProvider.ts +++ b/packages/opentelemetry-metrics/src/MeterProvider.ts @@ -15,7 +15,7 @@ */ import { ConsoleLogger } from '@opentelemetry/core'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { Meter } from '.'; import { DEFAULT_CONFIG, MeterConfig } from './types'; @@ -23,13 +23,19 @@ import { DEFAULT_CONFIG, MeterConfig } from './types'; /** * This class represents a meter provider which platform libraries can extend */ -export class MeterProvider implements types.MeterProvider { +export class MeterProvider implements api.MeterProvider { + private readonly _config: MeterConfig; private readonly _meters: Map = new Map(); - readonly resource: Resource = Resource.createTelemetrySDKResource(); - readonly logger: types.Logger; + readonly resource: Resource; + readonly logger: api.Logger; - constructor(private _config: MeterConfig = DEFAULT_CONFIG) { - this.logger = _config.logger || new ConsoleLogger(_config.logLevel); + constructor(config: MeterConfig = DEFAULT_CONFIG) { + this.logger = config.logger ?? new ConsoleLogger(config.logLevel); + this.resource = config.resource ?? Resource.createTelemetrySDKResource(); + this._config = Object.assign({}, config, { + logger: this.logger, + resource: this.resource, + }); } /** diff --git a/packages/opentelemetry-metrics/src/Metric.ts b/packages/opentelemetry-metrics/src/Metric.ts index 6d81b4e2f2f..ce9d89df520 100644 --- a/packages/opentelemetry-metrics/src/Metric.ts +++ b/packages/opentelemetry-metrics/src/Metric.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { BoundCounter, @@ -30,12 +30,12 @@ import { hashLabels } from './Utils'; /** This is a SDK implementation of {@link Metric} interface. */ export abstract class Metric - implements types.Metric { + implements api.UnboundMetric { protected readonly _monotonic: boolean; protected readonly _disabled: boolean; - protected readonly _valueType: types.ValueType; - protected readonly _logger: types.Logger; - private readonly _descriptor: MetricDescriptor; + protected readonly _valueType: api.ValueType; + protected readonly _logger: api.Logger; + protected readonly _descriptor: MetricDescriptor; private readonly _instruments: Map = new Map(); constructor( @@ -58,7 +58,7 @@ export abstract class Metric * @param labels key-values pairs that are associated with a specific metric * that you want to record. */ - bind(labels: types.Labels): T { + bind(labels: api.Labels): T { const hash = hashLabels(labels); if (this._instruments.has(hash)) return this._instruments.get(hash)!; @@ -71,7 +71,7 @@ export abstract class Metric * Removes the Instrument from the metric, if it is present. * @param labels key-values pairs that are associated with a specific metric. */ - unbind(labels: types.Labels): void { + unbind(labels: api.Labels): void { this._instruments.delete(hashLabels(labels)); } @@ -102,12 +102,11 @@ export abstract class Metric }; } - protected abstract _makeInstrument(labels: types.Labels): T; + protected abstract _makeInstrument(labels: api.Labels): T; } /** This is a SDK implementation of Counter Metric. */ -export class CounterMetric extends Metric - implements Pick { +export class CounterMetric extends Metric implements api.Counter { constructor( name: string, options: MetricOptions, @@ -116,7 +115,7 @@ export class CounterMetric extends Metric ) { super(name, options, MetricKind.COUNTER, resource); } - protected _makeInstrument(labels: types.Labels): BoundCounter { + protected _makeInstrument(labels: api.Labels): BoundCounter { return new BoundCounter( labels, this._disabled, @@ -124,7 +123,7 @@ export class CounterMetric extends Metric this._valueType, this._logger, // @todo: consider to set to CounterSumAggregator always. - this._batcher.aggregatorFor(MetricKind.COUNTER) + this._batcher.aggregatorFor(this._descriptor) ); } @@ -134,13 +133,12 @@ export class CounterMetric extends Metric * @param labels key-values pairs that are associated with a specific metric * that you want to record. */ - add(value: number, labels: types.Labels) { + add(value: number, labels: api.Labels) { this.bind(labels).add(value); } } -export class MeasureMetric extends Metric - implements Pick { +export class MeasureMetric extends Metric implements api.Measure { protected readonly _absolute: boolean; constructor( @@ -153,7 +151,7 @@ export class MeasureMetric extends Metric this._absolute = options.absolute !== undefined ? options.absolute : true; // Absolute default is true } - protected _makeInstrument(labels: types.Labels): BoundMeasure { + protected _makeInstrument(labels: api.Labels): BoundMeasure { return new BoundMeasure( labels, this._disabled, @@ -161,19 +159,19 @@ export class MeasureMetric extends Metric this._absolute, this._valueType, this._logger, - this._batcher.aggregatorFor(MetricKind.MEASURE) + this._batcher.aggregatorFor(this._descriptor) ); } - record(value: number, labels: types.Labels) { + record(value: number, labels: api.Labels) { this.bind(labels).record(value); } } /** This is a SDK implementation of Observer Metric. */ export class ObserverMetric extends Metric - implements Pick { - private _observerResult: types.ObserverResult = new ObserverResult(); + implements api.Observer { + private _observerResult = new ObserverResult(); constructor( name: string, @@ -184,19 +182,19 @@ export class ObserverMetric extends Metric super(name, options, MetricKind.OBSERVER, resource); } - protected _makeInstrument(labels: types.Labels): BoundObserver { + protected _makeInstrument(labels: api.Labels): BoundObserver { return new BoundObserver( labels, this._disabled, this._monotonic, this._valueType, this._logger, - this._batcher.aggregatorFor(MetricKind.OBSERVER) + this._batcher.aggregatorFor(this._descriptor) ); } getMetricRecord(): MetricRecord[] { - this._observerResult.observers.forEach((callback, labels) => { + this._observerResult.callbackObservers.forEach((callback, labels) => { const instrument = this.bind(labels); instrument.update(callback()); }); @@ -207,7 +205,13 @@ export class ObserverMetric extends Metric * Sets a callback where user can observe value for certain labels * @param callback */ - setCallback(callback: (observerResult: types.ObserverResult) => void): void { + setCallback(callback: (observerResult: api.ObserverResult) => void): void { callback(this._observerResult); + this._observerResult.observers.forEach((observer, labels) => { + observer.subscribe(value => { + const instrument = this.bind(labels); + instrument.update(value); + }); + }); } } diff --git a/packages/opentelemetry-metrics/src/MetricObservable.ts b/packages/opentelemetry-metrics/src/MetricObservable.ts new file mode 100644 index 00000000000..cd52774743c --- /dev/null +++ b/packages/opentelemetry-metrics/src/MetricObservable.ts @@ -0,0 +1,51 @@ +/*! + * 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 api from '@opentelemetry/api'; + +type Subscriber = (value?: number) => void; + +/** + * Implements the Metric Observable pattern + */ +export class MetricObservable implements api.MetricObservable { + private _subscribers: Subscriber[] = []; + + next(value: number) { + for (const subscriber of this._subscribers) { + subscriber(value); + } + } + + subscribe(subscriber: Function) { + if (typeof subscriber === 'function') { + this._subscribers.push(subscriber as Subscriber); + } + } + + unsubscribe(subscriber?: Function) { + if (typeof subscriber === 'function') { + for (let i = 0, j = this._subscribers.length; i < j; i++) { + if (this._subscribers[i] === subscriber) { + this._subscribers.splice(i, 1); + break; + } + } + } else { + this._subscribers = []; + } + } +} diff --git a/packages/opentelemetry-metrics/src/ObserverResult.ts b/packages/opentelemetry-metrics/src/ObserverResult.ts index 1cb9ecebd44..2ed593351d8 100644 --- a/packages/opentelemetry-metrics/src/ObserverResult.ts +++ b/packages/opentelemetry-metrics/src/ObserverResult.ts @@ -15,6 +15,7 @@ */ import { + MetricObservable, ObserverResult as TypeObserverResult, Labels, } from '@opentelemetry/api'; @@ -23,8 +24,17 @@ import { * Implementation of {@link TypeObserverResult} */ export class ObserverResult implements TypeObserverResult { - observers = new Map(); - observe(callback: any, labels: Labels): void { - this.observers.set(labels, callback); + callbackObservers: Map = new Map(); + observers: Map = new Map< + Labels, + MetricObservable + >(); + + observe(callback: Function | MetricObservable, labels: Labels): void { + if (typeof callback === 'function') { + this.callbackObservers.set(labels, callback); + } else { + this.observers.set(labels, callback); + } } } diff --git a/packages/opentelemetry-metrics/src/export/Batcher.ts b/packages/opentelemetry-metrics/src/export/Batcher.ts index 7caec738381..7b2fbd417f5 100644 --- a/packages/opentelemetry-metrics/src/export/Batcher.ts +++ b/packages/opentelemetry-metrics/src/export/Batcher.ts @@ -18,8 +18,13 @@ import { CounterSumAggregator, MeasureExactAggregator, ObserverAggregator, -} from './Aggregator'; -import { MetricRecord, MetricKind, Aggregator } from './types'; +} from './aggregators'; +import { + MetricRecord, + MetricKind, + Aggregator, + MetricDescriptor, +} from './types'; /** * Base class for all batcher types. @@ -31,8 +36,8 @@ import { MetricRecord, MetricKind, Aggregator } from './types'; export abstract class Batcher { protected readonly _batchMap = new Map(); - /** Returns an aggregator based off metric kind. */ - abstract aggregatorFor(metricKind: MetricKind): Aggregator; + /** Returns an aggregator based off metric descriptor. */ + abstract aggregatorFor(metricKind: MetricDescriptor): Aggregator; /** Stores record information to be ready for exporting. */ abstract process(record: MetricRecord): void; @@ -47,8 +52,8 @@ export abstract class Batcher { * passes them for exporting. */ export class UngroupedBatcher extends Batcher { - aggregatorFor(metricKind: MetricKind): Aggregator { - switch (metricKind) { + aggregatorFor(metricDescriptor: MetricDescriptor): Aggregator { + switch (metricDescriptor.metricKind) { case MetricKind.COUNTER: return new CounterSumAggregator(); case MetricKind.OBSERVER: diff --git a/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts b/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts index 78e5efc069f..90f2f6be5d8 100644 --- a/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts +++ b/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts @@ -14,14 +14,8 @@ * limitations under the License. */ -import { - MetricExporter, - MetricRecord, - MetricKind, - Sum, - Distribution, -} from './types'; -import { ExportResult } from '@opentelemetry/base'; +import { MetricExporter, MetricRecord, Distribution, Histogram } from './types'; +import { ExportResult } from '@opentelemetry/core'; /** * This is implementation of {@link MetricExporter} that prints metrics data to @@ -35,25 +29,26 @@ export class ConsoleMetricExporter implements MetricExporter { for (const metric of metrics) { console.log(metric.descriptor); console.log(metric.labels); - switch (metric.descriptor.metricKind) { - case MetricKind.COUNTER: - const sum = metric.aggregator.toPoint().value as Sum; - console.log('value: ' + sum); - break; - default: - const distribution = metric.aggregator.toPoint() - .value as Distribution; - console.log( - 'min: ' + - distribution.min + - ', max: ' + - distribution.max + - ', count: ' + - distribution.count + - ', sum: ' + - distribution.sum - ); - break; + const point = metric.aggregator.toPoint(); + if (typeof point.value === 'number') { + console.log('value: ' + point.value); + } else if (typeof (point.value as Histogram).buckets === 'object') { + const histogram = point.value as Histogram; + console.log( + `count: ${histogram.count}, sum: ${histogram.sum}, buckets: ${histogram.buckets}` + ); + } else { + const distribution = point.value as Distribution; + console.log( + 'min: ' + + distribution.min + + ', max: ' + + distribution.max + + ', count: ' + + distribution.count + + ', sum: ' + + distribution.sum + ); } } return resultCallback(ExportResult.SUCCESS); diff --git a/packages/opentelemetry-metrics/src/export/Controller.ts b/packages/opentelemetry-metrics/src/export/Controller.ts index ccef3213eb6..5ce3d0ee681 100644 --- a/packages/opentelemetry-metrics/src/export/Controller.ts +++ b/packages/opentelemetry-metrics/src/export/Controller.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { unrefTimer } from '@opentelemetry/core'; +import { ExportResult, unrefTimer } from '@opentelemetry/core'; import { Meter } from '../Meter'; import { MetricExporter } from './types'; -import { ExportResult } from '@opentelemetry/base'; const DEFAULT_EXPORT_INTERVAL = 60_000; diff --git a/packages/opentelemetry-metrics/src/export/NoopExporter.ts b/packages/opentelemetry-metrics/src/export/NoopExporter.ts index 84eab150b8d..05b3694939a 100644 --- a/packages/opentelemetry-metrics/src/export/NoopExporter.ts +++ b/packages/opentelemetry-metrics/src/export/NoopExporter.ts @@ -15,7 +15,7 @@ */ import { MetricExporter, MetricRecord } from './types'; -import { ExportResult } from '@opentelemetry/base'; +import { ExportResult } from '@opentelemetry/core'; export class NoopExporter implements MetricExporter { // By default does nothing diff --git a/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts b/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts new file mode 100644 index 00000000000..6b1fdc1ee98 --- /dev/null +++ b/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts @@ -0,0 +1,37 @@ +/*! + * 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 { Aggregator, Point } from '../types'; +import { HrTime } from '@opentelemetry/api'; +import { hrTime } from '@opentelemetry/core'; + +/** Basic aggregator which calculates a Sum from individual measurements. */ +export class CounterSumAggregator implements Aggregator { + private _current: number = 0; + private _lastUpdateTime: HrTime = [0, 0]; + + update(value: number): void { + this._current += value; + this._lastUpdateTime = hrTime(); + } + + toPoint(): Point { + return { + value: this._current, + timestamp: this._lastUpdateTime, + }; + } +} diff --git a/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts b/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts new file mode 100644 index 00000000000..beae9090b9b --- /dev/null +++ b/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts @@ -0,0 +1,81 @@ +/*! + * 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 { Aggregator, Point, Histogram } from '../types'; +import { HrTime } from '@opentelemetry/api'; +import { hrTime } from '@opentelemetry/core'; + +/** + * Basic aggregator which observes events and counts them in pre-defined buckets + * and provides the total sum and count of all observations. + */ +export class HistogramAggregator implements Aggregator { + private _lastCheckpoint: Histogram; + private _currentCheckpoint: Histogram; + private _lastCheckpointTime: HrTime; + private readonly _boundaries: number[]; + + constructor(boundaries: number[]) { + if (boundaries === undefined || boundaries.length === 0) { + throw new Error(`HistogramAggregator should be created with boundaries.`); + } + // we need to an ordered set to be able to correctly compute count for each + // boundary since we'll iterate on each in order. + this._boundaries = boundaries.sort(); + this._lastCheckpoint = this._newEmptyCheckpoint(); + this._lastCheckpointTime = hrTime(); + this._currentCheckpoint = this._newEmptyCheckpoint(); + } + + update(value: number): void { + this._currentCheckpoint.count += 1; + this._currentCheckpoint.sum += value; + + for (let i = 0; i < this._boundaries.length; i++) { + if (value < this._boundaries[i]) { + this._currentCheckpoint.buckets.counts[i] += 1; + return; + } + } + + // value is above all observed boundaries + this._currentCheckpoint.buckets.counts[this._boundaries.length] += 1; + } + + reset(): void { + this._lastCheckpointTime = hrTime(); + this._lastCheckpoint = this._currentCheckpoint; + this._currentCheckpoint = this._newEmptyCheckpoint(); + } + + toPoint(): Point { + return { + value: this._lastCheckpoint, + timestamp: this._lastCheckpointTime, + }; + } + + private _newEmptyCheckpoint(): Histogram { + return { + buckets: { + boundaries: this._boundaries, + counts: this._boundaries.map(() => 0).concat([0]), + }, + sum: 0, + count: 0, + }; + } +} diff --git a/packages/opentelemetry-base/src/platform/browser/index.ts b/packages/opentelemetry-metrics/src/export/aggregators/index.ts similarity index 83% rename from packages/opentelemetry-base/src/platform/browser/index.ts rename to packages/opentelemetry-metrics/src/export/aggregators/index.ts index 953b08f4dac..938e1ad6e38 100644 --- a/packages/opentelemetry-base/src/platform/browser/index.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/index.ts @@ -14,4 +14,7 @@ * limitations under the License. */ -export * from './constants'; +export * from './countersum'; +export * from './observer'; +export * from './measureexact'; +export * from './histogram'; diff --git a/packages/opentelemetry-metrics/src/export/Aggregator.ts b/packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts similarity index 61% rename from packages/opentelemetry-metrics/src/export/Aggregator.ts rename to packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts index d8bd4373b9d..abbad0b4306 100644 --- a/packages/opentelemetry-metrics/src/export/Aggregator.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/measureexact.ts @@ -14,45 +14,10 @@ * limitations under the License. */ -import { Aggregator, Distribution, Point } from './types'; +import { Aggregator, Point } from '../types'; import { HrTime } from '@opentelemetry/api'; import { hrTime } from '@opentelemetry/core'; - -/** Basic aggregator which calculates a Sum from individual measurements. */ -export class CounterSumAggregator implements Aggregator { - private _current: number = 0; - private _lastUpdateTime: HrTime = [0, 0]; - - update(value: number): void { - this._current += value; - this._lastUpdateTime = hrTime(); - } - - toPoint(): Point { - return { - value: this._current, - timestamp: this._lastUpdateTime, - }; - } -} - -/** Basic aggregator for Observer which keeps the last recorded value. */ -export class ObserverAggregator implements Aggregator { - private _current: number = 0; - private _lastUpdateTime: HrTime = [0, 0]; - - update(value: number): void { - this._current = value; - this._lastUpdateTime = hrTime(); - } - - toPoint(): Point { - return { - value: this._current, - timestamp: this._lastUpdateTime, - }; - } -} +import { Distribution } from '../types'; /** Basic aggregator keeping all raw values (events, sum, max and min). */ export class MeasureExactAggregator implements Aggregator { diff --git a/packages/opentelemetry-base/src/platform/node/index.ts b/packages/opentelemetry-metrics/src/export/aggregators/observer.ts similarity index 52% rename from packages/opentelemetry-base/src/platform/node/index.ts rename to packages/opentelemetry-metrics/src/export/aggregators/observer.ts index 953b08f4dac..d1ba176c30f 100644 --- a/packages/opentelemetry-base/src/platform/node/index.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/observer.ts @@ -14,4 +14,24 @@ * limitations under the License. */ -export * from './constants'; +import { Aggregator, Point } from '../types'; +import { HrTime } from '@opentelemetry/api'; +import { hrTime } from '@opentelemetry/core'; + +/** Basic aggregator for Observer which keeps the last recorded value. */ +export class ObserverAggregator implements Aggregator { + private _current: number = 0; + private _lastUpdateTime: HrTime = [0, 0]; + + update(value: number): void { + this._current = value; + this._lastUpdateTime = hrTime(); + } + + toPoint(): Point { + return { + value: this._current, + timestamp: this._lastUpdateTime, + }; + } +} diff --git a/packages/opentelemetry-metrics/src/export/types.ts b/packages/opentelemetry-metrics/src/export/types.ts index ff4f1173eb0..cffe91bc47c 100644 --- a/packages/opentelemetry-metrics/src/export/types.ts +++ b/packages/opentelemetry-metrics/src/export/types.ts @@ -15,7 +15,7 @@ */ import { ValueType, HrTime, Labels } from '@opentelemetry/api'; -import { ExportResult } from '@opentelemetry/base'; +import { ExportResult } from '@opentelemetry/core'; /** The kind of metric. */ export enum MetricKind { @@ -37,6 +37,33 @@ export interface Distribution { sum: number; } +export interface Histogram { + /** + * Buckets are implemented using two different array: + * - boundaries contains every boundary (which are upper boundary for each slice) + * - counts contains count of event for each slice + * + * Note that we'll always have n+1 (where n is the number of boundaries) slice + * because we need to count event that are above the highest boundary. This is the + * reason why it's not implement using array of object, because the last slice + * dont have any boundary. + * + * Example if we measure the values: [5, 30, 5, 40, 5, 15, 15, 15, 25] + * with the boundaries [ 10, 20, 30 ], we will have the following state: + * + * buckets: { + * boundaries: [10, 20, 30], + * counts: [3, 3, 2, 1], + * } + */ + buckets: { + boundaries: number[]; + counts: number[]; + }; + sum: number; + count: number; +} + export interface MetricRecord { readonly descriptor: MetricDescriptor; readonly labels: Labels; @@ -80,6 +107,6 @@ export interface Aggregator { } export interface Point { - value: Sum | LastValue | Distribution; + value: Sum | LastValue | Distribution | Histogram; timestamp: HrTime; } diff --git a/packages/opentelemetry-metrics/src/index.ts b/packages/opentelemetry-metrics/src/index.ts index c9f158528f1..6cb01ff9a88 100644 --- a/packages/opentelemetry-metrics/src/index.ts +++ b/packages/opentelemetry-metrics/src/index.ts @@ -16,9 +16,9 @@ export * from './BoundInstrument'; export * from './Meter'; -export * from './Metric'; export * from './MeterProvider'; -export * from './export/Aggregator'; +export * from './Metric'; +export * from './MetricObservable'; +export * from './export/aggregators'; export * from './export/ConsoleMetricExporter'; export * from './export/types'; -export * from './export/Aggregator'; diff --git a/packages/opentelemetry-metrics/src/version.ts b/packages/opentelemetry-metrics/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-metrics/test/Batcher.test.ts b/packages/opentelemetry-metrics/test/Batcher.test.ts index c09998bd32d..72c68608bbe 100644 --- a/packages/opentelemetry-metrics/test/Batcher.test.ts +++ b/packages/opentelemetry-metrics/test/Batcher.test.ts @@ -15,16 +15,16 @@ */ import * as assert from 'assert'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { Meter, MeterProvider } from '../src'; describe('Batcher', () => { describe('Ungrouped', () => { let meter: Meter; - let fooCounter: types.BoundCounter; - let barCounter: types.BoundCounter; - let counter: types.Metric; + let fooCounter: api.BoundCounter; + let barCounter: api.BoundCounter; + let counter: api.Counter; beforeEach(() => { meter = new MeterProvider({ logger: new NoopLogger(), diff --git a/packages/opentelemetry-metrics/test/Meter.test.ts b/packages/opentelemetry-metrics/test/Meter.test.ts index dd028bec585..ffa85fe6345 100644 --- a/packages/opentelemetry-metrics/test/Meter.test.ts +++ b/packages/opentelemetry-metrics/test/Meter.test.ts @@ -27,13 +27,15 @@ import { ObserverMetric, MetricRecord, Aggregator, + MetricObservable, + MetricDescriptor, } from '../src'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { NoopLogger, hrTime, hrTimeToNanoseconds } from '@opentelemetry/core'; import { CounterSumAggregator, ObserverAggregator, -} from '../src/export/Aggregator'; +} from '../src/export/aggregators'; import { ValueType } from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { hashLabels } from '../src/Utils'; @@ -43,7 +45,7 @@ describe('Meter', () => { let meter: Meter; const keya = 'keya'; const keyb = 'keyb'; - const labels: types.Labels = { [keyb]: 'value2', [keya]: 'value1' }; + const labels: api.Labels = { [keyb]: 'value2', [keya]: 'value1' }; beforeEach(() => { meter = new MeterProvider({ @@ -198,7 +200,7 @@ describe('Meter', () => { // should skip below metric const counter2 = meter.createCounter('name1', { - valueType: types.ValueType.INT, + valueType: api.ValueType.INT, }) as CounterMetric; counter2.bind(labels).add(500); @@ -231,19 +233,19 @@ describe('Meter', () => { it('should return no op metric if name is an empty string', () => { const counter = meter.createCounter(''); - assert.ok(counter instanceof types.NoopMetric); + assert.ok(counter instanceof api.NoopMetric); }); it('should return no op metric if name does not start with a letter', () => { const counter1 = meter.createCounter('1name'); const counter_ = meter.createCounter('_name'); - assert.ok(counter1 instanceof types.NoopMetric); - assert.ok(counter_ instanceof types.NoopMetric); + assert.ok(counter1 instanceof api.NoopMetric); + assert.ok(counter_ instanceof api.NoopMetric); }); it('should return no op metric if name is an empty string contain only letters, numbers, ".", "_", and "-"', () => { const counter = meter.createCounter('name with invalid characters^&*('); - assert.ok(counter instanceof types.NoopMetric); + assert.ok(counter instanceof api.NoopMetric); }); }); }); @@ -290,19 +292,19 @@ describe('Meter', () => { describe('names', () => { it('should return no op metric if name is an empty string', () => { const measure = meter.createMeasure(''); - assert.ok(measure instanceof types.NoopMetric); + assert.ok(measure 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 types.NoopMetric); - assert.ok(measure_ instanceof types.NoopMetric); + assert.ok(measure1 instanceof api.NoopMetric); + assert.ok(measure_ 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 types.NoopMetric); + assert.ok(measure instanceof api.NoopMetric); }); }); @@ -440,6 +442,7 @@ describe('Meter', () => { }) as ObserverMetric; assert.ok(measure instanceof Metric); }); + it('should set callback and observe value ', () => { const measure = meter.createObserver('name', { description: 'desc', @@ -450,21 +453,28 @@ describe('Meter', () => { return Math.random(); } - measure.setCallback((observerResult: types.ObserverResult) => { + const metricObservable = new MetricObservable(); + + measure.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' }); observerResult.observe(getCpuUsage, { pid: '123', core: '4' }); + observerResult.observe(metricObservable, { pid: '123', core: '5' }); }); + metricObservable.next(0.123); + const metricRecords: MetricRecord[] = measure.getMetricRecord(); - assert.strictEqual(metricRecords.length, 4); + assert.strictEqual(metricRecords.length, 5); - const metric1 = metricRecords[0]; - const metric2 = metricRecords[1]; - const metric3 = metricRecords[2]; - const metric4 = metricRecords[3]; + const metric5 = metricRecords[0]; + assert.strictEqual(hashLabels(metric5.labels), '|#core:5,pid:123'); + const metric1 = metricRecords[1]; + const metric2 = metricRecords[2]; + const metric3 = metricRecords[3]; + const metric4 = metricRecords[4]; assert.strictEqual(hashLabels(metric1.labels), '|#core:1,pid:123'); assert.strictEqual(hashLabels(metric2.labels), '|#core:2,pid:123'); assert.strictEqual(hashLabels(metric3.labels), '|#core:3,pid:123'); @@ -474,6 +484,7 @@ describe('Meter', () => { ensureMetric(metric2); ensureMetric(metric3); ensureMetric(metric4); + ensureMetric(metric5); }); it('should return an observer with resource', () => { @@ -516,7 +527,7 @@ describe('Meter', () => { const counter = meter.createCounter('counter', { description: 'test', labelKeys: [key], - valueType: types.ValueType.INT, + valueType: api.ValueType.INT, }); const labels = { [key]: 'counter-value' }; const boundCounter = counter.bind(labels); @@ -556,7 +567,7 @@ class CustomBatcher extends Batcher { process(record: MetricRecord): void { throw new Error('process method not implemented.'); } - aggregatorFor(metricKind: MetricKind): Aggregator { + aggregatorFor(metricKind: MetricDescriptor): Aggregator { throw new Error('aggregatorFor method not implemented.'); } } diff --git a/packages/opentelemetry-metrics/test/MeterProvider.test.ts b/packages/opentelemetry-metrics/test/MeterProvider.test.ts index 82877759b36..45c54db6bb7 100644 --- a/packages/opentelemetry-metrics/test/MeterProvider.test.ts +++ b/packages/opentelemetry-metrics/test/MeterProvider.test.ts @@ -15,7 +15,7 @@ */ import * as assert from 'assert'; -import { MeterProvider, Meter } from '../src'; +import { MeterProvider, Meter, CounterMetric } from '../src'; import { NoopLogger } from '@opentelemetry/core'; describe('MeterProvider', () => { @@ -39,6 +39,14 @@ describe('MeterProvider', () => { assert.ok(meter instanceof Meter); }); + it('should propagate resources', () => { + const meterProvider = new MeterProvider(); + const meter = meterProvider.getMeter('test-meter-provider'); + const counter = meter.createCounter('test-counter') as CounterMetric; + assert.strictEqual((meter as any)._resource, meterProvider.resource); + assert.strictEqual(counter.resource, meterProvider.resource); + }); + it('should return the meter with default version without a version option', () => { const provider = new MeterProvider(); const meter1 = provider.getMeter('default'); diff --git a/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts b/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts new file mode 100644 index 00000000000..efb1c6519af --- /dev/null +++ b/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts @@ -0,0 +1,158 @@ +/*! + * Copyright 2019, 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 { HistogramAggregator } from '../../../src/export/aggregators'; +import { Histogram } from '../../../src'; + +describe('HistogramAggregator', () => { + describe('constructor()', () => { + it('should construct a histogramAggregator', () => { + assert.doesNotThrow(() => { + new HistogramAggregator([1, 2]); + }); + }); + + it('should sort boundaries', () => { + const aggregator = new HistogramAggregator([500, 300, 700]); + const point = aggregator.toPoint().value as Histogram; + assert.deepEqual(point.buckets.boundaries, [300, 500, 700]); + }); + + it('should throw if no boundaries are defined', () => { + // @ts-ignore + assert.throws(() => new HistogramAggregator()); + assert.throws(() => new HistogramAggregator([])); + }); + }); + + describe('.update()', () => { + it('should not update checkpoint', () => { + const aggregator = new HistogramAggregator([100, 200]); + aggregator.update(150); + const point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 0); + assert.equal(point.sum, 0); + }); + + it('should update the second bucket', () => { + const aggregator = new HistogramAggregator([100, 200]); + aggregator.update(150); + aggregator.reset(); + const point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 1); + assert.equal(point.sum, 150); + assert.equal(point.buckets.counts[0], 0); + assert.equal(point.buckets.counts[1], 1); + assert.equal(point.buckets.counts[2], 0); + }); + + it('should update the second bucket', () => { + const aggregator = new HistogramAggregator([100, 200]); + aggregator.update(50); + aggregator.reset(); + const point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 1); + assert.equal(point.sum, 50); + assert.equal(point.buckets.counts[0], 1); + assert.equal(point.buckets.counts[1], 0); + assert.equal(point.buckets.counts[2], 0); + }); + + it('should update the third bucket since value is above all boundaries', () => { + const aggregator = new HistogramAggregator([100, 200]); + aggregator.update(250); + aggregator.reset(); + const point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 1); + assert.equal(point.sum, 250); + assert.equal(point.buckets.counts[0], 0); + assert.equal(point.buckets.counts[1], 0); + assert.equal(point.buckets.counts[2], 1); + }); + }); + + describe('.count', () => { + it('should return last checkpoint count', () => { + const aggregator = new HistogramAggregator([100]); + let point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, point.count); + aggregator.update(10); + aggregator.reset(); + point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 1); + assert.equal(point.count, point.count); + }); + }); + + describe('.sum', () => { + it('should return last checkpoint sum', () => { + const aggregator = new HistogramAggregator([100]); + let point = aggregator.toPoint().value as Histogram; + assert.equal(point.sum, point.sum); + aggregator.update(10); + aggregator.reset(); + point = aggregator.toPoint().value as Histogram; + assert.equal(point.sum, 10); + }); + }); + + describe('.reset()', () => { + it('should create a empty checkoint by default', () => { + const aggregator = new HistogramAggregator([100]); + const point = aggregator.toPoint().value as Histogram; + assert.deepEqual(point.buckets.boundaries, [100]); + assert(point.buckets.counts.every(count => count === 0)); + // should contains one bucket for each boundary + one for values outside of the largest boundary + assert.equal(point.buckets.counts.length, 2); + assert.deepEqual(point.buckets.boundaries, [100]); + assert.equal(point.count, 0); + assert.equal(point.sum, 0); + }); + + it('should update checkpoint', () => { + const aggregator = new HistogramAggregator([100]); + aggregator.update(10); + aggregator.reset(); + const point = aggregator.toPoint().value as Histogram; + assert.equal(point.count, 1); + assert.equal(point.sum, 10); + assert.deepEqual(point.buckets.boundaries, [100]); + assert.equal(point.buckets.counts.length, 2); + assert.deepEqual(point.buckets.counts, [1, 0]); + }); + }); + + describe('.toPoint()', () => { + it('should return default checkpoint', () => { + const aggregator = new HistogramAggregator([100]); + const point = aggregator.toPoint().value as Histogram; + assert.deepEqual(aggregator.toPoint().value, point); + assert(aggregator.toPoint().timestamp.every(nbr => nbr > 0)); + }); + + it('should return last checkpoint if updated', () => { + const aggregator = new HistogramAggregator([100]); + aggregator.update(100); + aggregator.reset(); + assert( + aggregator + .toPoint() + .timestamp.every(nbr => typeof nbr === 'number' && nbr !== 0) + ); + }); + }); +}); diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 9a78149ffe4..e2eb356c3da 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/node", - "version": "0.6.1", + "version": "0.7.0", "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,8 +41,8 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/resources": "^0.6.1", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/resources": "^0.7.0", "@types/mocha": "^7.0.0", "@types/node": "^12.6.8", "@types/semver": "^6.0.1", @@ -60,10 +60,10 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/context-async-hooks": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/context-async-hooks": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "require-in-the-middle": "^5.0.0", "semver": "^7.1.3" } diff --git a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts index 5517134bc7c..be278696a82 100644 --- a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts +++ b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts @@ -120,7 +120,7 @@ export class PluginLoader { } this.logger.info( - `PluginLoader#load: trying loading ${name}@${version}` + `PluginLoader#load: trying to load ${name}@${version}` ); if (!version) return exports; diff --git a/packages/opentelemetry-node/src/version.ts b/packages/opentelemetry-node/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index 1cd0298e622..d38dda53196 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -58,6 +58,7 @@ describe('NodeTracerProvider', () => { Object.keys(require.cache).forEach(key => delete require.cache[key]); provider.stop(); contextManager.disable(); + context.disable(); }); describe('constructor', () => { diff --git a/packages/opentelemetry-node/test/registration.test.ts b/packages/opentelemetry-node/test/registration.test.ts index e36d910d456..d3056734707 100644 --- a/packages/opentelemetry-node/test/registration.test.ts +++ b/packages/opentelemetry-node/test/registration.test.ts @@ -17,30 +17,33 @@ import { context, NoopHttpTextPropagator, - NoopTracerProvider, propagation, trace, } from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopContextManager } from '@opentelemetry/context-base'; +import { HttpTraceContext } from '@opentelemetry/core'; import * as assert from 'assert'; import { NodeTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); - propagation.setGlobalPropagator(new NoopHttpTextPropagator()); - trace.setGlobalTracerProvider(new NoopTracerProvider()); + context.disable(); + trace.disable(); + propagation.disable(); }); it('should register default implementations', () => { const tracerProvider = new NodeTracerProvider(); tracerProvider.register(); - assert.ok(context['_contextManager'] instanceof AsyncHooksContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + context['_getContextManager']() instanceof AsyncHooksContextManager + ); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should register configured implementations', () => { @@ -54,10 +57,10 @@ describe('API registration', () => { propagator, }); - assert.ok(context['_contextManager'] === contextManager); - assert.ok(propagation['_propagator'] === propagator); + assert.ok(context['_getContextManager']() === contextManager); + assert.ok(propagation['_getGlobalPropagator']() === propagator); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null context manager', () => { @@ -66,10 +69,12 @@ describe('API registration', () => { contextManager: null, }); - assert.ok(context['_contextManager'] instanceof NoopContextManager); + assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null propagator', () => { @@ -78,9 +83,13 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_propagator'] instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); - assert.ok(context['_contextManager'] instanceof AsyncHooksContextManager); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + context['_getContextManager']() instanceof AsyncHooksContextManager + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); }); diff --git a/packages/opentelemetry-plugin-grpc/package.json b/packages/opentelemetry-plugin-grpc/package.json index 248c6af83be..65e48d832ea 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry grpc automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,10 +41,10 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/context-async-hooks": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "@types/mocha": "^7.0.0", "@types/node": "^12.6.9", "@types/semver": "^6.2.0", @@ -65,8 +65,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/core": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", "shimmer": "^1.2.1" } } diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index f53cd493aea..44efeb2a938 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -297,6 +297,10 @@ export class GrpcPlugin extends BasePlugin { }); call.on('error', (err: grpcTypes.ServiceError) => { + span.setStatus({ + code: _grpcStatusCodeToCanonicalCode(err.code), + message: err.message, + }); span.addEvent('finished with error'); span.setAttributes({ [AttributeNames.GRPC_ERROR_NAME]: err.name, diff --git a/packages/opentelemetry-plugin-grpc/src/version.ts b/packages/opentelemetry-plugin-grpc/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index 56ad4f09bfa..a54410a2808 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -312,7 +312,7 @@ describe('GrpcPlugin', () => { }); afterEach(() => { - contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { @@ -436,8 +436,7 @@ describe('GrpcPlugin', () => { return provider.getTracer('default').withSpan(span, async () => { const rootSpan = provider.getTracer('default').getCurrentSpan(); if (!rootSpan) { - assert.ok(false); - return; // return so typechecking passes for rootSpan.end() + return assert.ok(false); } assert.deepStrictEqual(rootSpan, span); @@ -531,8 +530,7 @@ describe('GrpcPlugin', () => { return provider.getTracer('default').withSpan(span, async () => { const rootSpan = provider.getTracer('default').getCurrentSpan(); if (!rootSpan) { - assert.ok(false); - return; // return so typechecking passes for rootSpan.end() + return assert.ok(false); } assert.deepStrictEqual(rootSpan, span); diff --git a/packages/opentelemetry-plugin-http/README.md b/packages/opentelemetry-plugin-http/README.md index 8daf06f8446..bcdc59e230e 100644 --- a/packages/opentelemetry-plugin-http/README.md +++ b/packages/opentelemetry-plugin-http/README.md @@ -55,6 +55,8 @@ Http plugin has few options available to choose from. You can set the following: | [`ignoreIncomingPaths`](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-plugin-http/src/types.ts#L28) | `IgnoreMatcher[]` | Http plugin will not trace all incoming requests that match paths | | [`ignoreOutgoingUrls`](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-plugin-http/src/types.ts#L28) | `IgnoreMatcher[]` | Http plugin will not trace all outgoing requests that match urls | | [`serverName`](https://github.com/open-telemetry/opentelemetry-js/blob/master/packages/opentelemetry-plugin-http/src/types.ts#L28) | `string` | The primary server name of the matched virtual host. | +| `requireParentforOutgoingSpans` | Boolean | Require that is a parent span to create new span for outgoing requests. | +| `requireParentforIncomingSpans` | Boolean | Require that is a parent span to create new span for incoming requests. | ## Useful links - For more information on OpenTelemetry, visit: diff --git a/packages/opentelemetry-plugin-http/package.json b/packages/opentelemetry-plugin-http/package.json index 887c9fec98c..9e43384dd54 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry http automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,10 +41,10 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/context-async-hooks": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "@types/got": "^9.6.7", "@types/mocha": "^7.0.0", "@types/node": "^12.12.9", @@ -72,8 +72,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/core": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", "semver": "^7.1.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-http/src/http.ts b/packages/opentelemetry-plugin-http/src/http.ts index 51263cc89e0..c6c9aaa9337 100644 --- a/packages/opentelemetry-plugin-http/src/http.ts +++ b/packages/opentelemetry-plugin-http/src/http.ts @@ -22,8 +22,14 @@ import { SpanKind, SpanOptions, Status, + SpanContext, + TraceFlags, } from '@opentelemetry/api'; -import { BasePlugin } from '@opentelemetry/core'; +import { + BasePlugin, + NoRecordingSpan, + getExtractedSpanContext, +} from '@opentelemetry/core'; import { ClientRequest, IncomingMessage, @@ -57,6 +63,12 @@ export class HttpPlugin extends BasePlugin { /** keep track on spans not ended */ private readonly _spanNotEnded: WeakSet; + private readonly _emptySpanContext: SpanContext = { + traceId: '', + spanId: '', + traceFlags: TraceFlags.NONE, + }; + constructor(readonly moduleName: string, readonly version: string) { super(`@opentelemetry/plugin-${moduleName}`, VERSION); // For now component is equal to moduleName but it can change in the future. @@ -396,7 +408,6 @@ export class HttpPlugin extends BasePlugin { const spanOptions: SpanOptions = { kind: SpanKind.CLIENT, }; - const span = plugin._startHttpSpan(operationName, spanOptions); return plugin._tracer.withSpan(span, () => { @@ -417,9 +428,26 @@ export class HttpPlugin extends BasePlugin { } private _startHttpSpan(name: string, options: SpanOptions) { - const span = this._tracer - .startSpan(name, options) - .setAttribute(AttributeNames.COMPONENT, this.component); + /* + * If a parent is required but not present, we use a `NoRecordingSpan` to still + * propagate context without recording it. + */ + const requireParent = + options.kind === SpanKind.CLIENT + ? this._config.requireParentforOutgoingSpans + : this._config.requireParentforIncomingSpans; + let span: Span; + if (requireParent === true && this._tracer.getCurrentSpan() === undefined) { + const spanContext = + getExtractedSpanContext(context.active()) ?? plugin._emptySpanContext; + // TODO: Refactor this when a solution is found in + // https://github.com/open-telemetry/opentelemetry-specification/issues/530 + span = new NoRecordingSpan(spanContext); + } else { + span = this._tracer + .startSpan(name, options) + .setAttribute(AttributeNames.COMPONENT, this.component); + } this._spanNotEnded.add(span); return span; } diff --git a/packages/opentelemetry-plugin-http/src/types.ts b/packages/opentelemetry-plugin-http/src/types.ts index 335e0bbc304..b7e230d37a1 100644 --- a/packages/opentelemetry-plugin-http/src/types.ts +++ b/packages/opentelemetry-plugin-http/src/types.ts @@ -69,6 +69,10 @@ export interface HttpPluginConfig extends PluginConfig { applyCustomAttributesOnSpan?: HttpCustomAttributeFunction; /** The primary server name of the matched virtual host. */ serverName?: string; + /** Require parent to create span for outgoing requests */ + requireParentforOutgoingSpans?: boolean; + /** Require parent to create span for incoming requests */ + requireParentforIncomingSpans?: boolean; } export interface Err extends Error { diff --git a/packages/opentelemetry-plugin-http/src/version.ts b/packages/opentelemetry-plugin-http/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index 94c9c410f60..7197a7410d9 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -85,7 +85,7 @@ describe('HttpPlugin', () => { }); afterEach(() => { - contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { @@ -696,5 +696,125 @@ describe('HttpPlugin', () => { req.end(); }); }); + + describe('with require parent span', () => { + beforeEach(done => { + memoryExporter.reset(); + plugin.enable(http, provider, provider.logger, {}); + server = http.createServer((request, response) => { + response.end('Test Server Response'); + }); + server.listen(serverPort, done); + }); + + afterEach(() => { + server.close(); + plugin.disable(); + }); + + it(`should not trace without parent with options enabled (both client & server)`, async () => { + plugin.disable(); + const config: HttpPluginConfig = { + requireParentforIncomingSpans: true, + requireParentforOutgoingSpans: true, + }; + plugin.enable(http, provider, provider.logger, config); + const testPath = `/test/test`; + await httpRequest.get( + `${protocol}://${hostname}:${serverPort}${testPath}` + ); + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 0); + }); + + it(`should not trace without parent with options enabled (client only)`, async () => { + plugin.disable(); + const config: HttpPluginConfig = { + requireParentforOutgoingSpans: true, + }; + plugin.enable(http, provider, provider.logger, config); + const testPath = `/test/test`; + const result = await httpRequest.get( + `${protocol}://${hostname}:${serverPort}${testPath}` + ); + assert( + result.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY] !== undefined + ); + assert( + result.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY] !== undefined + ); + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 1); + assert.strictEqual( + spans.every(span => span.kind === SpanKind.SERVER), + true + ); + }); + + it(`should not trace without parent with options enabled (server only)`, async () => { + plugin.disable(); + const config: HttpPluginConfig = { + requireParentforIncomingSpans: true, + }; + plugin.enable(http, provider, provider.logger, config); + const testPath = `/test/test`; + const result = await httpRequest.get( + `${protocol}://${hostname}:${serverPort}${testPath}` + ); + assert( + result.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY] !== undefined + ); + assert( + result.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY] !== undefined + ); + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 1); + assert.strictEqual( + spans.every(span => span.kind === SpanKind.CLIENT), + true + ); + }); + + it(`should trace with parent with both requireParent options enabled`, done => { + plugin.disable(); + const config: HttpPluginConfig = { + requireParentforIncomingSpans: true, + requireParentforOutgoingSpans: true, + }; + plugin.enable(http, provider, provider.logger, config); + const testPath = `/test/test`; + const tracer = provider.getTracer('default'); + const span = tracer.startSpan('parentSpan', { + kind: SpanKind.INTERNAL, + }); + tracer.withSpan(span, () => { + httpRequest + .get(`${protocol}://${hostname}:${serverPort}${testPath}`) + .then(result => { + span.end(); + assert( + result.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY] !== + undefined + ); + assert( + result.reqHeaders[DummyPropagation.SPAN_CONTEXT_KEY] !== + undefined + ); + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 2); + assert.strictEqual( + spans.filter(span => span.kind === SpanKind.CLIENT).length, + 1 + ); + assert.strictEqual( + spans.filter(span => span.kind === SpanKind.INTERNAL).length, + 1 + ); + return done(); + }) + .catch(done); + }); + }); + }); }); }); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts index c6880fda542..9b69793d28e 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { SpanKind } from '@opentelemetry/api'; +import { context, SpanKind } from '@opentelemetry/api'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; import { @@ -40,6 +41,13 @@ const memoryExporter = new InMemorySpanExporter(); const protocol = 'http'; describe('Packages', () => { + beforeEach(() => { + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('get', () => { const logger = new NoopLogger(); const provider = new NodeTracerProvider({ diff --git a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts index 6314d480924..d79588e2879 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts @@ -261,7 +261,7 @@ describe('Utility', () => { ); /* tslint:disable-next-line:no-any */ utils.setSpanWithError(span, new Error(errorMessage), obj as any); - const attributes = span.toReadableSpan().attributes; + const attributes = span.attributes; assert.strictEqual( attributes[AttributeNames.HTTP_ERROR_MESSAGE], errorMessage diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index 0a529c684ec..8b083785766 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -15,7 +15,7 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { SpanKind, Span, context } from '@opentelemetry/api'; import * as assert from 'assert'; import * as http from 'http'; import { plugin } from '../../src/http'; @@ -31,6 +31,7 @@ import { } from '@opentelemetry/tracing'; import { HttpPluginConfig } from '../../src/types'; import { AttributeNames } from '../../src/enums/AttributeNames'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; const protocol = 'http'; const serverPort = 32345; const hostname = 'localhost'; @@ -41,6 +42,14 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpPlugin Integration tests', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('enable()', () => { before(function(done) { // mandatory diff --git a/packages/opentelemetry-plugin-https/package.json b/packages/opentelemetry-plugin-https/package.json index 6f2e25d140b..c79f068a7e8 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry https automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,10 +41,10 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/context-async-hooks": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/node": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/context-async-hooks": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/node": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "@types/got": "^9.6.7", "@types/mocha": "^7.0.0", "@types/node": "^12.12.9", @@ -72,9 +72,9 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/plugin-http": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/plugin-http": "^0.7.0", "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 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts index 572ea6ea1a9..d323be77ba7 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts @@ -25,7 +25,7 @@ import * as sinon from 'sinon'; import { plugin } from '../../src/https'; import { httpsRequest } from '../utils/httpsRequest'; import { NodeTracerProvider } from '@opentelemetry/node'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; describe('HttpsPlugin', () => { let server: https.Server; @@ -37,7 +37,7 @@ describe('HttpsPlugin', () => { logger, }); // const tracer = provider.getTracer('test-https') - let tracer: types.Tracer; + let tracer: api.Tracer; before(() => { nock.cleanAll(); nock.enableNetConnect(); diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts index 16ed7f67e8d..5648223fe06 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -92,6 +92,7 @@ describe('HttpsPlugin', () => { afterEach(() => { contextManager.disable(); + context.disable(); }); it('should return a plugin', () => { diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts index 106d00a32e8..0b6935fe36b 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -14,27 +14,28 @@ * limitations under the License. */ +import { context, Span, SpanKind } from '@opentelemetry/api'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { NoopLogger } from '@opentelemetry/core'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { NodeTracerProvider } from '@opentelemetry/node'; +import { Http } from '@opentelemetry/plugin-http'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; import * as assert from 'assert'; -import * as https from 'https'; +import axios, { AxiosResponse } from 'axios'; +import * as got from 'got'; import * as http from 'http'; +import * as https from 'https'; import * as nock from 'nock'; +import * as path from 'path'; +import * as request from 'request-promise-native'; +import * as superagent from 'superagent'; +import * as url from 'url'; import { plugin } from '../../src/https'; import { assertSpan } from '../utils/assertSpan'; import { DummyPropagation } from '../utils/DummyPropagation'; -import * as url from 'url'; -import axios, { AxiosResponse } from 'axios'; -import * as superagent from 'superagent'; -import * as got from 'got'; -import * as request from 'request-promise-native'; -import * as path from 'path'; -import { - InMemorySpanExporter, - SimpleSpanProcessor, -} from '@opentelemetry/tracing'; -import { Http } from '@opentelemetry/plugin-http'; -import { NodeTracerProvider } from '@opentelemetry/node'; const memoryExporter = new InMemorySpanExporter(); @@ -43,6 +44,14 @@ export const customAttributeFunction = (span: Span): void => { }; describe('Packages', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); describe('get', () => { const logger = new NoopLogger(); diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index fa8be0e518e..d66ee4ae90a 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -20,7 +20,7 @@ import { Http, AttributeNames, } from '@opentelemetry/plugin-http'; -import { SpanKind, Span } from '@opentelemetry/api'; +import { SpanKind, Span, context } from '@opentelemetry/api'; import * as assert from 'assert'; import * as http from 'http'; import * as https from 'https'; @@ -35,6 +35,7 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; +import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; const protocol = 'https'; const serverPort = 42345; @@ -46,6 +47,15 @@ export const customAttributeFunction = (span: Span): void => { }; describe('HttpsPlugin Integration tests', () => { + beforeEach(() => { + memoryExporter.reset(); + context.setGlobalContextManager(new AsyncHooksContextManager().enable()); + }); + + afterEach(() => { + context.disable(); + }); + describe('enable()', () => { before(function(done) { // mandatory diff --git a/packages/opentelemetry-plugin-xml-http-request/package.json b/packages/opentelemetry-plugin-xml-http-request/package.json index 6ffdbbd2a88..b12a130ed7f 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.6.1", + "version": "0.7.0", "description": "OpenTelemetry XMLHttpRequest automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -44,8 +44,8 @@ }, "devDependencies": { "@babel/core": "^7.6.0", - "@opentelemetry/context-zone": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/context-zone": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "@types/mocha": "^7.0.0", "@types/node": "^12.6.8", "@types/shimmer": "^1.0.1", @@ -76,10 +76,9 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/web": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/web": "^0.7.0", "shimmer": "^1.2.1" } } diff --git a/packages/opentelemetry-plugin-xml-http-request/src/types.ts b/packages/opentelemetry-plugin-xml-http-request/src/types.ts index c8b36457cf4..0fb63f676ac 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/types.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; /** * method "open" from XMLHttpRequest @@ -51,11 +51,11 @@ export interface XhrMem { status?: number; statusText?: string; // span assigned to xhr - span: types.Span; + span: api.Span; // span url - not available on types.Span spanUrl?: string; // startTime of send function - used to filter cors preflight requests - sendStartTime?: types.HrTime; + sendStartTime?: api.HrTime; // resources created between send and end plus some additional timeout createdResources?: { observer: PerformanceObserver; diff --git a/packages/opentelemetry-plugin-xml-http-request/src/version.ts b/packages/opentelemetry-plugin-xml-http-request/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index b4009d68618..88eec64ae62 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -316,6 +316,7 @@ export class XMLHttpRequestPlugin extends BasePlugin { } const currentSpan = this._tracer.startSpan(url, { + kind: api.SpanKind.CLIENT, attributes: { [AttributeNames.COMPONENT]: this.component, [AttributeNames.HTTP_METHOD]: method, diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index c35741cd38b..08b0b209eea 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { B3Propagator, LogLevel, @@ -101,23 +101,23 @@ describe('xhr', () => { beforeEach(() => { contextManager = new ZoneContextManager().enable(); - types.context.setGlobalContextManager(contextManager); + api.context.setGlobalContextManager(contextManager); }); afterEach(() => { - contextManager.disable(); + api.context.disable(); }); before(() => { - types.propagation.setGlobalPropagator(new B3Propagator()); + api.propagation.setGlobalPropagator(new B3Propagator()); }); describe('when request is successful', () => { - let webTracerWithZone: types.Tracer; + let webTracerWithZone: api.Tracer; let webTracerProviderWithZone: WebTracerProvider; let dummySpanExporter: DummySpanExporter; let exportSpy: any; - let rootSpan: types.Span; + let rootSpan: api.Span; let spyEntries: any; const url = `${window.location.origin}/xml-http-request.js`; let fakeNow = 0; @@ -210,6 +210,11 @@ describe('xhr', () => { assert.strictEqual(span.name, url, 'span has wrong name'); }); + it('span should have correct kind', () => { + const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; + assert.strictEqual(span.kind, api.SpanKind.CLIENT, 'span has wrong kind'); + }); + it('span should have correct attributes', () => { const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; const attributes = span.attributes; @@ -326,7 +331,7 @@ describe('xhr', () => { describe('AND origin match with window.location', () => { it('should set trace headers', () => { - const span: types.Span = exportSpy.args[0][0][0]; + const span: api.Span = exportSpy.args[0][0][0]; assert.strictEqual( requests[0].requestHeaders[X_B3_TRACE_ID], span.context().traceId, @@ -358,7 +363,7 @@ describe('xhr', () => { ); }); it('should set trace headers', () => { - const span: types.Span = exportSpy.args[0][0][0]; + const span: api.Span = exportSpy.args[0][0][0]; assert.strictEqual( requests[0].requestHeaders[X_B3_TRACE_ID], span.context().traceId, @@ -411,10 +416,10 @@ describe('xhr', () => { describe('when request is NOT successful', () => { let webTracerWithZoneProvider: WebTracerProvider; - let webTracerWithZone: types.Tracer; + let webTracerWithZone: api.Tracer; let dummySpanExporter: DummySpanExporter; let exportSpy: any; - let rootSpan: types.Span; + let rootSpan: api.Span; let spyEntries: any; const url = 'https://raw.githubusercontent.com/open-telemetry/opentelemetry-js/master/package.json'; diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json index 532fd101503..21b3d4cfed5 100644 --- a/packages/opentelemetry-resources/package.json +++ b/packages/opentelemetry-resources/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/resources", - "version": "0.6.1", + "version": "0.7.0", "description": "OpenTelemetry SDK resources", "main": "build/src/index.js", "browser": { @@ -61,8 +61,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", "gcp-metadata": "^3.5.0" } } diff --git a/packages/opentelemetry-resources/src/Resource.ts b/packages/opentelemetry-resources/src/Resource.ts index 0a76dad9684..bed19ee739f 100644 --- a/packages/opentelemetry-resources/src/Resource.ts +++ b/packages/opentelemetry-resources/src/Resource.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SDK_INFO } from '@opentelemetry/base'; +import { SDK_INFO } from '@opentelemetry/core'; import { TELEMETRY_SDK_RESOURCE } from './constants'; import { ResourceLabels } from './types'; diff --git a/packages/opentelemetry-resources/src/version.ts b/packages/opentelemetry-resources/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-resources/test/Resource.test.ts b/packages/opentelemetry-resources/test/Resource.test.ts index 2623094817d..4061932532f 100644 --- a/packages/opentelemetry-resources/test/Resource.test.ts +++ b/packages/opentelemetry-resources/test/Resource.test.ts @@ -15,7 +15,7 @@ */ import * as assert from 'assert'; -import { SDK_INFO } from '@opentelemetry/base'; +import { SDK_INFO } from '@opentelemetry/core'; import { Resource } from '../src'; import { assertTelemetrySDKResource } from './util/resource-assertions'; diff --git a/packages/opentelemetry-resources/test/resource-assertions.test.ts b/packages/opentelemetry-resources/test/resource-assertions.test.ts index d3b0e17957c..2ccff2e1b43 100644 --- a/packages/opentelemetry-resources/test/resource-assertions.test.ts +++ b/packages/opentelemetry-resources/test/resource-assertions.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SDK_INFO } from '@opentelemetry/base'; +import { SDK_INFO } from '@opentelemetry/core'; import { Resource } from '../src/Resource'; import { CLOUD_RESOURCE, diff --git a/packages/opentelemetry-resources/test/util/resource-assertions.ts b/packages/opentelemetry-resources/test/util/resource-assertions.ts index 02332191a16..db33bd76325 100644 --- a/packages/opentelemetry-resources/test/util/resource-assertions.ts +++ b/packages/opentelemetry-resources/test/util/resource-assertions.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SDK_INFO } from '@opentelemetry/base'; +import { SDK_INFO } from '@opentelemetry/core'; import * as assert from 'assert'; import { Resource } from '../../src/Resource'; import { diff --git a/packages/opentelemetry-shim-opentracing/package.json b/packages/opentelemetry-shim-opentracing/package.json index 05254b2562e..1f9bdb58da0 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.6.1", + "version": "0.7.0", "description": "OpenTracing to OpenTelemetry shim", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -39,7 +39,7 @@ "access": "public" }, "devDependencies": { - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/tracing": "^0.7.0", "@types/mocha": "^7.0.0", "@types/node": "^12.6.9", "codecov": "^3.6.1", @@ -54,8 +54,8 @@ "typescript": "3.7.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/core": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", "opentracing": "^0.14.4" } } diff --git a/packages/opentelemetry-shim-opentracing/src/version.ts b/packages/opentelemetry-shim-opentracing/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-test-utils/package.json b/packages/opentelemetry-test-utils/package.json index 48641ad4c41..9ba91bec737 100644 --- a/packages/opentelemetry-test-utils/package.json +++ b/packages/opentelemetry-test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@opentelemetry/test-utils", "private": true, - "version": "0.6.1", + "version": "0.7.0", "description": "Test utilities.", "main": "build/testUtils.js", "scripts": { @@ -23,9 +23,9 @@ }, "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", "devDependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1", + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0", "gts": "^1.1.2", "ts-node": "^8.6.2", "tslint-consistent-codestyle": "^1.16.0", diff --git a/packages/opentelemetry-tracing/package.json b/packages/opentelemetry-tracing/package.json index 5425c35f225..967241ecb8a 100644 --- a/packages/opentelemetry-tracing/package.json +++ b/packages/opentelemetry-tracing/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/tracing", - "version": "0.6.1", + "version": "0.7.0", "description": "OpenTelemetry Tracing", "main": "build/src/index.js", "browser": { @@ -73,10 +73,9 @@ "webpack": "^4.35.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/base": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/resources": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/resources": "^0.7.0" } } diff --git a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts index fe44199e617..375f998aa75 100644 --- a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts @@ -27,6 +27,7 @@ import { Resource } from '@opentelemetry/resources'; * This class represents a basic tracer provider which platform libraries can extend */ export class BasicTracerProvider implements api.TracerProvider { + private readonly _config: TracerConfig; private readonly _registeredSpanProcessors: SpanProcessor[] = []; private readonly _tracers: Map = new Map(); @@ -34,9 +35,13 @@ export class BasicTracerProvider implements api.TracerProvider { readonly logger: api.Logger; readonly resource: Resource; - constructor(private _config: TracerConfig = DEFAULT_CONFIG) { - this.logger = _config.logger || new ConsoleLogger(_config.logLevel); - this.resource = _config.resource || Resource.createTelemetrySDKResource(); + constructor(config: TracerConfig = DEFAULT_CONFIG) { + this.logger = config.logger ?? new ConsoleLogger(config.logLevel); + this.resource = config.resource ?? Resource.createTelemetrySDKResource(); + this._config = Object.assign({}, config, { + logger: this.logger, + resource: this.resource, + }); } getTracer(name: string, version = '*', config?: TracerConfig): Tracer { diff --git a/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts b/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts index b4d4c9d3fa3..92a04dd530f 100644 --- a/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Span } from '@opentelemetry/api'; import { SpanProcessor } from './SpanProcessor'; +import { ReadableSpan } from './export/ReadableSpan'; /** * Implementation of the {@link SpanProcessor} that simply forwards all @@ -25,16 +25,18 @@ export class MultiSpanProcessor implements SpanProcessor { constructor(private readonly _spanProcessors: SpanProcessor[]) {} forceFlush(): void { - // do nothing as all spans are being exported without waiting + for (const spanProcessor of this._spanProcessors) { + spanProcessor.forceFlush(); + } } - onStart(span: Span): void { + onStart(span: ReadableSpan): void { for (const spanProcessor of this._spanProcessors) { spanProcessor.onStart(span); } } - onEnd(span: Span): void { + onEnd(span: ReadableSpan): void { for (const spanProcessor of this._spanProcessors) { spanProcessor.onEnd(span); } diff --git a/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts b/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts index 2898e77cfa9..c00bcb393a4 100644 --- a/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import { Span } from '@opentelemetry/api'; import { SpanProcessor } from './SpanProcessor'; +import { ReadableSpan } from './export/ReadableSpan'; /** No-op implementation of SpanProcessor */ export class NoopSpanProcessor implements SpanProcessor { - onStart(span: Span): void {} - onEnd(span: Span): void {} + onStart(span: ReadableSpan): void {} + onEnd(span: ReadableSpan): void {} shutdown(): void {} forceFlush(): void {} } diff --git a/packages/opentelemetry-tracing/src/Span.ts b/packages/opentelemetry-tracing/src/Span.ts index 4028564a4d0..7a6c97bda74 100644 --- a/packages/opentelemetry-tracing/src/Span.ts +++ b/packages/opentelemetry-tracing/src/Span.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { hrTime, hrTimeDuration, @@ -30,25 +30,25 @@ import { TraceParams } from './types'; /** * This class represents a span. */ -export class Span implements types.Span, ReadableSpan { +export class Span implements api.Span, ReadableSpan { // Below properties are included to implement ReadableSpan for export // purposes but are not intended to be written-to directly. - readonly spanContext: types.SpanContext; - readonly kind: types.SpanKind; + readonly spanContext: api.SpanContext; + readonly kind: api.SpanKind; readonly parentSpanId?: string; - readonly attributes: types.Attributes = {}; - readonly links: types.Link[] = []; - readonly events: types.TimedEvent[] = []; - readonly startTime: types.HrTime; + readonly attributes: api.Attributes = {}; + readonly links: api.Link[] = []; + readonly events: api.TimedEvent[] = []; + readonly startTime: api.HrTime; readonly resource: Resource; name: string; - status: types.Status = { - code: types.CanonicalCode.OK, + status: api.Status = { + code: api.CanonicalCode.OK, }; - endTime: types.HrTime = [0, 0]; + endTime: api.HrTime = [0, 0]; private _ended = false; - private _duration: types.HrTime = [-1, -1]; - private readonly _logger: types.Logger; + private _duration: api.HrTime = [-1, -1]; + private readonly _logger: api.Logger; private readonly _spanProcessor: SpanProcessor; private readonly _traceParams: TraceParams; @@ -56,11 +56,11 @@ export class Span implements types.Span, ReadableSpan { constructor( parentTracer: Tracer, spanName: string, - spanContext: types.SpanContext, - kind: types.SpanKind, + spanContext: api.SpanContext, + kind: api.SpanKind, parentSpanId?: string, - links: types.Link[] = [], - startTime: types.TimeInput = hrTime() + links: api.Link[] = [], + startTime: api.TimeInput = hrTime() ) { this.name = spanName; this.spanContext = spanContext; @@ -75,7 +75,7 @@ export class Span implements types.Span, ReadableSpan { this._spanProcessor.onStart(this); } - context(): types.SpanContext { + context(): api.SpanContext { return this.spanContext; } @@ -98,7 +98,7 @@ export class Span implements types.Span, ReadableSpan { return this; } - setAttributes(attributes: types.Attributes): this { + setAttributes(attributes: api.Attributes): this { Object.keys(attributes).forEach(key => { this.setAttribute(key, attributes[key]); }); @@ -114,8 +114,8 @@ export class Span implements types.Span, ReadableSpan { */ addEvent( name: string, - attributesOrStartTime?: types.Attributes | types.TimeInput, - startTime?: types.TimeInput + attributesOrStartTime?: api.Attributes | api.TimeInput, + startTime?: api.TimeInput ): this { if (this._isSpanEnded()) return this; if (this.events.length >= this._traceParams.numberOfEventsPerSpan!) { @@ -124,7 +124,7 @@ export class Span implements types.Span, ReadableSpan { } if (isTimeInput(attributesOrStartTime)) { if (typeof startTime === 'undefined') { - startTime = attributesOrStartTime as types.TimeInput; + startTime = attributesOrStartTime as api.TimeInput; } attributesOrStartTime = undefined; } @@ -133,13 +133,13 @@ export class Span implements types.Span, ReadableSpan { } this.events.push({ name, - attributes: attributesOrStartTime as types.Attributes, + attributes: attributesOrStartTime as api.Attributes, time: timeInputToHrTime(startTime), }); return this; } - setStatus(status: types.Status): this { + setStatus(status: api.Status): this { if (this._isSpanEnded()) return this; this.status = status; return this; @@ -151,7 +151,7 @@ export class Span implements types.Span, ReadableSpan { return this; } - end(endTime: types.TimeInput = hrTime()): void { + end(endTime: api.TimeInput = hrTime()): void { if (this._isSpanEnded()) { this._logger.error('You can only call end() on a span once.'); return; @@ -175,11 +175,7 @@ export class Span implements types.Span, ReadableSpan { return true; } - toReadableSpan(): ReadableSpan { - return this; - } - - get duration(): types.HrTime { + get duration(): api.HrTime { return this._duration; } diff --git a/packages/opentelemetry-tracing/src/SpanProcessor.ts b/packages/opentelemetry-tracing/src/SpanProcessor.ts index 0320455ae98..7f8deae0a9c 100644 --- a/packages/opentelemetry-tracing/src/SpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/SpanProcessor.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Span } from '@opentelemetry/api'; +import { ReadableSpan } from './export/ReadableSpan'; /** * SpanProcessor is the interface Tracer SDK uses to allow synchronous hooks @@ -27,18 +27,18 @@ export interface SpanProcessor { forceFlush(): void; /** - * Called when a {@link Span} is started, if the `span.isRecording()` + * Called when a {@link ReadableSpan} is started, if the `span.isRecording()` * returns true. * @param span the Span that just started. */ - onStart(span: Span): void; + onStart(span: ReadableSpan): void; /** - * Called when a {@link Span} is ended, if the `span.isRecording()` + * Called when a {@link ReadableSpan} is ended, if the `span.isRecording()` * returns true. * @param span the Span that just ended. */ - onEnd(span: Span): void; + onEnd(span: ReadableSpan): void; /** * Shuts down the processor. Called when SDK is shut down. This is an diff --git a/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts b/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts index 87fd79bded7..381ec393f43 100644 --- a/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts @@ -15,7 +15,6 @@ */ import { unrefTimer } from '@opentelemetry/core'; -import { Span } from '../Span'; import { SpanProcessor } from '../SpanProcessor'; import { BufferConfig } from '../types'; import { ReadableSpan } from './ReadableSpan'; @@ -53,13 +52,13 @@ export class BatchSpanProcessor implements SpanProcessor { } // does nothing. - onStart(span: Span): void {} + onStart(span: ReadableSpan): void {} - onEnd(span: Span): void { + onEnd(span: ReadableSpan): void { if (this._isShutdown) { return; } - this._addToBuffer(span.toReadableSpan()); + this._addToBuffer(span); } shutdown(): void { diff --git a/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts b/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts index 7f5fc968047..42c5875bd6c 100644 --- a/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts @@ -16,8 +16,7 @@ import { SpanExporter } from './SpanExporter'; import { ReadableSpan } from './ReadableSpan'; -import { ExportResult } from '@opentelemetry/base'; -import { hrTimeToMicroseconds } from '@opentelemetry/core'; +import { ExportResult, hrTimeToMicroseconds } from '@opentelemetry/core'; /** * This is implementation of {@link SpanExporter} that prints spans to the diff --git a/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts b/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts index 5415075ddb2..b3de120411f 100644 --- a/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts @@ -16,7 +16,7 @@ import { SpanExporter } from './SpanExporter'; import { ReadableSpan } from './ReadableSpan'; -import { ExportResult } from '@opentelemetry/base'; +import { ExportResult } from '@opentelemetry/core'; /** * This class can be used for testing purposes. It stores the exported spans diff --git a/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts b/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts index e76797cfcfd..073ffb3f206 100644 --- a/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { Span } from '../Span'; import { SpanProcessor } from '../SpanProcessor'; import { SpanExporter } from './SpanExporter'; +import { ReadableSpan } from './ReadableSpan'; /** * An implementation of the {@link SpanProcessor} that converts the {@link Span} @@ -33,13 +33,13 @@ export class SimpleSpanProcessor implements SpanProcessor { } // does nothing. - onStart(span: Span): void {} + onStart(span: ReadableSpan): void {} - onEnd(span: Span): void { + onEnd(span: ReadableSpan): void { if (this._isShutdown) { return; } - this._exporter.export([span.toReadableSpan()], () => {}); + this._exporter.export([span], () => {}); } shutdown(): void { diff --git a/packages/opentelemetry-tracing/src/export/SpanExporter.ts b/packages/opentelemetry-tracing/src/export/SpanExporter.ts index 88e191c1ffd..72f7ff25726 100644 --- a/packages/opentelemetry-tracing/src/export/SpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/SpanExporter.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ExportResult } from '@opentelemetry/base'; +import { ExportResult } from '@opentelemetry/core'; import { ReadableSpan } from './ReadableSpan'; /** diff --git a/packages/opentelemetry-tracing/src/types.ts b/packages/opentelemetry-tracing/src/types.ts index 008ac1523ca..7f5dedb0317 100644 --- a/packages/opentelemetry-tracing/src/types.ts +++ b/packages/opentelemetry-tracing/src/types.ts @@ -29,7 +29,7 @@ import { Resource } from '@opentelemetry/resources'; */ export interface TracerConfig { /** - * Attributed that will be applied on every span created by Tracer. + * Attributes that will be applied on every span created by Tracer. * Useful to add infrastructure and environment information to your spans. */ defaultAttributes?: Attributes; diff --git a/packages/opentelemetry-tracing/src/version.ts b/packages/opentelemetry-tracing/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index 832128e9c4c..6de7339798d 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -15,6 +15,7 @@ */ import { Context, context, SpanContext, TraceFlags } from '@opentelemetry/api'; +import { ContextManager } from '@opentelemetry/context-base'; import { ALWAYS_SAMPLER, NEVER_SAMPLER, @@ -25,16 +26,12 @@ import { TraceState, } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { - NoopContextManager, - ContextManager, -} from '@opentelemetry/context-base'; import * as assert from 'assert'; import { BasicTracerProvider, Span } from '../src'; describe('BasicTracerProvider', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); + context.disable(); }); describe('constructor', () => { @@ -124,6 +121,14 @@ describe('BasicTracerProvider', () => { assert.ok(span instanceof Span); }); + it('should propagate resources', () => { + const tracerProvider = new BasicTracerProvider(); + const tracer = tracerProvider.getTracer('default'); + const span = tracer.startSpan('my-span') as Span; + assert.strictEqual(tracer.resource, tracerProvider.resource); + assert.strictEqual(span.resource, tracerProvider.resource); + }); + it('should start a span with name and options', () => { const tracer = new BasicTracerProvider().getTracer('default'); const span = tracer.startSpan('my-span', {}); @@ -338,6 +343,7 @@ describe('BasicTracerProvider', () => { context.setGlobalContextManager({ active: () => setActiveSpan(Context.ROOT_CONTEXT, ('foo' as any) as Span), + disable: () => {}, } as ContextManager); const tracer = new BasicTracerProvider().getTracer('default'); diff --git a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts index 62b33fe224a..b83da007a65 100644 --- a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts @@ -31,33 +31,44 @@ class TestProcessor implements SpanProcessor { } describe('MultiSpanProcessor', () => { - const tracer = new BasicTracerProvider().getTracer('default'); - const span = tracer.startSpan('one'); - it('should handle empty span processor', () => { const multiSpanProcessor = new MultiSpanProcessor([]); - multiSpanProcessor.onStart(span); - multiSpanProcessor.onEnd(span); + + const tracerProvider = new BasicTracerProvider(); + tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracer = tracerProvider.getTracer('default'); + const span = tracer.startSpan('one'); + span.end(); multiSpanProcessor.shutdown(); }); it('should handle one span processor', () => { const processor1 = new TestProcessor(); const multiSpanProcessor = new MultiSpanProcessor([processor1]); - multiSpanProcessor.onStart(span); + + const tracerProvider = new BasicTracerProvider(); + tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracer = tracerProvider.getTracer('default'); + const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); - multiSpanProcessor.onEnd(span); + span.end(); assert.strictEqual(processor1.spans.length, 1); + multiSpanProcessor.shutdown(); }); it('should handle two span processor', () => { const processor1 = new TestProcessor(); const processor2 = new TestProcessor(); const multiSpanProcessor = new MultiSpanProcessor([processor1, processor2]); - multiSpanProcessor.onStart(span); + + const tracerProvider = new BasicTracerProvider(); + tracerProvider.addSpanProcessor(multiSpanProcessor); + const tracer = tracerProvider.getTracer('default'); + const span = tracer.startSpan('one'); assert.strictEqual(processor1.spans.length, 0); assert.strictEqual(processor1.spans.length, processor2.spans.length); - multiSpanProcessor.onEnd(span); + + span.end(); assert.strictEqual(processor1.spans.length, 1); assert.strictEqual(processor1.spans.length, processor2.spans.length); @@ -65,4 +76,19 @@ describe('MultiSpanProcessor', () => { assert.strictEqual(processor1.spans.length, 0); assert.strictEqual(processor1.spans.length, processor2.spans.length); }); + + it('should force span processors to flush', () => { + let flushed = false; + const processor: SpanProcessor = { + forceFlush: () => { + flushed = true; + }, + onStart: span => {}, + onEnd: span => {}, + shutdown: () => {}, + }; + const multiSpanProcessor = new MultiSpanProcessor([processor]); + multiSpanProcessor.forceFlush(); + assert.ok(flushed); + }); }); diff --git a/packages/opentelemetry-tracing/test/Span.test.ts b/packages/opentelemetry-tracing/test/Span.test.ts index 0eeeda7ab96..db737573719 100644 --- a/packages/opentelemetry-tracing/test/Span.test.ts +++ b/packages/opentelemetry-tracing/test/Span.test.ts @@ -220,28 +220,25 @@ describe('Span', () => { parentId ); - const readableSpan = span.toReadableSpan(); - assert.strictEqual(readableSpan.name, 'my-span'); - assert.strictEqual(readableSpan.kind, SpanKind.INTERNAL); - assert.strictEqual(readableSpan.parentSpanId, parentId); - assert.strictEqual(readableSpan.spanContext.traceId, spanContext.traceId); - assert.deepStrictEqual(readableSpan.status, { + assert.strictEqual(span.name, 'my-span'); + assert.strictEqual(span.kind, SpanKind.INTERNAL); + assert.strictEqual(span.parentSpanId, parentId); + assert.strictEqual(span.spanContext.traceId, spanContext.traceId); + assert.deepStrictEqual(span.status, { code: CanonicalCode.OK, }); - assert.deepStrictEqual(readableSpan.attributes, {}); - assert.deepStrictEqual(readableSpan.links, []); - assert.deepStrictEqual(readableSpan.events, []); + assert.deepStrictEqual(span.attributes, {}); + assert.deepStrictEqual(span.links, []); + assert.deepStrictEqual(span.events, []); }); it('should return ReadableSpan with attributes', () => { const span = new Span(tracer, 'my-span', spanContext, SpanKind.CLIENT); span.setAttribute('attr1', 'value1'); - let readableSpan = span.toReadableSpan(); - assert.deepStrictEqual(readableSpan.attributes, { attr1: 'value1' }); + assert.deepStrictEqual(span.attributes, { attr1: 'value1' }); span.setAttributes({ attr2: 123, attr1: false }); - readableSpan = span.toReadableSpan(); - assert.deepStrictEqual(readableSpan.attributes, { + assert.deepStrictEqual(span.attributes, { attr1: false, attr2: 123, }); @@ -249,8 +246,7 @@ describe('Span', () => { span.end(); // shouldn't add new attribute span.setAttribute('attr3', 'value3'); - readableSpan = span.toReadableSpan(); - assert.deepStrictEqual(readableSpan.attributes, { + assert.deepStrictEqual(span.attributes, { attr1: false, attr2: 123, }); @@ -271,9 +267,8 @@ describe('Span', () => { }, ] ); - const readableSpan = span.toReadableSpan(); - assert.strictEqual(readableSpan.links.length, 2); - assert.deepStrictEqual(readableSpan.links, [ + assert.strictEqual(span.links.length, 2); + assert.deepStrictEqual(span.links, [ { context: linkContext, }, @@ -289,17 +284,15 @@ describe('Span', () => { it('should return ReadableSpan with events', () => { const span = new Span(tracer, 'my-span', spanContext, SpanKind.CLIENT); span.addEvent('sent'); - let readableSpan = span.toReadableSpan(); - assert.strictEqual(readableSpan.events.length, 1); - const [event] = readableSpan.events; + assert.strictEqual(span.events.length, 1); + const [event] = span.events; assert.deepStrictEqual(event.name, 'sent'); assert.ok(!event.attributes); assert.ok(event.time[0] > 0); span.addEvent('rev', { attr1: 'value', attr2: 123, attr3: true }); - readableSpan = span.toReadableSpan(); - assert.strictEqual(readableSpan.events.length, 2); - const [event1, event2] = readableSpan.events; + assert.strictEqual(span.events.length, 2); + const [event1, event2] = span.events; assert.deepStrictEqual(event1.name, 'sent'); assert.ok(!event1.attributes); assert.ok(event1.time[0] > 0); @@ -314,9 +307,7 @@ describe('Span', () => { span.end(); // shouldn't add new event span.addEvent('sent'); - assert.strictEqual(readableSpan.events.length, 2); - readableSpan = span.toReadableSpan(); - assert.strictEqual(readableSpan.events.length, 2); + assert.strictEqual(span.events.length, 2); }); it('should return ReadableSpan with new status', () => { @@ -325,12 +316,8 @@ describe('Span', () => { code: CanonicalCode.PERMISSION_DENIED, message: 'This is an error', }); - const readableSpan = span.toReadableSpan(); - assert.strictEqual( - readableSpan.status.code, - CanonicalCode.PERMISSION_DENIED - ); - assert.strictEqual(readableSpan.status.message, 'This is an error'); + assert.strictEqual(span.status.code, CanonicalCode.PERMISSION_DENIED); + assert.strictEqual(span.status.message, 'This is an error'); span.end(); // shouldn't update status diff --git a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts index cfd215ff884..f83f96ce02f 100644 --- a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts +++ b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts @@ -20,9 +20,8 @@ import { SimpleSpanProcessor, BasicTracerProvider, } from '../../src'; -import { ExportResult } from '@opentelemetry/base'; import { context } from '@opentelemetry/api'; -import { setActiveSpan } from '@opentelemetry/core'; +import { ExportResult, setActiveSpan } from '@opentelemetry/core'; describe('InMemorySpanExporter', () => { const memoryExporter = new InMemorySpanExporter(); diff --git a/packages/opentelemetry-web/package.json b/packages/opentelemetry-web/package.json index 6b296fcc93a..b8ce2dff7d4 100644 --- a/packages/opentelemetry-web/package.json +++ b/packages/opentelemetry-web/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/web", - "version": "0.6.1", + "version": "0.7.0", "description": "OpenTelemetry Web Tracer", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -43,8 +43,8 @@ }, "devDependencies": { "@babel/core": "^7.6.0", - "@opentelemetry/context-zone": "^0.6.1", - "@opentelemetry/resources": "^0.6.1", + "@opentelemetry/context-zone": "^0.7.0", + "@opentelemetry/resources": "^0.7.0", "@types/jquery": "^3.3.31", "@types/mocha": "^7.0.0", "@types/node": "^12.6.8", @@ -76,9 +76,9 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "@opentelemetry/api": "^0.6.1", - "@opentelemetry/context-base": "^0.6.1", - "@opentelemetry/core": "^0.6.1", - "@opentelemetry/tracing": "^0.6.1" + "@opentelemetry/api": "^0.7.0", + "@opentelemetry/context-base": "^0.7.0", + "@opentelemetry/core": "^0.7.0", + "@opentelemetry/tracing": "^0.7.0" } } diff --git a/packages/opentelemetry-web/src/utils.ts b/packages/opentelemetry-web/src/utils.ts index 0beec8d9f0b..e5a3cd43fed 100644 --- a/packages/opentelemetry-web/src/utils.ts +++ b/packages/opentelemetry-web/src/utils.ts @@ -16,7 +16,7 @@ import { PerformanceEntries, PerformanceResourceTimingInfo } from './types'; import { PerformanceTimingNames as PTN } from './enums/PerformanceTimingNames'; -import * as types from '@opentelemetry/api'; +import * as api from '@opentelemetry/api'; import { hrTimeToNanoseconds, timeInputToHrTime } from '@opentelemetry/core'; /** @@ -35,10 +35,10 @@ export function hasKey(obj: O, key: keyof any): key is keyof O { * @param entries */ export function addSpanNetworkEvent( - span: types.Span, + span: api.Span, performanceName: string, entries: PerformanceEntries -): types.Span | undefined { +): api.Span | undefined { if ( hasKey(entries, performanceName) && typeof entries[performanceName] === 'number' @@ -82,8 +82,8 @@ export function sortResources(filteredResources: PerformanceResourceTiming[]) { */ export function getResource( spanUrl: string, - startTimeHR: types.HrTime, - endTimeHR: types.HrTime, + startTimeHR: api.HrTime, + endTimeHR: api.HrTime, resources: PerformanceResourceTiming[], ignoredResources: WeakSet = new WeakSet< PerformanceResourceTiming @@ -147,7 +147,7 @@ export function getResource( function findMainRequest( resources: PerformanceResourceTiming[], corsPreFlightRequestEndTime: number, - spanEndTimeHR: types.HrTime + spanEndTimeHR: api.HrTime ): PerformanceResourceTiming { const spanEndTime = hrTimeToNanoseconds(spanEndTimeHR); const minTime = hrTimeToNanoseconds( @@ -189,8 +189,8 @@ function findMainRequest( */ function filterResourcesForSpan( spanUrl: string, - startTimeHR: types.HrTime, - endTimeHR: types.HrTime, + startTimeHR: api.HrTime, + endTimeHR: api.HrTime, resources: PerformanceResourceTiming[], ignoredResources: WeakSet ) { diff --git a/packages/opentelemetry-web/src/version.ts b/packages/opentelemetry-web/src/version.ts index 74e9e923376..103553581ce 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.6.1'; +export const VERSION = '0.7.0'; diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index e22d4cef861..60007a44796 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -15,11 +15,11 @@ */ import { context } from '@opentelemetry/api'; -import { B3Propagator, BasePlugin, NoopLogger } from '@opentelemetry/core'; import { ContextManager } from '@opentelemetry/context-base'; import { ZoneContextManager } from '@opentelemetry/context-zone'; -import { Tracer, Span } from '@opentelemetry/tracing'; +import { B3Propagator, BasePlugin, NoopLogger } from '@opentelemetry/core'; import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources'; +import { Span, Tracer } from '@opentelemetry/tracing'; import * as assert from 'assert'; import * as sinon from 'sinon'; import { WebTracerConfig } from '../src'; @@ -48,6 +48,7 @@ describe('WebTracerProvider', () => { afterEach(() => { contextManager.disable(); + context.disable(); }); it('should construct an instance with required only options', () => { diff --git a/packages/opentelemetry-web/test/registration.test.ts b/packages/opentelemetry-web/test/registration.test.ts index 497bc868d0c..adcee3a94ec 100644 --- a/packages/opentelemetry-web/test/registration.test.ts +++ b/packages/opentelemetry-web/test/registration.test.ts @@ -17,29 +17,30 @@ import { context, NoopHttpTextPropagator, - NoopTracerProvider, propagation, trace, } from '@opentelemetry/api'; -import { HttpTraceContext } from '@opentelemetry/core'; import { NoopContextManager } from '@opentelemetry/context-base'; +import { HttpTraceContext } from '@opentelemetry/core'; import * as assert from 'assert'; -import { WebTracerProvider, StackContextManager } from '../src'; +import { StackContextManager, WebTracerProvider } from '../src'; describe('API registration', () => { beforeEach(() => { - context.setGlobalContextManager(new NoopContextManager()); - propagation.setGlobalPropagator(new NoopHttpTextPropagator()); - trace.setGlobalTracerProvider(new NoopTracerProvider()); + context.disable(); + trace.disable(); + propagation.disable(); }); it('should register default implementations', () => { const tracerProvider = new WebTracerProvider(); tracerProvider.register(); - assert.ok(context['_contextManager'] instanceof StackContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(context['_getContextManager']() instanceof StackContextManager); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should register configured implementations', () => { @@ -53,10 +54,10 @@ describe('API registration', () => { propagator, }); - assert.ok(context['_contextManager'] === contextManager); - assert.ok(propagation['_propagator'] === propagator); + assert.ok(context['_getContextManager']() === contextManager); + assert.ok(propagation['_getGlobalPropagator']() === propagator); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null context manager', () => { @@ -65,10 +66,12 @@ describe('API registration', () => { contextManager: null, }); - assert.ok(context['_contextManager'] instanceof NoopContextManager); + assert.ok(context['_getContextManager']() instanceof NoopContextManager); - assert.ok(propagation['_propagator'] instanceof HttpTraceContext); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok( + propagation['_getGlobalPropagator']() instanceof HttpTraceContext + ); + assert.ok(trace.getTracerProvider() === tracerProvider); }); it('should skip null propagator', () => { @@ -77,9 +80,11 @@ describe('API registration', () => { propagator: null, }); - assert.ok(propagation['_propagator'] instanceof NoopHttpTextPropagator); + assert.ok( + propagation['_getGlobalPropagator']() instanceof NoopHttpTextPropagator + ); - assert.ok(context['_contextManager'] instanceof StackContextManager); - assert.ok(trace['_tracerProvider'] === tracerProvider); + assert.ok(context['_getContextManager']() instanceof StackContextManager); + assert.ok(trace.getTracerProvider() === tracerProvider); }); }); diff --git a/packages/tsconfig.base.json b/packages/tsconfig.base.json index 116c12d66d2..3d1763d3a2f 100644 --- a/packages/tsconfig.base.json +++ b/packages/tsconfig.base.json @@ -3,6 +3,7 @@ "allowUnreachableCode": false, "allowUnusedLabels": false, "declaration": true, + "declarationMap": true, "forceConsistentCasingInFileNames": true, "module": "commonjs", "noEmitOnError": true,