diff --git a/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/src/detectors/ContainerDetector.ts b/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/src/detectors/ContainerDetector.ts index e318c8bd4..fcbbcc6e1 100644 --- a/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/src/detectors/ContainerDetector.ts +++ b/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/src/detectors/ContainerDetector.ts @@ -57,9 +57,29 @@ export class ContainerDetector implements Detector { this.UTF8_UNICODE ); const splitData = rawData.trim().split('\n'); - for (const str of splitData) { - if (str.length >= this.CONTAINER_ID_LENGTH) { - return str.substring(str.length - this.CONTAINER_ID_LENGTH); + for (const line of splitData) { + const lastSlashIdx = line.lastIndexOf('/'); + if (lastSlashIdx === -1) { + continue; + } + const lastSection = line.substring(lastSlashIdx + 1); + const colonIdx = lastSection.lastIndexOf(':'); + if (colonIdx !== -1) { + // since containerd v1.5.0+, containerId is divided by the last colon when the cgroupDriver is systemd: + // https://github.com/containerd/containerd/blob/release/1.5/pkg/cri/server/helpers_linux.go#L64 + return lastSection.substring(colonIdx + 1); + } else { + let startIdx = lastSection.lastIndexOf('-'); + let endIdx = lastSection.lastIndexOf('.'); + + startIdx = startIdx === -1 ? 0 : startIdx + 1; + if (endIdx === -1) { + endIdx = lastSection.length; + } + if (startIdx > endIdx) { + continue; + } + return lastSection.substring(startIdx, endIdx); } } return undefined; diff --git a/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/test/ContainerDetector.test.ts b/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/test/ContainerDetector.test.ts index e9c5c3aaf..8ee03d1f3 100644 --- a/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/test/ContainerDetector.test.ts +++ b/auto-merge/contrib/detectors/node/opentelemetry-resource-detector-container/test/ContainerDetector.test.ts @@ -28,7 +28,7 @@ import { ContainerDetector } from '../src'; describe('ContainerDetector', () => { let readStub; const correctCgroupV1Data = - 'bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm'; + '12:pids:/kubepods.slice/bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm'; const correctCgroupV2Data = `tmhdefghijklmnopqrstuvwxyzafgrefghiugkmnopqrstuvwxyzabcdefghijkl/hostname fhkjdshgfhsdfjhdsfkjhfkdshkjhfd/host sahfhfjkhjhfhjdhfjkdhfkjdhfjkhhdsjfhdfhjdhfkj/somethingelse`; diff --git a/auto-merge/js/CHANGELOG.md b/auto-merge/js/CHANGELOG.md index 4c48f21a6..53987c416 100644 --- a/auto-merge/js/CHANGELOG.md +++ b/auto-merge/js/CHANGELOG.md @@ -17,6 +17,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/ ### :house: (Internal) +* test: added a performance benchmark test for span creation [#4105](https://github.com/open-telemetry/opentelemetry-js/pull/4105) + ## 1.17.0 ### :bug: (Bug Fix) diff --git a/auto-merge/js/experimental/examples/opencensus-shim/README.md b/auto-merge/js/experimental/examples/opencensus-shim/README.md index 0738d67d8..6d95a9135 100644 --- a/auto-merge/js/experimental/examples/opencensus-shim/README.md +++ b/auto-merge/js/experimental/examples/opencensus-shim/README.md @@ -9,6 +9,8 @@ The example has: - Root Spans (on client), instrumented with OpenCensus's HTTP instrumentation - Child Span from a remote parent (on server), instrumented with OpenCensus's HTTP instrumentation - Another Child Span created in the server representing some work being done, instrumented manually with OpenTelemetry. +- Server metrics coming from OpenCensus's HTTP instrumentation, available through the +OpenTelemetry's Prometheus exporter. ## Installation @@ -64,6 +66,14 @@ Go to Jaeger with your browser and click on the "Servi

+## Check the Prometheus metrics + +Load the Prometheus metrics endpoint of the server at in your +browser. You should see the `opencensus_io_http_server_*` related metrics in +the output. + +

+ ## Useful links - For more information on OpenTelemetry, visit: diff --git a/auto-merge/js/experimental/examples/opencensus-shim/images/prom-metrics.png b/auto-merge/js/experimental/examples/opencensus-shim/images/prom-metrics.png new file mode 100644 index 000000000..953e12253 Binary files /dev/null and b/auto-merge/js/experimental/examples/opencensus-shim/images/prom-metrics.png differ diff --git a/auto-merge/js/experimental/examples/opencensus-shim/package.json b/auto-merge/js/experimental/examples/opencensus-shim/package.json index d8615a6b7..bd97c726c 100644 --- a/auto-merge/js/experimental/examples/opencensus-shim/package.json +++ b/auto-merge/js/experimental/examples/opencensus-shim/package.json @@ -28,10 +28,13 @@ }, "dependencies": { "@opencensus/core": "0.1.0", + "@opencensus/instrumentation-http": "0.1.0", "@opencensus/nodejs-base": "0.1.0", "@opentelemetry/api": "1.6.0", + "@opentelemetry/exporter-prometheus": "0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.43.0", "@opentelemetry/resources": "1.17.0", + "@opentelemetry/sdk-metrics": "1.17.0", "@opentelemetry/sdk-trace-node": "1.17.0", "@opentelemetry/semantic-conventions": "1.17.0", "@opentelemetry/shim-opencensus": "0.43.0" diff --git a/auto-merge/js/experimental/examples/opencensus-shim/server.js b/auto-merge/js/experimental/examples/opencensus-shim/server.js index 98ddcf5b6..00893bafe 100644 --- a/auto-merge/js/experimental/examples/opencensus-shim/server.js +++ b/auto-merge/js/experimental/examples/opencensus-shim/server.js @@ -5,6 +5,8 @@ const setup = require('./setup'); const utils = require('./utils'); const { trace } = require('@opentelemetry/api'); +const oc = require('@opencensus/core'); + setup('opencensus-shim-example-server'); const http = require('http'); diff --git a/auto-merge/js/experimental/examples/opencensus-shim/setup.js b/auto-merge/js/experimental/examples/opencensus-shim/setup.js index 37206971e..99bf8bf8b 100644 --- a/auto-merge/js/experimental/examples/opencensus-shim/setup.js +++ b/auto-merge/js/experimental/examples/opencensus-shim/setup.js @@ -15,37 +15,64 @@ */ 'use strict'; -const { DiagConsoleLogger, diag, DiagLogLevel } = require('@opentelemetry/api'); +const { diag, metrics } = require('@opentelemetry/api'); const { NodeTracerProvider, BatchSpanProcessor, } = require('@opentelemetry/sdk-trace-node'); +const { MeterProvider } = require('@opentelemetry/sdk-metrics'); const { OTLPTraceExporter, } = require('@opentelemetry/exporter-trace-otlp-grpc'); +const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); const { Resource } = require('@opentelemetry/resources'); const { SemanticResourceAttributes, } = require('@opentelemetry/semantic-conventions'); +const { OpenCensusMetricProducer } = require('@opentelemetry/shim-opencensus'); +const instrumentationHttp = require('@opencensus/instrumentation-http'); +const { TracingBase } = require('@opencensus/nodejs-base'); +const oc = require('@opencensus/core'); module.exports = function setup(serviceName) { - const tracing = require('@opencensus/nodejs-base'); + /** + * You can alternatively just use the @opentelemetry/nodejs package directly: + * + * ```js + * const tracing = require('@opencensus/nodejs'); + * ``` + */ + const tracing = new TracingBase(['http']); + tracing.tracer = new oc.CoreTracer(); - diag.setLogger(new DiagConsoleLogger(), { logLevel: DiagLogLevel.ALL }); - const provider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: serviceName, - }), + const resource = new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: serviceName, }); - provider.addSpanProcessor( + const tracerProvider = new NodeTracerProvider({ resource }); + tracerProvider.addSpanProcessor( new BatchSpanProcessor(new OTLPTraceExporter(), { scheduledDelayMillis: 5000, }) ); - provider.register(); + tracerProvider.register(); + + const meterProvider = new MeterProvider({ resource }); + meterProvider.addMetricReader( + new PrometheusExporter({ + metricProducers: [ + new OpenCensusMetricProducer({ + openCensusMetricProducerManager: + oc.Metrics.getMetricProducerManager(), + }), + ], + }) + ); + metrics.setGlobalMeterProvider(meterProvider); // Start OpenCensus tracing - tracing.start({ samplingRate: 1, logger: diag }); + tracing.start({ samplingRate: 1, logger: diag, stats: oc.globalStats }); + // Register OpenCensus HTTP stats views + instrumentationHttp.registerAllViews(oc.globalStats); - return provider; + return tracerProvider; }; diff --git a/auto-merge/js/experimental/packages/shim-opencensus/README.md b/auto-merge/js/experimental/packages/shim-opencensus/README.md index e79cfc0f4..66e4d6e3d 100644 --- a/auto-merge/js/experimental/packages/shim-opencensus/README.md +++ b/auto-merge/js/experimental/packages/shim-opencensus/README.md @@ -13,11 +13,11 @@ More details are available in the [OpenCensus Compatibility Specification](https npm install --save @opentelemetry/shim-opencensus ``` -## Usage +## Tracing usage ### Installing the shim's require-in-the-middle hook -This is the recommended way to use the shim. +This is the recommended way to use the shim for tracing. This package provides a `require-in-the-middle` hook which replaces OpenCensus's `CoreTracer` class with a shim implementation that writes to the OpenTelemetry API. This will cause all @@ -72,6 +72,25 @@ tracer.startRootSpan({name: 'main'}, rootSpan => { }); ``` +## Metrics usage + +OpenCensus metrics can be collected and sent to an OpenTelemetry exporter by providing the +`OpenCensusMetricProducer` to your `MetricReader`. For example, to export OpenCensus metrics +through the OpenTelemetry Prometheus exporter: + +```js +meterProvider.addMetricReader( + new PrometheusExporter({ + metricProducers: [ + new OpenCensusMetricProducer({ + openCensusMetricProducerManager: + oc.Metrics.getMetricProducerManager(), + }), + ], + }) +); +``` + ## Example See [examples/opencensus-shim](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/examples/opencensus-shim) for a short example. diff --git a/auto-merge/js/package.json b/auto-merge/js/package.json index fb734e564..6d5460207 100644 --- a/auto-merge/js/package.json +++ b/auto-merge/js/package.json @@ -15,6 +15,7 @@ "test:browser": "lerna run test:browser", "test:webworker": "lerna run test:webworker", "test:backcompat": "lerna run test:backcompat", + "test:bench": "lerna run test:bench", "bootstrap": "lerna bootstrap --hoist --nohoist='zone.js'", "changelog": "lerna-changelog", "codecov": "lerna run codecov", @@ -65,6 +66,7 @@ "devDependencies": { "@typescript-eslint/eslint-plugin": "5.59.11", "@typescript-eslint/parser": "5.59.11", + "benchmark": "2.1.4", "eslint": "8.44.0", "eslint-config-prettier": "9.0.0", "eslint-plugin-header": "3.1.1", diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 0dab8ad1a..7ba3f0d68 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -4982,9 +4982,9 @@ "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==" }, "node_modules/@types/node": { - "version": "18.17.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.17.tgz", - "integrity": "sha512-cOxcXsQ2sxiwkykdJqvyFS+MLQPLvIdwh5l6gNg8qF6s+C7XSkEWOZjK+XhUZd+mYvHV/180g2cnCcIl4l06Pw==" + "version": "18.17.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" }, "node_modules/@types/qs": { "version": "6.9.8", @@ -7390,9 +7390,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001535", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz", - "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==", + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", "funding": [ { "type": "opencollective", @@ -8645,9 +8645,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.523", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", - "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==" + "version": "1.4.525", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.525.tgz", + "integrity": "sha512-GIZ620hDK4YmIqAWkscG4W6RwY6gOx1y5J6f4JUQwctiJrqH2oxZYU4mXHi35oV32tr630UcepBzSBGJ/WYcZA==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -10239,9 +10239,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -19264,9 +19264,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", - "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, diff --git a/pkgs/sdk/trace/base/package.json b/pkgs/sdk/trace/base/package.json index 61872ce3c..0970b15cb 100644 --- a/pkgs/sdk/trace/base/package.json +++ b/pkgs/sdk/trace/base/package.json @@ -30,6 +30,7 @@ "tdd:browser": "karma start", "tdd:node": "npm run test -- --watch-extensions ts --watch", "test": "npm run test:node && npm run test:browser && npm run test:webworker", + "test:bench": "node test/performance/benchmark/index.js", "test:browser": "nyc karma start ./karma.conf.js --single-run", "test:debug": "nyc karma start ./karma.debug.conf.js --wait", "test:node": "", diff --git a/pkgs/sdk/trace/base/test/performance/benchmark/index.js b/pkgs/sdk/trace/base/test/performance/benchmark/index.js new file mode 100644 index 000000000..83558ea01 --- /dev/null +++ b/pkgs/sdk/trace/base/test/performance/benchmark/index.js @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +require('./span'); diff --git a/pkgs/sdk/trace/base/test/performance/benchmark/span.js b/pkgs/sdk/trace/base/test/performance/benchmark/span.js new file mode 100644 index 000000000..ac978a614 --- /dev/null +++ b/pkgs/sdk/trace/base/test/performance/benchmark/span.js @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const Benchmark = require('benchmark'); +const { BasicTracerProvider } = require('../../../build/src'); + +const tracerProvider = new BasicTracerProvider(); +const tracer = tracerProvider.getTracer('test') + +const suite = new Benchmark.Suite(); + +suite.on('cycle', event => { + console.log(String(event.target)); +}); + +suite.add('create spans (10 attributes)', function() { + const span = tracer.startSpan('span'); + span.setAttribute('aaaaaaaaaaaaaaaaaaaa', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('bbbbbbbbbbbbbbbbbbbb', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('cccccccccccccccccccc', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('dddddddddddddddddddd', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('eeeeeeeeeeeeeeeeeeee', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('ffffffffffffffffffff', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('gggggggggggggggggggg', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('hhhhhhhhhhhhhhhhhhhh', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('iiiiiiiiiiiiiiiiiiii', 'aaaaaaaaaaaaaaaaaaaa'); + span.setAttribute('jjjjjjjjjjjjjjjjjjjj', 'aaaaaaaaaaaaaaaaaaaa'); +}); + +suite.run();