diff --git a/.gitignore b/.gitignore index 842fc0c4..d81ee49f 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ Temporary Items ### Node ### # Logs -logs +/logs *.log npm-debug.log* yarn-debug.log* diff --git a/MIGRATING.md b/MIGRATING.md new file mode 100644 index 00000000..cdb427a3 --- /dev/null +++ b/MIGRATING.md @@ -0,0 +1,154 @@ +# Migrate from the SignalFx Tracing Library for NodeJS + +The Splunk Distribution of OpenTelemetry for NodeJS replaces the SignalFx Tracing +Library for NodeJS. If you’re using the SignalFx Tracing Library, migrate to +the Splunk Distribution of OpenTelemetry for NodeJS to use OpenTelemetry +instrumentation to send traces to Splunk APM. The Splunk Distribution of +OpenTelemetry for NodeJS uses OpenTelemetry to instrument applications, which is +an open-source API to gather telemetry data, and has a smaller footprint. + +Because the SignalFx Tracing Library for NodeJS uses OpenTracing and the Splunk Distribution of OpenTelemetry for NodeJS +uses OpenTelemetry, the semantic conventions for span names and attributes change when you migrate. For more +information, see +[Migrate from OpenTracing to OpenTelemetry](https://docs.signalfx.com/en/latest/apm/apm-getting-started/apm-opentelemetry-collector.html#apm-opentelemetry-migration). + +## Getting help + +If you experience any issues following the guide below, or something is unclear, or missing, please don't hesitate to +open an issue in Github. Any and all ideas for improvements are also welcome. + + +## Known limitations as compared to SignalFx Tracing Library + +- Different subset of supported Node.js versions, see [Requirements section](#requirements) for more information. +- No auto-instrumentation for: + - `AdonisJS`, + - `amqp10`, + - `mongodb-core` ([because it's deprecated](https://github.com/mongodb-js/mongodb-core)), but note that there is + [an instrumentation for MongoDB driver](https://opentelemetry.io/registry/?s=mongodb&component=&language=js#), + - `sails`. +- Limited instrumentation for: + - `nest` - only manual instrumentation helpers, provided by community. +- Other notes on instrumentation: + - `express`, `koa` and `hapi` instrumentations require active `http`/`https` instrumentation to produce spans, + - `bluebird`, `q`, `when` - supported out-of-the-box via `AsyncLocalStorageContextManager` (or `AsyncHooksContextManager` in Node.js below `14.8`), + - `socket.io` - provided by community and improved by Splunk (). + +## Changes to defaults + +- Default flush interval, which defines how frequently captured telemetry data is sent to the backend, is now 30s instead of 2s + +## Requirements + +This Splunk Distribution of OpenTelemetry requires Node.js 8.5 or later, +[see more information here](https://github.com/open-telemetry/opentelemetry-js#node-support) +If you're still using an earlier version of Node.js, continue using the SignalFx Tracing Library for Node.js. + +Current effective required Node.js version is: ![node-current](https://img.shields.io/node/v/@splunk/otel?style=flat-square) + +## Migration steps + +### Instrumented libraries + +With the exception of [explicitly listed limitations](#known-limitations) we aim to support all libraries supported by +signalfx-nodejs-tracing. To find an equivalent auto-instrumentation open and for +each instrumentation +[from `signalfx-nodejs-tracing`'s README](https://github.com/signalfx/signalfx-nodejs-tracing/#requirements-and-supported-software) +search by the name of the library in the registry. + +For example, if you'd like to migrate instrumentation for `mysql`, go to +[https://opentelemetry.io/registry/?s=**mysql**&component=&language=**js**#](https://opentelemetry.io/registry/?s=mysql&component=&language=js#). + +Once you have identified an instrumentation package, **install it** using npm or Yarn. + +- If the package is [on this list](./README.md#default-instrumentation-packages-), it + will be enabled automatically (**but it won't be installed automatically**). +- if it's not on the list, follow the steps for + [installing other instrumentation packages](./README.md#custom-instrumentation-packages). + +### Environment variables + +Rename environment variables: + +| OpenTracing environment variable | OpenTelemetry environment variable | notes | +| ---------------------------------- | ------------------------------------ | ----- | +| SIGNALFX_ACCESS_TOKEN | SPLUNK_ACCESS_TOKEN | | +| SIGNALFX_SERVICE_NAME | OTEL_SERVICE_NAME | | +| SIGNALFX_ENDPOINT_URL | OTEL_EXPORTER_JAEGER_ENDPOINT | if Jaeger is used | +| SIGNALFX_ENDPOINT_URL | n/a | OTLP is not implemented yet | +| SIGNALFX_RECORDED_VALUE_MAX_LENGTH | SPLUNK_MAX_ATTR_LENGTH | | +| SIGNALFX_TRACING_DEBUG | no direct equivalent | see [instrumentation logs](#instrumentation-logs) | +| SIGNALFX_SPAN_TAGS | OTEL_RESOURCE_ATTRIBUTES | format needs to be changed to `key1=val1,key2=val2` | +| SIGNALFX_LOGS_INJECTION | SPLUNK_LOGS_INJECTION | | +| SIGNALFX_LOGS_INJECTION_TAGS | OTEL_RESOURCE_ATTRIBUTES | there's no direct equivalent, but values specified in `OTEL_RESOURCE_ATTRIBUTES` will also be used for logs injection | +| SIGNALFX_ENABLED_PLUGINS | n/a | see [the README section about instrumentations](./README.md#custom-instrumentation-packages) | +| SIGNALFX_SERVER_TIMING_CONTEXT | SPLUNK_TRACE_RESPONSE_HEADER_ENABLED | | +| SIGNALFX_TRACING_ENABLED | OTEL_TRACE_ENABLED | | + +### Programmatic configuration + +Update these programmatic configuration options: + +| OpenTracing property | OpenTelemetry property | Notes | +| ------------------------ | ----------------------- | ----- | +| `service` | `serviceName` | | +| `url` | `endpoint` | | +| `accessToken` | `accessToken` | | +| `enabled` | - | no equivalent, but Environment Variable can be used | +| `debug` | - | no direct equivalent, see [instrumentation logs](#instrumentation-logs) | +| `tags` | `tracerConfig.resource` | | +| `logInjection` | `logInjectionEnabled` | | +| `logInjectionTags` | - | no direct equivalent, but `tracerConfig.resource` can be used | +| `flushInterval` | - | no direct equivalent, contact us if you had customized this value | +| `plugins` | - | see [the README section about instrumentations](./README.md#custom-instrumentation-packages) | +| `recordedValueMaxLength` | `maxAttrLength` | | +| `enableServerTiming` | `serverTimingEnabled` | | + +### Instrumentation entry point + +```javascript +const tracer = require('signalfx-tracing').init({ + // your options here +}) +``` + +becomes + +```javascript +const { startTracing } = require('@splunk/otel'); + +startTracing({ + // your new options here +}); +``` + +and requires installing `@splunk/otel` first, using either npm or Yarn. Same as in `signalfx-nodejs-tracing`, this code +is to be run before your `import` or `require` statements. + +Alternatively, you can append the flag `-r @splunk/otel/instrument` instead when launching `node` (it runs +`startTracing` under the hood). In that case you cannot use programmatic configuration and must rely on environment +variables only. + +### Instrumentation logs + +There isn't a one-to-one mapping for `SIGNALFX_TRACING_DEBUG`. The closest equivalent is `OTEL_LOG_LEVEL`, however the +logged information will be different. + +> Note that this section is about the logs produced by instrumentation, and not +about the logs produced by the application. + +Logging level is controlled by the `OTEL_LOG_LEVEL` environment variable. The two most common values are: +- `INFO`: the default value +- `VERBOSE`: highest value likely to be needed + +For all possible log levels see +[this source file](https://github.com/open-telemetry/opentelemetry-js-api/blob/main/src/diag/types.ts). + +There is no default output for logs. Even if you set `OTEL_LOG_LEVEL=VERBOSE`, nothing is output to the console. You +need to set an output first, for example to `stdout`, by adding `DiagConsoleLogger`: + +```js +const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); + +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); +``` diff --git a/README.md b/README.md index 0a3bf44d..b9f3dbfa 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@

