diff --git a/experimental/examples/opencensus-shim/README.md b/experimental/examples/opencensus-shim/README.md new file mode 100644 index 0000000000..0738d67d89 --- /dev/null +++ b/experimental/examples/opencensus-shim/README.md @@ -0,0 +1,75 @@ +# Overview + +The OpenCensus shim allows existing OpenCensus instrumentation to interoperate with OpenTelemetry instrumentation by using the OpenTelemetry SDK as an implementation for OpenCensus. + +This is a simple example that demonstrates how existing OpenCensus instrumentation can be integrated with OpenTelemetry. + +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. + +## Installation + +```sh +# from this directory +$ npm install +``` + +## Run the Application + +### Jaeger + +Setup [Jaeger Tracing All in One](https://www.jaegertracing.io/docs/latest/getting-started/#all-in-one) agent. If you have docker installed: + +```sh +docker run \ + --rm \ + --name jaeger \ + -e COLLECTOR_OTLP_ENABLED=true \ + -p 16686:16686 \ + -p 4317:4317 \ + jaegertracing/all-in-one:latest +``` + +### Run the sample server + +```sh +# from this directory +$ node -r @opentelemetry/shim-opencensus/register ./server.js +``` + +The `-r @opentelemetry/shim-opencensus/register` flag to Node tells it to load the OpenCensus +shim's register module to install the OpenCensus shim. The shim bridges all calls to +OpenCensus's tracers to OpenTelemetry. + +### Run the sample client + +```sh +# from this directory +node -r @opentelemetry/shim-opencensus/register ./client.js +``` + +Again, we use the `-r @opentelemetry/shim-opencensus/register` flag to install the OpenCensus shim. + +## Check the trace + +Go to Jaeger with your browser and click on the "Service" dropdown. Choose `opencensus-shim-example-server` and hit "Find Traces". Click on one of the available traces and you should see 3 spans: + +- An outer span from the client. This came from the OpenCensus HTTP instrumentation. + - A child from the server. This came from the OpenCensus HTTP instrumentation. + - A child for the sleep operation. This was manually instrumented with OpenTelemetry. + Notice this span is correctly recorded as a child of the OpenCensus instrumentation. + +

