diff --git a/packages/opentelemetry-node/docs/supported-technologies.md b/packages/opentelemetry-node/docs/supported-technologies.md index 1b088e3d..70832bb0 100644 --- a/packages/opentelemetry-node/docs/supported-technologies.md +++ b/packages/opentelemetry-node/docs/supported-technologies.md @@ -42,11 +42,12 @@ requires: | `@opentelemetry/instrumentation-cassandra-driver` | `cassandra-driver` version range `>=4.4.0 <5` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-cassandra#readme) | | `@opentelemetry/instrumentation-express` | `express` version range `^4.0.0` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-express#readme) | | `@opentelemetry/instrumentation-fastify` | `fastify` version range `>=3 <5` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-fastify#readme) | +| `@opentelemetry/instrumentation-fs` | `fs` module for suppported Node.js versions | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/instrumentation-fs#readme) | | `@opentelemetry/instrumentation-generic-pool` | `generic-pool` version range `2 - 2.3, ^2.4, >=3` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-generic-pool#readme) | | `@opentelemetry/instrumentation-graphql` | `graphql` version range `>=14.0.0 <17` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-graphql#readme) | | `@opentelemetry/instrumentation-grpc` | `@grpc/grpc-js` version range `^1.0.0` | [README](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-grpc#readme) | | `@opentelemetry/instrumentation-hapi` | `@hapi/hapi >=17.0.0 <21` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-hapi#readme) | -| `@opentelemetry/instrumentation-http` | `http` module for Node.js `>=14` | [README](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-http#readme) | +| `@opentelemetry/instrumentation-http` | `http` module for suppported Node.js versions | [README](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-http#readme) | | `@opentelemetry/instrumentation-ioredis` | `ioredis` version range `>=2 <6` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-ioredis#readme) | | `@opentelemetry/instrumentation-kafkajs` | `kafkajs` version range `>=0.1.0 <3` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/instrumentation-kafkajs#readme) | | `@opentelemetry/instrumentation-knex` | `knex` version range `>=0.10.0` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-knex#readme) | @@ -58,7 +59,7 @@ requires: | `@opentelemetry/instrumentation-mysql` | `mysql` version range `>=2.0.0 <3` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-mysql#readme) | | `@opentelemetry/instrumentation-mysql2` | `mysql2` version range `>=1.4.2 <4` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-mysql2#readme) | | `@opentelemetry/instrumentation-nestjs-core` | `@nestjs/core` version range `>=4.0.0` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-nestjs-core#readme) | -| `@opentelemetry/instrumentation-net` | `net` module for Node.js `>=14` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-net#readme) | +| `@opentelemetry/instrumentation-net` | `net` module for suppported Node.js versions | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-net#readme) | | `@opentelemetry/instrumentation-pino` | `pino` version range `>=5.14.0 <10` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-pino#readme) | | `@opentelemetry/instrumentation-pg` | `pg` version range `>=8 <9` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-pg#readme) | | `@opentelemetry/instrumentation-redis-4` | `redis` version range `^4.0.0` | [README](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-redis-4#readme) | diff --git a/packages/opentelemetry-node/lib/instrumentations.js b/packages/opentelemetry-node/lib/instrumentations.js index f50ee045..53ed7756 100644 --- a/packages/opentelemetry-node/lib/instrumentations.js +++ b/packages/opentelemetry-node/lib/instrumentations.js @@ -35,6 +35,7 @@ * "@opentelemetry/instrumentation-dns": import('@opentelemetry/instrumentation-dns').DnsInstrumentationConfig | InstrumentationFactory, * "@opentelemetry/instrumentation-express": import('@opentelemetry/instrumentation-express').ExpressInstrumentationConfig | InstrumentationFactory, * "@opentelemetry/instrumentation-fastify": import('@opentelemetry/instrumentation-fastify').FastifyInstrumentationConfig | InstrumentationFactory, + * "@opentelemetry/instrumentation-fs": import('@opentelemetry/instrumentation-fs').FsInstrumentationConfig | InstrumentationFactory, * "@opentelemetry/instrumentation-generic-pool": import('@opentelemetry/instrumentation').InstrumentationConfig | InstrumentationFactory, * "@opentelemetry/instrumentation-graphql": import('@opentelemetry/instrumentation-graphql').GraphQLInstrumentation | InstrumentationFactory, * "@opentelemetry/instrumentation-grpc": import('@opentelemetry/instrumentation-grpc').GrpcInstrumentationConfig | InstrumentationFactory, @@ -77,6 +78,7 @@ const {CucumberInstrumentation} = require('@opentelemetry/instrumentation-cucumb const {DataloaderInstrumentation} = require('@opentelemetry/instrumentation-dataloader'); const {DnsInstrumentation} = require('@opentelemetry/instrumentation-dns'); const {ExpressInstrumentation} = require('@opentelemetry/instrumentation-express'); +const {FsInstrumentation} = require('@opentelemetry/instrumentation-fs'); const {FastifyInstrumentation} = require('@opentelemetry/instrumentation-fastify'); const {GenericPoolInstrumentation} = require('@opentelemetry/instrumentation-generic-pool'); const {GraphQLInstrumentation} = require('@opentelemetry/instrumentation-graphql'); @@ -130,6 +132,7 @@ const INSTRUMENTATIONS = { '@opentelemetry/instrumentation-dns': (cfg) => new DnsInstrumentation(cfg), '@opentelemetry/instrumentation-express': (cfg) => new ExpressInstrumentation(cfg), '@opentelemetry/instrumentation-fastify': (cfg) => new FastifyInstrumentation(cfg), + '@opentelemetry/instrumentation-fs': (cfg) => new FsInstrumentation(cfg), '@opentelemetry/instrumentation-generic-pool': (cfg) => new GenericPoolInstrumentation(cfg), '@opentelemetry/instrumentation-graphql': (cfg) => new GraphQLInstrumentation(cfg), '@opentelemetry/instrumentation-grpc': (cfg) => new GrpcInstrumentation(cfg), @@ -272,19 +275,24 @@ function getInstrumentations(opts = {}) { const isFactory = typeof opts[name] === 'function'; const isObject = typeof opts[name] === 'object'; const instrFactory = isFactory ? opts[name] : INSTRUMENTATIONS[name]; - const instrConfig = isObject ? opts[name] : undefined; + let instrConfig = isObject ? opts[name] : undefined; // We should instantiate a instrumentation: // - if set via OTEL_NODE_ENABLED_INSTRUMENTATIONS // - overriding any config that might be passed // NOTE: factories are not overwritten // - otherwise - // - of there is no config passed (elastic SDK will use its defaults) + // - if there is no config passed (elastic SDK will use its defaults) // - if the configuration passed is not disabling it let instr; - if (instrConfig && enabledFromEnv) { - instrConfig.enabled = true; + if (enabledFromEnv) { + instrConfig = {...instrConfig, enabled: true}; + } else if (name === '@opentelemetry/instrumentation-fs') { + // if `fs` not present in envvar instrumentation is disabled + // unless an explicit config says the opposite + // ref: https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2467 + instrConfig = {enabled: false, ...instrConfig}; } if (!instrConfig || instrConfig.enabled !== false) { diff --git a/packages/opentelemetry-node/package-lock.json b/packages/opentelemetry-node/package-lock.json index 8ea950c8..4b97e328 100644 --- a/packages/opentelemetry-node/package-lock.json +++ b/packages/opentelemetry-node/package-lock.json @@ -29,6 +29,7 @@ "@opentelemetry/instrumentation-dns": "^0.43.0", "@opentelemetry/instrumentation-express": "^0.47.0", "@opentelemetry/instrumentation-fastify": "^0.44.0", + "@opentelemetry/instrumentation-fs": "^0.19.0", "@opentelemetry/instrumentation-generic-pool": "^0.43.0", "@opentelemetry/instrumentation-graphql": "^0.47.0", "@opentelemetry/instrumentation-grpc": "^0.57.1", @@ -2708,6 +2709,21 @@ "@opentelemetry/api": "^1.3.0" } }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.0.tgz", + "integrity": "sha512-JGwmHhBkRT2G/BYNV1aGI+bBjJu4fJUD/5/Jat0EWZa2ftrLV3YE8z84Fiij/wK32oMZ88eS8DI4ecLGZhpqsQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, "node_modules/@opentelemetry/instrumentation-generic-pool": { "version": "0.43.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.0.tgz", @@ -11674,6 +11690,15 @@ "@opentelemetry/semantic-conventions": "^1.27.0" } }, + "@opentelemetry/instrumentation-fs": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.0.tgz", + "integrity": "sha512-JGwmHhBkRT2G/BYNV1aGI+bBjJu4fJUD/5/Jat0EWZa2ftrLV3YE8z84Fiij/wK32oMZ88eS8DI4ecLGZhpqsQ==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.0" + } + }, "@opentelemetry/instrumentation-generic-pool": { "version": "0.43.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.0.tgz", diff --git a/packages/opentelemetry-node/package.json b/packages/opentelemetry-node/package.json index 52e8e447..64d88780 100644 --- a/packages/opentelemetry-node/package.json +++ b/packages/opentelemetry-node/package.json @@ -85,6 +85,7 @@ "@opentelemetry/instrumentation-dns": "^0.43.0", "@opentelemetry/instrumentation-express": "^0.47.0", "@opentelemetry/instrumentation-fastify": "^0.44.0", + "@opentelemetry/instrumentation-fs": "^0.19.0", "@opentelemetry/instrumentation-generic-pool": "^0.43.0", "@opentelemetry/instrumentation-graphql": "^0.47.0", "@opentelemetry/instrumentation-grpc": "^0.57.1", diff --git a/packages/opentelemetry-node/test/fixtures/use-fs.js b/packages/opentelemetry-node/test/fixtures/use-fs.js new file mode 100644 index 00000000..99f81408 --- /dev/null +++ b/packages/opentelemetry-node/test/fixtures/use-fs.js @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ + +// Usage: node -r @elastic/opentelemetry-node use-fs.js + +const {join} = require('path'); +const {stat} = require('fs'); +const {trace} = require('@opentelemetry/api'); + +const path = join(__dirname, 'use-fs.js'); + +async function main() { + await new Promise((resolve, reject) => { + stat(path, (err, st) => { + if (err) { + reject(err); + } else { + resolve(st); + } + }); + }); +} + +const tracer = trace.getTracer('test'); +tracer.startActiveSpan('manual-span', async (span) => { + await main(); + span.end(); +}); diff --git a/packages/opentelemetry-node/test/instr-fs.test.js b/packages/opentelemetry-node/test/instr-fs.test.js new file mode 100644 index 00000000..539735c5 --- /dev/null +++ b/packages/opentelemetry-node/test/instr-fs.test.js @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ + +// Test that 'express' instrumentation generates the telemetry we expect. + +const test = require('tape'); +const {runTestFixtures} = require('./testutils'); + +/** @type {import('./testutils').TestFixture[]} */ +const testFixtures = [ + { + name: 'use-fs (default disabled)', + args: ['./fixtures/use-fs.js'], + cwd: __dirname, + env: { + NODE_OPTIONS: '--require=@elastic/opentelemetry-node', + }, + // verbose: true, + checkTelemetry: (t, col) => { + // We expect spans like this + // ------ trace 6dc0c7 (2 spans) ------ + // span 3d5f2a "manual-span" (1.2ms, SPAN_KIND_INTERNAL) + const spans = col.sortedSpans; + t.equal(spans.length, 1); + + t.equal(spans[0].name, 'manual-span'); + t.equal(spans[0].kind, 'SPAN_KIND_INTERNAL'); + }, + }, + { + name: 'use-fs (enabled via env var)', + args: ['./fixtures/use-fs.js'], + cwd: __dirname, + env: { + NODE_OPTIONS: '--require=@elastic/opentelemetry-node', + OTEL_NODE_ENABLED_INSTRUMENTATIONS: 'fs', + }, + // verbose: true, + checkTelemetry: (t, col) => { + // We expect spans like this + // ------ trace 7c87d0 (1 span) ------ + // span 1ecc98 "fs statSync" (0.0ms, SPAN_KIND_INTERNAL) + // ------ trace 281967 (1 span) ------ + // span 7bab63 "fs statSync" (0.0ms, SPAN_KIND_INTERNAL) + // ------ trace 8b214a (1 span) ------ + // span 417068 "fs readFileSync" (0.1ms, SPAN_KIND_INTERNAL) + // ------ trace d61bc6 (1 span) ------ + // span a6f9cc "fs statSync" (0.1ms, SPAN_KIND_INTERNAL) + // ------ trace 292114 (2 spans) ------ + // span c66b96 "manual-span" (6.6ms, SPAN_KIND_INTERNAL) + // +1ms `- span 5b7d1c "fs stat" (6.3ms, SPAN_KIND_INTERNAL) + const spans = col.sortedSpans; + t.equal(spans.length, 18); + + t.strictEqual( + spans.filter( + (s) => s.scope.name === '@opentelemetry/instrumentation-fs' + ).length, + 17 + ); + t.ok(spans.every((s) => s.kind === 'SPAN_KIND_INTERNAL')); + }, + }, +]; + +test('fs instrumentation', (suite) => { + runTestFixtures(suite, testFixtures); + suite.end(); +}); diff --git a/packages/opentelemetry-node/types/instrumentations.d.ts b/packages/opentelemetry-node/types/instrumentations.d.ts index 39c19247..64449b9a 100644 --- a/packages/opentelemetry-node/types/instrumentations.d.ts +++ b/packages/opentelemetry-node/types/instrumentations.d.ts @@ -12,6 +12,7 @@ export type InstrumentaionsMap = { "@opentelemetry/instrumentation-dns": import('@opentelemetry/instrumentation-dns').DnsInstrumentationConfig | InstrumentationFactory; "@opentelemetry/instrumentation-express": import('@opentelemetry/instrumentation-express').ExpressInstrumentationConfig | InstrumentationFactory; "@opentelemetry/instrumentation-fastify": import('@opentelemetry/instrumentation-fastify').FastifyInstrumentationConfig | InstrumentationFactory; + "@opentelemetry/instrumentation-fs": import('@opentelemetry/instrumentation-fs').FsInstrumentationConfig | InstrumentationFactory; "@opentelemetry/instrumentation-generic-pool": import('@opentelemetry/instrumentation').InstrumentationConfig | InstrumentationFactory; "@opentelemetry/instrumentation-graphql": import('@opentelemetry/instrumentation-graphql').GraphQLInstrumentation | InstrumentationFactory; "@opentelemetry/instrumentation-grpc": import('@opentelemetry/instrumentation-grpc').GrpcInstrumentationConfig | InstrumentationFactory;