Beta - GitHub branch checks state GitHub release (latest by date) npm node-current Codecov + GitHub branch checks state

-# Splunk distribution of OpenTelemetry JS +# Splunk distribution of OpenTelemetry JS for NodeJS The Splunk distribution of [OpenTelemetry JS](https://github.com/open-telemetry/opentelemetry-js) provides @@ -29,7 +29,7 @@ This Splunk distribution comes with the following defaults: If you're currently using the SignalFx Tracing Library for Node and want to migrate to the Splunk Distribution of OpenTelemetry Node, see [Migrate from -the SignalFx Tracing Library for JS](migration.md). +the SignalFx Tracing Library for JS](./MIGRATING.md). > :construction: This project is currently in **BETA**. It is **officially supported** by Splunk. However, breaking changes **MAY** be introduced. @@ -225,20 +225,25 @@ By default the following instrumentations will automatically be enabled if they any of these instrumentations, you'll need to install them with npm and then run your app with `-r @splunk/otel/instrument` flag as described above. ``` -@opentelemetry/instrumentation-http @opentelemetry/instrumentation-dns +@opentelemetry/instrumentation-express @opentelemetry/instrumentation-graphql @opentelemetry/instrumentation-grpc -@opentelemetry/instrumentation-koa -@opentelemetry/instrumentation-express +@opentelemetry/instrumentation-hapi +@opentelemetry/instrumentation-http @opentelemetry/instrumentation-ioredis +@opentelemetry/instrumentation-koa @opentelemetry/instrumentation-mongodb @opentelemetry/instrumentation-mysql @opentelemetry/instrumentation-net @opentelemetry/instrumentation-pg -@opentelemetry/instrumentation-hapi opentelemetry-instrumentation-amqplib +opentelemetry-instrumentation-aws-sdk opentelemetry-instrumentation-elasticsearch +opentelemetry-instrumentation-kafkajs +opentelemetry-instrumentation-mongoose +opentelemetry-instrumentation-sequelize +opentelemetry-instrumentation-typeorm ``` If log injection is enabled, the corresponding logging library package will need to be installed beforehand. Supported logging library instrumentations: diff --git a/examples/logs/.gitignore b/examples/logs/.gitignore new file mode 100644 index 00000000..504afef8 --- /dev/null +++ b/examples/logs/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +package-lock.json diff --git a/examples/logs/index.js b/examples/logs/index.js new file mode 100644 index 00000000..bba0ccc7 --- /dev/null +++ b/examples/logs/index.js @@ -0,0 +1,17 @@ +const { diag, DiagConsoleLogger } = require("@opentelemetry/api"); +const { NodeTracerProvider } = require("@opentelemetry/node"); +const { registerInstrumentations } = require("@opentelemetry/instrumentation"); +const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http"); +const { getEnv } = require("@opentelemetry/core"); + +// TODO: this is quite inconvenient +diag.setLogger(new DiagConsoleLogger(), getEnv().OTEL_LOG_LEVEL); + +const provider = new NodeTracerProvider(); +provider.register(); + +registerInstrumentations({ + instrumentations: [ + new HttpInstrumentation(), + ], +}); diff --git a/examples/logs/package.json b/examples/logs/package.json new file mode 100644 index 00000000..9d04f8d9 --- /dev/null +++ b/examples/logs/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@opentelemetry/api": "^1.0.1", + "@splunk/otel": "^0.9.0" + } +} diff --git a/package.json b/package.json index a8eca345..a227f5e6 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ }, "peerDependencies": { "@opentelemetry/instrumentation-bunyan": "^0.23.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.23.0", "@opentelemetry/instrumentation-dns": "^0.23.0", "@opentelemetry/instrumentation-express": "^0.23.0", "@opentelemetry/instrumentation-graphql": "^0.23.0", @@ -100,9 +101,12 @@ "@opentelemetry/instrumentation-hapi": "^0.23.0", "@opentelemetry/instrumentation-http": "^0.23.0", "@opentelemetry/instrumentation-ioredis": "^0.23.0", + "@opentelemetry/instrumentation-knex": "^0.23.0", "@opentelemetry/instrumentation-koa": "^0.23.0", + "@opentelemetry/instrumentation-memcached": "^0.23.0", "@opentelemetry/instrumentation-mongodb": "^0.23.0", "@opentelemetry/instrumentation-mysql": "^0.23.0", + "@opentelemetry/instrumentation-mysql2": "^0.23.0", "@opentelemetry/instrumentation-net": "^0.23.0", "@opentelemetry/instrumentation-pg": "^0.23.0", "@opentelemetry/instrumentation-pino": "^0.23.0", @@ -185,6 +189,18 @@ }, "opentelemetry-instrumentation-mongoose": { "optional": true + }, + "@opentelemetry/instrumentation-cassandra-driver": { + "optional": true + }, + "@opentelemetry/instrumentation-knex": { + "optional": true + }, + "@opentelemetry/instrumentation-memcached": { + "optional": true + }, + "@opentelemetry/instrumentation-mysql2": { + "optional": true } } } diff --git a/src/instrumentations/index.ts b/src/instrumentations/index.ts index 031f4bc8..08c32ab5 100644 --- a/src/instrumentations/index.ts +++ b/src/instrumentations/index.ts @@ -18,32 +18,44 @@ import { InstrumentationOption } from '@opentelemetry/instrumentation'; import { load } from './loader'; +// please keep the list sorted alphabetically +// please update ../../README.md#default-instrumentation-packages when changing this list +// please check if ../../MIGRATING.md#known-limitations needs to be updated when changing this list const supportedInstrumentations: [string, string][] = [ - ['@opentelemetry/instrumentation-http', 'HttpInstrumentation'], + ['@opentelemetry/instrumentation-bunyan', 'BunyanInstrumentation'], + [ + '@opentelemetry/instrumentation-cassandra-driver', + 'CassandraDriverInstrumentation', + ], ['@opentelemetry/instrumentation-dns', 'DnsInstrumentation'], + ['@opentelemetry/instrumentation-express', 'ExpressInstrumentation'], ['@opentelemetry/instrumentation-graphql', 'GraphQLInstrumentation'], ['@opentelemetry/instrumentation-grpc', 'GrpcInstrumentation'], - ['@opentelemetry/instrumentation-koa', 'KoaInstrumentation'], - ['@opentelemetry/instrumentation-express', 'ExpressInstrumentation'], + ['@opentelemetry/instrumentation-hapi', 'HapiInstrumentation'], + ['@opentelemetry/instrumentation-http', 'HttpInstrumentation'], ['@opentelemetry/instrumentation-ioredis', 'IORedisInstrumentation'], + ['@opentelemetry/instrumentation-knex', 'KnexInstrumentation'], + ['@opentelemetry/instrumentation-koa', 'KoaInstrumentation'], + ['@opentelemetry/instrumentation-memcached', 'MemcachedInstrumentation'], ['@opentelemetry/instrumentation-mongodb', 'MongoDBInstrumentation'], ['@opentelemetry/instrumentation-mysql', 'MySQLInstrumentation'], + ['@opentelemetry/instrumentation-mysql2', 'MySQL2Instrumentation'], ['@opentelemetry/instrumentation-net', 'NetInstrumentation'], ['@opentelemetry/instrumentation-pg', 'PgInstrumentation'], - ['@opentelemetry/instrumentation-hapi', 'HapiInstrumentation'], - ['@opentelemetry/instrumentation-bunyan', 'BunyanInstrumentation'], ['@opentelemetry/instrumentation-pino', 'PinoInstrumentation'], + ['@opentelemetry/instrumentation-redis', 'RedisInstrumentation'], + ['@opentelemetry/instrumentation-restify', 'RestifyInstrumentation'], ['@opentelemetry/instrumentation-winston', 'WinstonInstrumentation'], ['opentelemetry-instrumentation-amqplib', 'AmqplibInstrumentation'], + ['opentelemetry-instrumentation-aws-sdk', 'AwsInstrumentation'], [ 'opentelemetry-instrumentation-elasticsearch', 'ElasticsearchInstrumentation', ], - ['opentelemetry-instrumentation-aws-sdk', 'AwsInstrumentation'], ['opentelemetry-instrumentation-kafkajs', 'KafkaJsInstrumentation'], + ['opentelemetry-instrumentation-mongoose', 'MongooseInstrumentation'], ['opentelemetry-instrumentation-sequelize', 'SequelizeInstrumentation'], ['opentelemetry-instrumentation-typeorm', 'TypeormInstrumentation'], - ['opentelemetry-instrumentation-mongoose', 'MongooseInstrumentation'], ]; export function getInstrumentations(): InstrumentationOption[] { diff --git a/src/options.ts b/src/options.ts index 044a4d5c..af3a9ea4 100644 --- a/src/options.ts +++ b/src/options.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { env } from 'process'; import { SpanExporter, SpanProcessor } from '@opentelemetry/tracing'; import { InstrumentationOption } from '@opentelemetry/instrumentation'; import { B3Propagator, B3InjectEncoding } from '@opentelemetry/propagator-b3'; @@ -84,8 +83,12 @@ export function _setDefaultOptions(options: Partial = {}): Options { options.logInjectionEnabled = getEnvBoolean('SPLUNK_LOGS_INJECTION', false); } + const otelEnv = getEnv(); + options.endpoint = - options.endpoint || env.OTEL_EXPORTER_JAEGER_ENDPOINT || defaultEndpoint; + options.endpoint || + otelEnv.OTEL_EXPORTER_JAEGER_ENDPOINT || + defaultEndpoint; const extraTracerConfig = options.tracerConfig || {}; @@ -93,7 +96,7 @@ export function _setDefaultOptions(options: Partial = {}): Options { const serviceName = options.serviceName || - getEnv().OTEL_SERVICE_NAME || + otelEnv.OTEL_SERVICE_NAME || resource.attributes[ResourceAttributes.SERVICE_NAME] || defaultServiceName; diff --git a/test/instrumentations.test.ts b/test/instrumentations.test.ts index 7582a75c..13651658 100644 --- a/test/instrumentations.test.ts +++ b/test/instrumentations.test.ts @@ -23,31 +23,40 @@ import * as loader from '../src/instrumentations/loader'; describe('instrumentations', () => { const supportedInstrumentations = [ - ['@opentelemetry/instrumentation-http', 'HttpInstrumentation'], + ['@opentelemetry/instrumentation-bunyan', 'BunyanInstrumentation'], + [ + '@opentelemetry/instrumentation-cassandra-driver', + 'CassandraDriverInstrumentation', + ], ['@opentelemetry/instrumentation-dns', 'DnsInstrumentation'], + ['@opentelemetry/instrumentation-express', 'ExpressInstrumentation'], ['@opentelemetry/instrumentation-graphql', 'GraphQLInstrumentation'], ['@opentelemetry/instrumentation-grpc', 'GrpcInstrumentation'], - ['@opentelemetry/instrumentation-koa', 'KoaInstrumentation'], - ['@opentelemetry/instrumentation-express', 'ExpressInstrumentation'], + ['@opentelemetry/instrumentation-hapi', 'HapiInstrumentation'], + ['@opentelemetry/instrumentation-http', 'HttpInstrumentation'], ['@opentelemetry/instrumentation-ioredis', 'IORedisInstrumentation'], + ['@opentelemetry/instrumentation-knex', 'KnexInstrumentation'], + ['@opentelemetry/instrumentation-koa', 'KoaInstrumentation'], + ['@opentelemetry/instrumentation-memcached', 'MemcachedInstrumentation'], ['@opentelemetry/instrumentation-mongodb', 'MongoDBInstrumentation'], ['@opentelemetry/instrumentation-mysql', 'MySQLInstrumentation'], + ['@opentelemetry/instrumentation-mysql2', 'MySQL2Instrumentation'], ['@opentelemetry/instrumentation-net', 'NetInstrumentation'], ['@opentelemetry/instrumentation-pg', 'PgInstrumentation'], - ['@opentelemetry/instrumentation-hapi', 'HapiInstrumentation'], - ['@opentelemetry/instrumentation-bunyan', 'BunyanInstrumentation'], ['@opentelemetry/instrumentation-pino', 'PinoInstrumentation'], + ['@opentelemetry/instrumentation-redis', 'RedisInstrumentation'], + ['@opentelemetry/instrumentation-restify', 'RestifyInstrumentation'], ['@opentelemetry/instrumentation-winston', 'WinstonInstrumentation'], ['opentelemetry-instrumentation-amqplib', 'AmqplibInstrumentation'], + ['opentelemetry-instrumentation-aws-sdk', 'AwsInstrumentation'], [ 'opentelemetry-instrumentation-elasticsearch', 'ElasticsearchInstrumentation', ], - ['opentelemetry-instrumentation-aws-sdk', 'AwsInstrumentation'], ['opentelemetry-instrumentation-kafkajs', 'KafkaJsInstrumentation'], + ['opentelemetry-instrumentation-mongoose', 'MongooseInstrumentation'], ['opentelemetry-instrumentation-sequelize', 'SequelizeInstrumentation'], ['opentelemetry-instrumentation-typeorm', 'TypeormInstrumentation'], - ['opentelemetry-instrumentation-mongoose', 'MongooseInstrumentation'], ]; it('does not load if packages are not installed', () => {