+ +## Useful links + +- For more information on OpenTelemetry, visit: +- For more information on OpenTelemetry for Node.js, visit: +- For more information on OpenCensus, visit: + +## LICENSE + +Apache License 2.0 diff --git a/experimental/examples/opencensus-shim/client.js b/experimental/examples/opencensus-shim/client.js new file mode 100644 index 0000000000..e0a2ed52fa --- /dev/null +++ b/experimental/examples/opencensus-shim/client.js @@ -0,0 +1,54 @@ +/* + * 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. + */ +'use strict'; + +const setup = require('./setup'); + +const provider = setup('opencensus-shim-example-client'); + +const http = require('http'); + +makeRequest(); + +async function makeRequest() { + const data = await new Promise((resolve, reject) => { + http + .get( + { + host: 'localhost', + port: 3000, + path: '/', + }, + resp => { + let data = ''; + + resp.on('data', chunk => { + data += chunk; + }); + + resp.on('end', async () => { + resolve(JSON.parse(data)); + }); + } + ) + .on('error', err => { + reject(err); + }); + }); + console.log('Got data from server: ', data); + + await provider.shutdown(); +} diff --git a/experimental/examples/opencensus-shim/images/jaeger-trace.png b/experimental/examples/opencensus-shim/images/jaeger-trace.png new file mode 100644 index 0000000000..15521f64cd Binary files /dev/null and b/experimental/examples/opencensus-shim/images/jaeger-trace.png differ diff --git a/experimental/examples/opencensus-shim/package.json b/experimental/examples/opencensus-shim/package.json new file mode 100644 index 0000000000..baddb59ee3 --- /dev/null +++ b/experimental/examples/opencensus-shim/package.json @@ -0,0 +1,41 @@ +{ + "name": "opencensus-shim", + "private": true, + "version": "0.38.0", + "description": "Example of using @opentelemetry/shim-opencensus in Node.js", + "main": "index.js", + "scripts": { + "client": "node -r @opentelemetry/shim-opencensus/register ./client.js", + "server": "node -r @opentelemetry/shim-opencensus/register ./server.js" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js.git" + }, + "keywords": [ + "opentelemetry", + "http", + "tracing", + "opencensus" + ], + "engines": { + "node": ">=14" + }, + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js/issues" + }, + "dependencies": { + "@opentelemetry/api": "1.4.1", + "@opentelemetry/sdk-trace-node": "1.13.0", + "@opencensus/core": "0.1.0", + "@opencensus/nodejs": "0.1.0", + "@opentelemetry/semantic-conventions": "1.13.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.39.1", + "@opentelemetry/resources": "1.13.0", + "@opentelemetry/shim-opencensus": "0.39.1" + }, + "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/examples/opencensus-shim", + "devDependencies": {} +} diff --git a/experimental/examples/opencensus-shim/server.js b/experimental/examples/opencensus-shim/server.js new file mode 100644 index 0000000000..98ddcf5b60 --- /dev/null +++ b/experimental/examples/opencensus-shim/server.js @@ -0,0 +1,39 @@ +'use strict'; + +const { SpanStatusCode } = require('@opentelemetry/api'); +const setup = require('./setup'); +const utils = require('./utils'); +const { trace } = require('@opentelemetry/api'); + +setup('opencensus-shim-example-server'); +const http = require('http'); + +const otelTracer = trace.getTracer('opencensus-shim-example'); + +function startServer(port) { + // requests are traced by OpenCensus http instrumentation + const server = http.createServer(async (req, res) => { + // you can mix OTel and OC instrumentation + + // deliberately sleeping to mock some action + await otelTracer.startActiveSpan('sleep', async span => { + await utils.sleep(1000); + span.end(); + }); + + trace.getActiveSpan()?.addEvent('write headers'); + res.writeHead(200, { 'Content-Type': 'application/json' }); + trace.getActiveSpan()?.addEvent('write json response'); + res.write(JSON.stringify({ status: 'OK', message: 'Hello World!' })); + trace.getActiveSpan()?.setStatus(SpanStatusCode.OK); + res.end(); + }); + + server.listen(port, err => { + if (err) throw err; + + console.log(`Server is listening on ${port}`); + }); +} + +startServer(3000); diff --git a/experimental/examples/opencensus-shim/setup.js b/experimental/examples/opencensus-shim/setup.js new file mode 100644 index 0000000000..e96c62ae0c --- /dev/null +++ b/experimental/examples/opencensus-shim/setup.js @@ -0,0 +1,51 @@ +/* + * 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. + */ +'use strict'; + +const { DiagConsoleLogger, diag, DiagLogLevel } = require('@opentelemetry/api'); +const { + NodeTracerProvider, + BatchSpanProcessor, +} = require('@opentelemetry/sdk-trace-node'); +const { + OTLPTraceExporter, +} = require('@opentelemetry/exporter-trace-otlp-grpc'); +const { Resource } = require('@opentelemetry/resources'); +const { + SemanticResourceAttributes, +} = require('@opentelemetry/semantic-conventions'); + +module.exports = function setup(serviceName) { + const tracing = require('@opencensus/nodejs'); + + diag.setLogger(new DiagConsoleLogger(), { logLevel: DiagLogLevel.ALL }); + const provider = new NodeTracerProvider({ + resource: new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: serviceName, + }), + }); + provider.addSpanProcessor( + new BatchSpanProcessor(new OTLPTraceExporter(), { + scheduledDelayMillis: 5000, + }) + ); + provider.register(); + + // Start OpenCensus tracing + tracing.start({ samplingRate: 1, logger: diag }); + + return provider; +}; diff --git a/experimental/examples/opencensus-shim/utils.js b/experimental/examples/opencensus-shim/utils.js new file mode 100644 index 0000000000..3b1c625009 --- /dev/null +++ b/experimental/examples/opencensus-shim/utils.js @@ -0,0 +1,22 @@ +/* + * 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. + */ +'use strict'; + +async function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +exports.sleep = sleep; diff --git a/experimental/packages/shim-opencensus/README.md b/experimental/packages/shim-opencensus/README.md index e614fccf38..e79cfc0f43 100644 --- a/experimental/packages/shim-opencensus/README.md +++ b/experimental/packages/shim-opencensus/README.md @@ -15,7 +15,64 @@ npm install --save @opentelemetry/shim-opencensus ## Usage -TODO +### Installing the shim's require-in-the-middle hook + +This is the recommended way to use the shim. + +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 +usage of OpenCensus's tracing methods (in OpenCensus instrumentation or your own custom +instrumentation) to be reported to OpenTelemetry. + +There are two options for installing the hook: + +1. Using Node's `--require` flag to load the register module: + + ```sh + node --require @opentelemetry/shim-opencensus/register ./app.js + ``` + +2. Programmatically: + + ```js + // Early in your application startup + require('@opentelemetry/shim-opencensus').installShim(); + ``` + + Note that this has to be run before any OpenCensus tracers have been created. + +### Replace OpenCensus tracer with the `ShimTracer` in your code + +Alternatively, you can replace any usage of OpenCensus tracers in your code with the `ShimTracer` directly. + +Before: + +```js +const tracing = require('@opencensus/nodejs'); +const tracer = tracing.start({samplingRate: 1}).tracer; + +// ... + +tracer.startRootSpan({name: 'main'}, rootSpan => { + rootSpan.end(); +}); +``` + +After: + +```js +const { trace } = require('@opentelemetry/api'); +const { ShimTracer } = require('@opentelemetry/shim-opencensus'); +const tracer = new ShimTracer(trace.getTracer('my-module')); + +// ... + +tracer.startRootSpan({name: 'main'}, rootSpan => { + rootSpan.end(); +}); +``` + +## 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/experimental/packages/shim-opencensus/package.json b/experimental/packages/shim-opencensus/package.json index ec3c5dafed..675c3c4cf6 100644 --- a/experimental/packages/shim-opencensus/package.json +++ b/experimental/packages/shim-opencensus/package.json @@ -4,6 +4,10 @@ "description": "OpenCensus to OpenTelemetry shim", "main": "build/src/index.js", "types": "build/src/index.d.ts", + "exports": { + ".": "./build/src/index.js", + "./register": "./build/src/register.js" + }, "repository": "open-telemetry/opentelemetry-js", "scripts": { "prepublishOnly": "npm run compile", diff --git a/experimental/packages/shim-opencensus/src/index.ts b/experimental/packages/shim-opencensus/src/index.ts index ccfe42e2f8..5df2f6c315 100644 --- a/experimental/packages/shim-opencensus/src/index.ts +++ b/experimental/packages/shim-opencensus/src/index.ts @@ -15,3 +15,4 @@ */ export { ShimTracer } from './ShimTracer'; +export { installShim, uninstallShim } from './shim';