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 febd901776..eec56fe5f4 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/test/mongodb-v4.test.ts @@ -639,6 +639,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 debe84dbdc..33ae1e1e5c 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 @@ -652,6 +652,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', () => {