diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts b/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts index caaff5c550..4820915575 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts @@ -55,6 +55,25 @@ import { V4Connect, V4Session } from './internal-types'; import { PACKAGE_NAME, PACKAGE_VERSION } from './version'; import { UpDownCounter } from '@opentelemetry/api'; +// Skipping mongoose-added `non-enumerable` properties +// https://github.com/Automattic/mongoose/blob/b34aba65bd64540e330665477f542eb79c877909/lib/helpers/document/compile.js#L217C11-L228C6 +// These properties are added by mongoose and supposed to be non-enumerable +// but they are enumerable in some versions of mongoose. +// These properties have made non-enumerable from mongoose@5.13.14 +// https://github.com/Automattic/mongoose/commit/62b7b9c07ad3c763d5e42714ee149c28412db79e +const KEYS_TO_SKIP_SCRUBBING = [ + 'isNew', + '$__', + '$errors', + 'errors', + '_doc', + '$locals', + '$op', + '__parentArray', + '__index', + '$isDocumentArrayElement', +]; + /** mongodb instrumentation plugin for OpenTelemetry */ export class MongoDBInstrumentation extends InstrumentationBase { private _connectionsUsage!: UpDownCounter; @@ -932,17 +951,29 @@ export class MongoDBInstrumentation extends InstrumentationBase= 10) { + return 'Max Depth'; + } + + if (value instanceof Uint8Array || value instanceof Buffer) { + return 'Binary Data'; + } + if (Array.isArray(value)) { - return value.map(element => this._scrubStatement(element)); + return value.map(element => this._scrubStatement(element, depth + 1)); } if (typeof value === 'object' && value !== null) { return Object.fromEntries( - Object.entries(value).map(([key, element]) => [ - key, - this._scrubStatement(element), - ]) + Object.entries(value) + .filter(([key]) => { + return !KEYS_TO_SKIP_SCRUBBING.includes(key); + }) + .map(([key, element]) => [ + key, + this._scrubStatement(element, depth + 1), + ]) ); } 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..dd0eaf6755 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 @@ -415,6 +415,81 @@ describe('MongoDBInstrumentation-Tracing-v5', () => { }); }); }); + + it('should skip `Buffer` and `Uint8Array` values', done => { + const buffer = Buffer.from('buffer'); + const uint8Array = new Uint8Array([1, 2, 3, 4]); + const span = trace.getTracer('default').startSpan('insertRootSpan'); + context.with(trace.setSpan(context.active(), span), () => { + collection + .insertOne({ buffer, uint8Array }) + .then(() => { + span.end(); + const spans = getTestSpans(); + const operationName = 'mongodb.insert'; + assertSpans( + spans, + operationName, + SpanKind.CLIENT, + 'insert', + URL, + false, + false + ); + const mongoSpan = spans.find(s => s.name === operationName); + const dbStatement = JSON.parse( + mongoSpan!.attributes[SEMATTRS_DB_STATEMENT] as string + ); + assert.strictEqual(dbStatement.buffer, 'Binary Data'); + assert.strictEqual(dbStatement.uint8Array, 'Binary Data'); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); + + it('should skip nested levels of objects over the limit of 10', done => { + const deeplyNestedObject = { + a: { + b: { c: { d: { e: { f: { g: { h: { i: { j: { k: 1 } } } } } } } } }, + }, + }; + + const span = trace.getTracer('default').startSpan('insertRootSpan'); + context.with(trace.setSpan(context.active(), span), () => { + collection + .insertOne({ deeplyNestedObject }) + .then(() => { + span.end(); + const spans = getTestSpans(); + const operationName = 'mongodb.insert'; + assertSpans( + spans, + operationName, + SpanKind.CLIENT, + 'insert', + URL, + false, + false + ); + const mongoSpan = spans.find(s => s.name === operationName); + const dbStatement = JSON.parse( + mongoSpan!.attributes[SEMATTRS_DB_STATEMENT] as string + ); + assert.deepStrictEqual(dbStatement.deeplyNestedObject, { + a: { + b: { c: { d: { e: { f: { g: { h: { i: 'Max Depth' } } } } } } }, + }, + }); + done(); + }) + .catch(err => { + done(err); + }); + }); + }); }); describe('when specifying a dbStatementSerializer configuration', () => {