Skip to content

Commit 96eb7dc

Browse files
ferrelucasblumamir
andauthored
fix(instrumentation-mongoose): Fix instrumentation for Mongoose Model methods, save() and remove(), by passing options argument to original method calls (#2009)
* Fixing Mongoose instrumentation on Model methods with callback + tests * Fixing and adding more tests * Removing skip on existing failing test * Renaming callback index variable * use exported strings for attributes * Defining args as IArguments and updating its values directly * Fix lint issues * Replacing tests with session option to use wtimeout to avoid the need of transactions in the instrumentation test --------- Co-authored-by: Amir Blum <[email protected]>
1 parent 20bc736 commit 96eb7dc

File tree

3 files changed

+99
-21
lines changed

3 files changed

+99
-21
lines changed

plugins/node/instrumentation-mongoose/src/mongoose.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ export class MongooseInstrumentation extends InstrumentationBase {
330330
exec,
331331
originalThis,
332332
span,
333+
args,
333334
self._config.responseHook,
334335
moduleVersion
335336
)

plugins/node/instrumentation-mongoose/src/utils.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,23 @@ export function handleCallbackResponse(
9898
exec: Function,
9999
originalThis: any,
100100
span: Span,
101+
args: IArguments,
101102
responseHook?: MongooseResponseCustomAttributesFunction,
102103
moduleVersion: string | undefined = undefined
103104
) {
104-
return exec.apply(originalThis, [
105-
(err: Error, response: any) => {
106-
err
107-
? setErrorStatus(span, err)
108-
: applyResponseHook(span, response, responseHook, moduleVersion);
109-
span.end();
110-
return callback!(err, response);
111-
},
112-
]);
105+
let callbackArgumentIndex = 0;
106+
if (args.length === 2) {
107+
callbackArgumentIndex = 1;
108+
}
109+
110+
args[callbackArgumentIndex] = (err: Error, response: any): any => {
111+
err
112+
? setErrorStatus(span, err)
113+
: applyResponseHook(span, response, responseHook, moduleVersion);
114+
115+
span.end();
116+
return callback!(err, response);
117+
};
118+
119+
return exec.apply(originalThis, args);
113120
}

plugins/node/instrumentation-mongoose/test/mongoose.test.ts

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ describe('mongoose instrumentation', () => {
6666
beforeEach(async () => {
6767
instrumentation.disable();
6868
instrumentation.setConfig({
69-
dbStatementSerializer: (_operation: string, payload) =>
70-
JSON.stringify(payload),
69+
dbStatementSerializer: (_operation: string, payload) => {
70+
return JSON.stringify(payload, (key, value) => {
71+
return key === 'session' ? '[Session]' : value;
72+
});
73+
},
7174
});
7275
instrumentation.enable();
7376
await loadUsers();
@@ -97,23 +100,90 @@ describe('mongoose instrumentation', () => {
97100
expect(statement.document).toEqual(expect.objectContaining(document));
98101
});
99102

100-
it('instrumenting save operation with callback', done => {
101-
const document = {
102-
firstName: 'Test first name',
103-
lastName: 'Test last name',
104-
105-
};
106-
const user: IUser = new User(document);
103+
describe('when save call does not have callback', async () => {
104+
it('instrumenting save operation with option property set', async () => {
105+
const document = {
106+
firstName: 'Test first name',
107+
lastName: 'Test last name',
108+
109+
};
110+
const user: IUser = new User(document);
111+
await user.save({ wtimeout: 42 });
107112

108-
user.save(() => {
109113
const spans = getTestSpans();
110-
111114
expect(spans.length).toBe(1);
112115
assertSpan(spans[0] as ReadableSpan);
113116
expect(spans[0].attributes[SEMATTRS_DB_OPERATION]).toBe('save');
114117
const statement = getStatement(spans[0] as ReadableSpan);
115118
expect(statement.document).toEqual(expect.objectContaining(document));
116-
done();
119+
expect(statement.options.wtimeout).toEqual(42);
120+
121+
const createdUser = await User.findById(user._id).lean();
122+
expect(createdUser?._id.toString()).toEqual(user._id.toString());
123+
});
124+
});
125+
126+
describe('when save call has callback', async () => {
127+
it('instrumenting save operation with promise and option property set', done => {
128+
const document = {
129+
firstName: 'Test first name',
130+
lastName: 'Test last name',
131+
132+
};
133+
const user: IUser = new User(document);
134+
user.save({ wtimeout: 42 }, async () => {
135+
const spans = getTestSpans();
136+
expect(spans.length).toBe(1);
137+
assertSpan(spans[0] as ReadableSpan);
138+
expect(spans[0].attributes[SEMATTRS_DB_OPERATION]).toBe('save');
139+
const statement = getStatement(spans[0] as ReadableSpan);
140+
expect(statement.document).toEqual(expect.objectContaining(document));
141+
expect(statement.options.wtimeout).toEqual(42);
142+
143+
const createdUser = await User.findById(user._id).lean();
144+
expect(createdUser?._id.toString()).toEqual(user._id.toString());
145+
done();
146+
});
147+
});
148+
149+
it('instrumenting save operation with generic options and callback', done => {
150+
const document = {
151+
firstName: 'Test first name',
152+
lastName: 'Test last name',
153+
154+
};
155+
const user: IUser = new User(document);
156+
157+
user.save({}, () => {
158+
const spans = getTestSpans();
159+
160+
expect(spans.length).toBe(1);
161+
assertSpan(spans[0] as ReadableSpan);
162+
expect(spans[0].attributes[SEMATTRS_DB_OPERATION]).toBe('save');
163+
const statement = getStatement(spans[0] as ReadableSpan);
164+
expect(statement.document).toEqual(expect.objectContaining(document));
165+
done();
166+
});
167+
});
168+
169+
it('instrumenting save operation with only callback', done => {
170+
const document = {
171+
firstName: 'Test first name',
172+
lastName: 'Test last name',
173+
174+
};
175+
const user: IUser = new User(document);
176+
177+
user.save(() => {
178+
const spans = getTestSpans();
179+
180+
expect(spans.length).toBe(1);
181+
assertSpan(spans[0] as ReadableSpan);
182+
expect(spans[0].attributes[SEMATTRS_DB_OPERATION]).toBe('save');
183+
const statement = getStatement(spans[0] as ReadableSpan);
184+
expect(statement.document).toEqual(expect.objectContaining(document));
185+
done();
186+
});
117187
});
118188
});
119189

0 commit comments

Comments
 (0)