From c9fdd1a900453f273e757f24336a96152dd8571a Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 7 Feb 2025 10:50:25 -0800 Subject: [PATCH 1/8] fix(instrumentation-pino): log-sending was losing records when the level was reduced (#2699) Before this fix, if a Pino logger level was reduced (e.g. from 'info' to 'debug'), then log.debug('msg') would *not* work. The same thing would happen if a child logger was created at a lower-level than its parent. This issue was that PinoInstrumentation is internally using a pino multistream (https://getpino.io/#/docs/api?id=pino-multistream) and statically setting the level of those streams to the current Logger level. If the logger level was set lower, the multistream levels would end up filtering records at that original higher level. The fix is to set the stream levels to 0 to never filter out records. Closes: https://github.com/open-telemetry/opentelemetry-js-contrib/issues/2696 --- .../src/instrumentation.ts | 5 ++- .../test/pino.test.ts | 43 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-pino/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-pino/src/instrumentation.ts index ef16fdda40..064635e52d 100644 --- a/plugins/node/opentelemetry-instrumentation-pino/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-pino/src/instrumentation.ts @@ -109,8 +109,9 @@ export class PinoInstrumentation extends InstrumentationBase { }); }); + it('emits log records to a lower level after level change', () => { + const logRecords = memExporter.getFinishedLogRecords(); + + logger.debug('first msg at debug'); + logger.trace('first msg at trace'); // Should *not* see this. + + logger.level = 'trace'; + logger.debug('second msg at debug'); + logger.trace('second msg at trace'); // *Should* see this. + + assert.strictEqual(logRecords.length, 3); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.DEBUG); + assert.strictEqual(logRecords[0].severityText, 'debug'); + assert.strictEqual(logRecords[0].body, 'first msg at debug'); + assert.strictEqual(logRecords[1].severityNumber, SeverityNumber.DEBUG); + assert.strictEqual(logRecords[1].severityText, 'debug'); + assert.strictEqual(logRecords[1].body, 'second msg at debug'); + assert.strictEqual(logRecords[2].severityNumber, SeverityNumber.TRACE); + assert.strictEqual(logRecords[2].severityText, 'trace'); + assert.strictEqual(logRecords[2].body, 'second msg at trace'); + }); + + it('emits log records from child logger at lower level', () => { + const logRecords = memExporter.getFinishedLogRecords(); + + const child = logger.child({ childField: 42 }, { level: 'trace' }); + + logger.debug('logger at debug level'); + logger.trace('logger at trace level'); // Should *not* see this one. + child.debug('child at debug level'); + child.trace('child at trace level'); // *Should* see this one. + assert.strictEqual(logRecords.length, 3); + assert.strictEqual(logRecords[0].severityNumber, SeverityNumber.DEBUG); + assert.strictEqual(logRecords[0].severityText, 'debug'); + assert.strictEqual(logRecords[0].body, 'logger at debug level'); + assert.strictEqual(logRecords[1].severityNumber, SeverityNumber.DEBUG); + assert.strictEqual(logRecords[1].severityText, 'debug'); + assert.strictEqual(logRecords[1].body, 'child at debug level'); + assert.strictEqual(logRecords[2].severityNumber, SeverityNumber.TRACE); + assert.strictEqual(logRecords[2].severityText, 'trace'); + assert.strictEqual(logRecords[2].body, 'child at trace level'); + }); + it('does not emit to the Logs SDK if disableLogSending=true', () => { instrumentation.setConfig({ disableLogSending: true }); From ce62d8cb01c549b4eb9394750bdb9a6a1f67de04 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Fri, 7 Feb 2025 16:55:57 -0800 Subject: [PATCH 2/8] docs: minor update for the newer javascript-contrib-triagers teams (#2697) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3c941f87c..eb11d35057 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -238,7 +238,7 @@ features for unmaintained components. At least one sponsor is needed to lift the adding the requested feature. Sponsors are expected to provide reviews for that feature and be responsive on the issue. Components marked as unmaintained still receive semantic conventions updates and bugfixes where possible. -[@open-telemetry/javascript-triagers](https://github.com/orgs/open-telemetry/teams/javascript-triagers) may add the +[@open-telemetry/javascript-contrib-triagers](https://github.com/orgs/open-telemetry/teams/javascript-contrib-triagers) may add the `type:semconv-update` or `bug` label to mark them as exempt from being auto-closed within two weeks. A component which is unmaintained may be deprecated if there is a problem that is not fixed in a timely manner. From c28ae7206953fae1aced9782e660bc9e5bd4363d Mon Sep 17 00:00:00 2001 From: Jaryk Date: Sun, 9 Feb 2025 15:12:42 +0100 Subject: [PATCH 3/8] test(cucumber): join all paths with path module (#2694) Co-authored-by: Amir Blum --- .../test/cucumber.test.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/plugins/node/instrumentation-cucumber/test/cucumber.test.ts b/plugins/node/instrumentation-cucumber/test/cucumber.test.ts index 2ffdcae627..f237c10b14 100644 --- a/plugins/node/instrumentation-cucumber/test/cucumber.test.ts +++ b/plugins/node/instrumentation-cucumber/test/cucumber.test.ts @@ -84,15 +84,14 @@ describe('CucumberInstrumentation', () => { providedConfiguration?: Partial ) => { // clean-up require cache to re-register cucumber hooks for a new run - ['features/support/world', 'features/step_definitions/steps'].forEach( - search => { - const key = Object.keys(require.cache).find(key => - key.includes(search) - ); - if (key == null) return; - delete require.cache[key]; - } - ); + [ + path.join('features', 'support', 'world'), + path.join('features', 'step_definitions', 'steps'), + ].forEach(search => { + const key = Object.keys(require.cache).find(key => key.includes(search)); + if (key == null) return; + delete require.cache[key]; + }); const featurePath = path.join(__dirname, 'current.feature'); await fs.promises.writeFile(featurePath, feature, 'utf-8'); const { runConfiguration } = await loadConfiguration({ @@ -100,8 +99,8 @@ describe('CucumberInstrumentation', () => { ...providedConfiguration, paths: [featurePath], require: [ - path.join(__dirname, 'features/support/world.ts'), - path.join(__dirname, 'features/step_definitions/steps.ts'), + path.join(__dirname, 'features', 'support', 'world.ts'), + path.join(__dirname, 'features', 'step_definitions', 'steps.ts'), ], }, }); @@ -170,7 +169,7 @@ describe('CucumberInstrumentation', () => { assert(parent, 'Expected a parent span'); assert.deepEqual(parent.attributes, { - [SEMATTRS_CODE_FILEPATH]: 'test/current.feature', + [SEMATTRS_CODE_FILEPATH]: path.join('test', 'current.feature'), [SEMATTRS_CODE_LINENO]: 7, [SEMATTRS_CODE_FUNCTION]: 'Button pushing', [SEMATTRS_CODE_NAMESPACE]: 'Basic', From 92106ffd189ecb6f25727a67e719ea5a72e2942f Mon Sep 17 00:00:00 2001 From: bokuweb Date: Sun, 9 Feb 2025 23:24:00 +0900 Subject: [PATCH 4/8] chore: Update README.md (#2695) Co-authored-by: Amir Blum --- .../opentelemetry-instrumentation-user-interaction/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/web/opentelemetry-instrumentation-user-interaction/README.md b/plugins/web/opentelemetry-instrumentation-user-interaction/README.md index 05f76a002b..404ac57382 100644 --- a/plugins/web/opentelemetry-instrumentation-user-interaction/README.md +++ b/plugins/web/opentelemetry-instrumentation-user-interaction/README.md @@ -108,7 +108,7 @@ registerInstrumentations({ ### Prevent spans from recording ```js -import { UserInteractionInstrumentation } from '@opentelemetryinstrumentation-user-interaction'; +import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; @@ -130,7 +130,7 @@ registerInstrumentations({ To attach extra attributes to user interaction spans, provide a callback function to the `shouldPreventSpanCreation` option: ```js -import { UserInteractionInstrumentation } from '@opentelemetryinstrumentation-user-interaction'; +import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; // ...general opentelemetry configuration From bc349a2b7d1ce3caf29fabe77fb91d8456ead172 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Mon, 10 Feb 2025 20:45:57 +0000 Subject: [PATCH 5/8] test(instrumentation-mongodb): Include all versions in coverage (#2681) --- .../package.json | 13 ++++++++----- .../test/mongodb-v3.test.ts | 12 ++++++++---- .../test/mongodb-v4.test.ts | 9 +++++++-- .../test/mongodb-v5-v6.test.ts | 5 +++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/package.json b/plugins/node/opentelemetry-instrumentation-mongodb/package.json index 0b1eee1b62..69e921d121 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/package.json +++ b/plugins/node/opentelemetry-instrumentation-mongodb/package.json @@ -7,12 +7,15 @@ "repository": "open-telemetry/opentelemetry-js-contrib", "scripts": { "docker:start": "docker run -e MONGODB_DB=opentelemetry-tests -e MONGODB_PORT=27017 -e MONGODB_HOST=127.0.0.1 -p 27017:27017 --rm mongo", - "test": "npm run test-v5-v6", - "test-v3": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/**/mongodb-v3.test.ts'", - "test-v4": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v4.test.ts'", - "test-v5-v6": "nyc mocha --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v5-v6.test.ts'", + "test": "npm run test-v3 && npm run test-v4 && npm run test-v5-v6 && nyc merge .nyc_output ./coverage/coverage-final.json", + "test-v3": "tav mongodb 3.7.4 npm run test-v3-run", + "test-v4": "tav mongodb 4.17.0 npm run test-v4-run", + "test-v5-v6": "npm run test-v5-v6-run", + "test-v3-run": "nyc --no-clean mocha --require '@opentelemetry/contrib-test-utils' 'test/**/mongodb-v3.test.ts'", + "test-v4-run": "nyc --no-clean mocha --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v4.test.ts'", + "test-v5-v6-run": "nyc --no-clean mocha --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v5-v6.test.ts'", "test-all-versions": "tav", - "tdd": "npm run test -- --watch-extensions ts --watch", + "tdd": "npm run test-v5-v6-run -- --watch-extensions ts --watch", "clean": "rimraf build/*", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v3.test.ts b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v3.test.ts index 4a3bd9a6e0..d1163315fc 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v3.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v3.test.ts @@ -39,6 +39,9 @@ import { SEMATTRS_NET_PEER_PORT, } from '@opentelemetry/semantic-conventions'; +// We can't use @ts-expect-error because it will fail depending on the used mongodb version on tests +/* eslint-disable @typescript-eslint/ban-ts-comment */ + describe('MongoDBInstrumentation-Tracing-v3', () => { function create(config: MongoDBInstrumentationConfig = {}) { instrumentation.setConfig(config); @@ -85,7 +88,7 @@ describe('MongoDBInstrumentation-Tracing-v3', () => { } // Non traced insertion of basic data to perform tests const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; - // @ts-expect-error -- v5 removed callback support + // @ts-ignore -- v5 removed callback support collection.insertMany(insertData, (err: any, result: any) => { resetMemoryExporter(); done(); @@ -94,7 +97,7 @@ describe('MongoDBInstrumentation-Tracing-v3', () => { afterEach(done => { if (shouldTest) { - // @ts-expect-error -- v5 removed callback support + // @ts-ignore -- v5 removed callback support collection.deleteMany({}, done); } else { done(); @@ -619,7 +622,6 @@ describe('MongoDBInstrumentation-Tracing-v3', () => { let collection: Collection; before(done => { accessCollection(URL, DB_NAME, COLLECTION_NAME, { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore useUnifiedTopology: true, }) @@ -642,7 +644,7 @@ describe('MongoDBInstrumentation-Tracing-v3', () => { it('should generate correct span attributes', done => { const span = trace.getTracer('default').startSpan('findRootSpan'); context.with(trace.setSpan(context.active(), span), () => { - // @ts-expect-error -- v5 removed callback support + // @ts-ignore -- v5 removed callback support collection.find({ a: 1 }).toArray((err, results) => { span.end(); const [mongoSpan] = getTestSpans(); @@ -723,3 +725,5 @@ describe('MongoDBInstrumentation-Tracing-v3', () => { }); }); }); + +/* eslint-enable @typescript-eslint/ban-ts-comment */ diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts index febd901776..e73a4fcf45 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts @@ -37,6 +37,9 @@ import type { MongoClient, Collection } from 'mongodb'; import { assertSpans, accessCollection, DEFAULT_MONGO_HOST } from './utils'; import { SEMATTRS_DB_STATEMENT } from '@opentelemetry/semantic-conventions'; +// We can't use @ts-expect-error because it will fail depending on the used mongodb version on tests +/* eslint-disable @typescript-eslint/ban-ts-comment */ + describe('MongoDBInstrumentation-Tracing-v4', () => { function create(config: MongoDBInstrumentationConfig = {}) { instrumentation.setConfig(config); @@ -82,7 +85,7 @@ describe('MongoDBInstrumentation-Tracing-v4', () => { } // Non traced insertion of basic data to perform tests const insertData = [{ a: 1 }, { a: 2 }, { a: 3 }]; - // @ts-expect-error -- v5 removed callback support + // @ts-ignore -- v5 removed callback support collection.insertMany(insertData, (err: any, result: any) => { resetMemoryExporter(); done(); @@ -91,7 +94,7 @@ describe('MongoDBInstrumentation-Tracing-v4', () => { afterEach(done => { if (shouldTest) { - // @ts-expect-error -- v5 removed callback support + // @ts-ignore -- v5 removed callback support collection.deleteMany({}, done); } else { done(); @@ -693,3 +696,5 @@ describe('MongoDBInstrumentation-Tracing-v4', () => { }); }); }); + +/* eslint-enable @typescript-eslint/ban-ts-comment */ diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts index debe84dbdc..eeeae5b24a 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts @@ -46,6 +46,9 @@ import type { MongoClient, Collection } from 'mongodb'; import { assertSpans, accessCollection, DEFAULT_MONGO_HOST } from './utils'; import { SEMATTRS_DB_STATEMENT } from '@opentelemetry/semantic-conventions'; +// We can't use @ts-expect-error because it will fail depending on the used mongodb version on tests +/* eslint-disable @typescript-eslint/ban-ts-comment */ + describe('MongoDBInstrumentation-Tracing-v5', () => { function create(config: MongoDBInstrumentationConfig = {}) { instrumentation.setConfig(config); @@ -706,3 +709,5 @@ describe('MongoDBInstrumentation-Tracing-v5', () => { }); }); }); + +/* eslint-enable @typescript-eslint/ban-ts-comment */ From 2989b94515ca6f62b628f63eeb881f4b91e391af Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Tue, 11 Feb 2025 08:59:47 +0000 Subject: [PATCH 6/8] feat(instrumentation-mongodb): Add `requireParentSpan` config option. (#2658) --- .../README.md | 1 + .../src/instrumentation.ts | 58 ++++++++++++++----- .../src/types.ts | 5 ++ .../test/mongodb-v3.test.ts | 43 ++++++++++++++ .../test/mongodb-v4.test.ts | 43 ++++++++++++++ .../test/mongodb-v5-v6.test.ts | 43 ++++++++++++++ 6 files changed, 180 insertions(+), 13 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/README.md b/plugins/node/opentelemetry-instrumentation-mongodb/README.md index ca43f4e3bd..2aba6a5bd6 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/README.md +++ b/plugins/node/opentelemetry-instrumentation-mongodb/README.md @@ -54,6 +54,7 @@ Mongodb instrumentation has few options available to choose from. You can set th | [`enhancedDatabaseReporting`](./src/types.ts#L32) | `string` | If true, additional information about query parameters and results will be attached (as `attributes`) to spans representing database operations | | `responseHook` | `MongoDBInstrumentationExecutionResponseHook` (function) | Function for adding custom attributes from db response | | `dbStatementSerializer` | `DbStatementSerializer` (function) | Custom serializer function for the db.statement tag | +| `requireParentSpan` | `boolean` | Require a parent span in order to create mongodb spans, default when unset is `true` | ## Semantic Conventions diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts index caaff5c550..b627a3d0be 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts @@ -55,13 +55,21 @@ import { V4Connect, V4Session } from './internal-types'; import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; import { UpDownCounter } from '@opentelemetry/api'; +const DEFAULT_CONFIG: MongoDBInstrumentationConfig = { + requireParentSpan: true, +}; + /** mongodb instrumentation plugin for OpenTelemetry */ export class MongoDBInstrumentation extends InstrumentationBase { private _connectionsUsage!: UpDownCounter; private _poolName!: string; constructor(config: MongoDBInstrumentationConfig = {}) { - super(PACKAGE_NAME, PACKAGE_VERSION, config); + super(PACKAGE_NAME, PACKAGE_VERSION, { ...DEFAULT_CONFIG, ...config }); + } + + override setConfig(config: MongoDBInstrumentationConfig = {}) { + super.setConfig({ ...DEFAULT_CONFIG, ...config }); } override _updateMetricInstruments() { @@ -438,10 +446,13 @@ export class MongoDBInstrumentation extends InstrumentationBase undefined; @@ -589,7 +606,7 @@ export class MongoDBInstrumentation extends InstrumentationBase { }); }); + describe('requireParentSpan', () => { + // Resetting the behavior to default to avoid flakes in other tests + beforeEach(() => { + instrumentation.setConfig(); + }); + + afterEach(() => { + instrumentation.setConfig(); + }); + + it('should not create spans without parent span when requireParentSpan is explicitly set to true', done => { + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 0); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + + it('should create spans without parent span when requireParentSpan is false', done => { + instrumentation.setConfig({ + requireParentSpan: false, + }); + + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 1); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + }); + /** Should intercept command */ describe('Removing Instrumentation', () => { it('should unpatch plugin', () => { diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts index e73a4fcf45..891fc78969 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts @@ -642,6 +642,49 @@ describe('MongoDBInstrumentation-Tracing-v4', () => { }); }); + describe('requireParentSpan', () => { + // Resetting the behavior to default to avoid flakes in other tests + beforeEach(() => { + instrumentation.setConfig(); + }); + + afterEach(() => { + instrumentation.setConfig(); + }); + + it('should not create spans without parent span when requireParentSpan is explicitly set to true', done => { + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 0); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + + it('should create spans without parent span when requireParentSpan is false', done => { + instrumentation.setConfig({ + requireParentSpan: false, + }); + + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 1); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + }); + /** Should intercept command */ describe('Removing Instrumentation', () => { it('should unpatch plugin', () => { diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts index eeeae5b24a..cd12910c58 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v5-v6.test.ts @@ -655,6 +655,49 @@ describe('MongoDBInstrumentation-Tracing-v5', () => { }); }); + describe('requireParentSpan', () => { + // Resetting the behavior to default to avoid flakes in other tests + beforeEach(() => { + instrumentation.setConfig(); + }); + + afterEach(() => { + instrumentation.setConfig(); + }); + + it('should not create spans without parent span when requireParentSpan is explicitly set to true', done => { + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 0); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + + it('should create spans without parent span when requireParentSpan is false', done => { + instrumentation.setConfig({ + requireParentSpan: false, + }); + + context.with(trace.deleteSpan(context.active()), () => { + collection + .insertOne({ a: 1 }) + .then(() => { + assert.strictEqual(getTestSpans().length, 1); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + }); + /** Should intercept command */ describe('Removing Instrumentation', () => { it('should unpatch plugin', () => { From 58bc158f6544a50fca5ad7e90159ac357158d29f Mon Sep 17 00:00:00 2001 From: Marc Pichler Date: Tue, 11 Feb 2025 11:53:30 +0100 Subject: [PATCH 7/8] refactor: use isWrapped from instrumentation package (#2704) --- .../test/userInteraction.nozone.test.ts | 6 ++++-- .../src/BaseOpenTelemetryComponent.ts | 2 +- .../test/BaseOpenTelemetryComponent.test.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/web/opentelemetry-instrumentation-user-interaction/test/userInteraction.nozone.test.ts b/plugins/web/opentelemetry-instrumentation-user-interaction/test/userInteraction.nozone.test.ts index f1d4231329..69c566a48c 100644 --- a/plugins/web/opentelemetry-instrumentation-user-interaction/test/userInteraction.nozone.test.ts +++ b/plugins/web/opentelemetry-instrumentation-user-interaction/test/userInteraction.nozone.test.ts @@ -16,8 +16,10 @@ const originalSetTimeout = window.setTimeout; import { trace } from '@opentelemetry/api'; -import { isWrapped } from '@opentelemetry/core'; -import { registerInstrumentations } from '@opentelemetry/instrumentation'; +import { + registerInstrumentations, + isWrapped, +} from '@opentelemetry/instrumentation'; import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request'; import * as tracing from '@opentelemetry/sdk-trace-base'; import { WebTracerProvider } from '@opentelemetry/sdk-trace-web'; diff --git a/plugins/web/opentelemetry-plugin-react-load/src/BaseOpenTelemetryComponent.ts b/plugins/web/opentelemetry-plugin-react-load/src/BaseOpenTelemetryComponent.ts index b3b7c9d926..2c5a5c9ba7 100644 --- a/plugins/web/opentelemetry-plugin-react-load/src/BaseOpenTelemetryComponent.ts +++ b/plugins/web/opentelemetry-plugin-react-load/src/BaseOpenTelemetryComponent.ts @@ -15,7 +15,7 @@ */ import * as api from '@opentelemetry/api'; -import { isWrapped } from '@opentelemetry/core'; +import { isWrapped } from '@opentelemetry/instrumentation'; import * as shimmer from 'shimmer'; import { AttributeNames } from './enums/AttributeNames'; import * as React from 'react'; diff --git a/plugins/web/opentelemetry-plugin-react-load/test/BaseOpenTelemetryComponent.test.ts b/plugins/web/opentelemetry-plugin-react-load/test/BaseOpenTelemetryComponent.test.ts index 323044bdc7..133af7749f 100644 --- a/plugins/web/opentelemetry-plugin-react-load/test/BaseOpenTelemetryComponent.test.ts +++ b/plugins/web/opentelemetry-plugin-react-load/test/BaseOpenTelemetryComponent.test.ts @@ -20,7 +20,7 @@ import { propagation, trace, } from '@opentelemetry/api'; -import { isWrapped } from '@opentelemetry/core'; +import { isWrapped } from '@opentelemetry/instrumentation'; import { B3Propagator } from '@opentelemetry/propagator-b3'; import { BasicTracerProvider, From 7a1e8b3fe1f61d1add3ef4af52f94aa823a19f9a Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Tue, 11 Feb 2025 05:05:36 -0800 Subject: [PATCH 8/8] chore: add 'lint:semconv-deps' (#2569) Co-authored-by: Marc Pichler --- package.json | 5 +- scripts/lint-semconv-deps.mjs | 99 +++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100755 scripts/lint-semconv-deps.mjs diff --git a/package.json b/package.json index 09705c8907..792002c80a 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,15 @@ "test:ci:changed": "nx affected -t test --base=origin/main --head=HEAD", "test-all-versions": "nx run-many -t test-all-versions", "changelog": "lerna-changelog", - "lint": "nx run-many -t lint && npm run lint:readme && npm run lint:markdown", + "lint": "nx run-many -t lint && npm run lint:readme && npm run lint:markdown && npm run lint:semconv-deps", "lint:fix": "nx run-many -t lint:fix && npm run lint:markdown:fix", "lint:deps": "npx --yes knip@5.33.3 --dependencies --production --tags=-knipignore", "lint:examples": "eslint ./examples/**/*.js", "lint:examples:fix": "eslint ./examples/**/*.js --fix", "lint:markdown": "markdownlint-cli2 $(git ls-files '*.md')", "lint:markdown:fix": "markdownlint-cli2 --fix $(git ls-files '*.md')", - "lint:readme": "nx run-many -t lint:readme" + "lint:readme": "nx run-many -t lint:readme", + "lint:semconv-deps": "./scripts/lint-semconv-deps.mjs" }, "keywords": [ "opentelemetry", diff --git a/scripts/lint-semconv-deps.mjs b/scripts/lint-semconv-deps.mjs new file mode 100755 index 0000000000..eddf2345a9 --- /dev/null +++ b/scripts/lint-semconv-deps.mjs @@ -0,0 +1,99 @@ +#!/usr/bin/env node +/* + * 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. + */ + +/** + * Lint the usage of `@opentelemetry/semantic-conventions` in packages in + * the workspace. + * + * See "Rule:" comments for things that are checked. + * + * Usage: + * node scripts/lint-semconv-deps.js + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { globSync } from 'glob'; + +const TOP = path.resolve(fileURLToPath(new URL('.', import.meta.url)), '..'); +const SEMCONV = '@opentelemetry/semantic-conventions'; +const USE_COLOR = process.stdout.isTTY && !process.env.NO_COLOR?.length > 0; + +let numProbs = 0; +function problem(...args) { + numProbs += 1; + if (USE_COLOR) { + process.stdout.write('\x1b[31m'); + } + args.unshift('lint-semconv-deps error:'); + console.log(...args); + if (USE_COLOR) { + process.stdout.write('\x1b[39m'); + } +} + +function getAllWorkspaceDirs() { + const pj = JSON.parse( + fs.readFileSync(path.join(TOP, 'package.json'), 'utf8') + ); + return pj.workspaces + .map((wsGlob) => globSync(path.join(wsGlob, 'package.json'))) + .flat() + .map(path.dirname); +} + +function lintSemconvDeps() { + const wsDirs = getAllWorkspaceDirs(); + + for (let wsDir of wsDirs) { + const pj = JSON.parse( + fs.readFileSync(path.join(wsDir, 'package.json'), 'utf8') + ); + const depRange = pj?.dependencies?.[SEMCONV]; + const devDepRange = pj?.devDependencies?.[SEMCONV]; + if (!(depRange || devDepRange)) { + continue; + } + + // Rule: The semconv dep should *not* be pinned. Expect `^X.Y.Z`. + const pinnedVerRe = /^\d+\.\d+\.\d+$/; + if (depRange && pinnedVerRe.exec(depRange)) { + problem(`${wsDir}/package.json: package ${pj.name} pins "${SEMCONV}" in dependencies, but should not (see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#why-not-pin-the-version)`); + } else if (devDepRange && pinnedVerRe.exec(devDepRange)) { + problem(`${wsDir}/package.json: package ${pj.name} pins "${SEMCONV}" in devDependencies, but should not (see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#why-not-pin-the-version)`); + } + + // Rule: The incubating entry-point should not be used. + const srcFiles = globSync(path.join(wsDir, 'src', '**', '*.ts')); + const usesIncubatingRe = /import\s+\{?[^{;]*\s+from\s+'@opentelemetry\/semantic-conventions\/incubating'/s; + for (let srcFile of srcFiles) { + const srcText = fs.readFileSync(srcFile, 'utf8'); + const match = usesIncubatingRe.exec(srcText); + if (match) { + problem(`${srcFile}: uses the 'incubating' entry-point from '@opentelemetry/semantic-conventions', but should not (see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv)`) + } + } + } +} + +// mainline +await lintSemconvDeps(); +if (numProbs > 0) { + process.exitCode = 1; +} +