Skip to content

Commit 5909ad4

Browse files
authored
feat(instrumentation-dataloader): Enhance dataloader instrumentation. (#2449)
1 parent 85f6398 commit 5909ad4

File tree

2 files changed

+425
-32
lines changed

2 files changed

+425
-32
lines changed

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

Lines changed: 120 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ const MODULE_NAME = 'dataloader';
3636
type DataloaderInternal = typeof Dataloader.prototype & {
3737
_batchLoadFn: Dataloader.BatchLoadFn<unknown, unknown>;
3838
_batch: { spanLinks?: Link[] } | null;
39-
40-
// TODO: Remove this once types on Dataloader get fixed https://github.com/graphql/dataloader/pull/334
41-
name?: string | null;
4239
};
4340

4441
type LoadFn = (typeof Dataloader.prototype)['load'];
4542
type LoadManyFn = (typeof Dataloader.prototype)['loadMany'];
43+
type PrimeFn = (typeof Dataloader.prototype)['prime'];
44+
type ClearFn = (typeof Dataloader.prototype)['clear'];
45+
type ClearAllFn = (typeof Dataloader.prototype)['clearAll'];
4646

4747
export class DataloaderInstrumentation extends InstrumentationBase<DataloaderInstrumentationConfig> {
4848
constructor(config: DataloaderInstrumentationConfig = {}) {
@@ -57,17 +57,18 @@ export class DataloaderInstrumentation extends InstrumentationBase<DataloaderIns
5757
dataloader => {
5858
this._patchLoad(dataloader.prototype);
5959
this._patchLoadMany(dataloader.prototype);
60+
this._patchPrime(dataloader.prototype);
61+
this._patchClear(dataloader.prototype);
62+
this._patchClearAll(dataloader.prototype);
6063

6164
return this._getPatchedConstructor(dataloader);
6265
},
6366
dataloader => {
64-
if (isWrapped(dataloader.prototype.load)) {
65-
this._unwrap(dataloader.prototype, 'load');
66-
}
67-
68-
if (isWrapped(dataloader.prototype.loadMany)) {
69-
this._unwrap(dataloader.prototype, 'loadMany');
70-
}
67+
['load', 'loadMany', 'prime', 'clear', 'clearAll'].forEach(method => {
68+
if (isWrapped(dataloader.prototype[method])) {
69+
this._unwrap(dataloader.prototype, method);
70+
}
71+
});
7172
}
7273
) as InstrumentationNodeModuleDefinition,
7374
];
@@ -81,7 +82,7 @@ export class DataloaderInstrumentation extends InstrumentationBase<DataloaderIns
8182

8283
private getSpanName(
8384
dataloader: DataloaderInternal,
84-
operation: 'load' | 'loadMany' | 'batch'
85+
operation: 'load' | 'loadMany' | 'batch' | 'prime' | 'clear' | 'clearAll'
8586
): string {
8687
const dataloaderName = dataloader.name;
8788
if (dataloaderName === undefined || dataloaderName === null) {
@@ -249,4 +250,112 @@ export class DataloaderInstrumentation extends InstrumentationBase<DataloaderIns
249250
});
250251
};
251252
}
253+
254+
private _patchPrime(proto: typeof Dataloader.prototype) {
255+
if (isWrapped(proto.prime)) {
256+
this._unwrap(proto, 'prime');
257+
}
258+
259+
this._wrap(proto, 'prime', this._getPatchedPrime.bind(this));
260+
}
261+
262+
private _getPatchedPrime(original: PrimeFn): PrimeFn {
263+
const instrumentation = this;
264+
265+
return function patchedPrime(
266+
this: DataloaderInternal,
267+
...args: Parameters<typeof original>
268+
) {
269+
if (!instrumentation.shouldCreateSpans()) {
270+
return original.call(this, ...args);
271+
}
272+
273+
const parent = context.active();
274+
const span = instrumentation.tracer.startSpan(
275+
instrumentation.getSpanName(this, 'prime'),
276+
{ kind: SpanKind.CLIENT },
277+
parent
278+
);
279+
280+
const ret = context.with(trace.setSpan(parent, span), () => {
281+
return original.call(this, ...args);
282+
});
283+
284+
span.end();
285+
286+
return ret;
287+
};
288+
}
289+
290+
private _patchClear(proto: typeof Dataloader.prototype) {
291+
if (isWrapped(proto.clear)) {
292+
this._unwrap(proto, 'clear');
293+
}
294+
295+
this._wrap(proto, 'clear', this._getPatchedClear.bind(this));
296+
}
297+
298+
private _getPatchedClear(original: ClearFn): ClearFn {
299+
const instrumentation = this;
300+
301+
return function patchedClear(
302+
this: DataloaderInternal,
303+
...args: Parameters<typeof original>
304+
) {
305+
if (!instrumentation.shouldCreateSpans()) {
306+
return original.call(this, ...args);
307+
}
308+
309+
const parent = context.active();
310+
const span = instrumentation.tracer.startSpan(
311+
instrumentation.getSpanName(this, 'clear'),
312+
{ kind: SpanKind.CLIENT },
313+
parent
314+
);
315+
316+
const ret = context.with(trace.setSpan(parent, span), () => {
317+
return original.call(this, ...args);
318+
});
319+
320+
span.end();
321+
322+
return ret;
323+
};
324+
}
325+
326+
private _patchClearAll(proto: typeof Dataloader.prototype) {
327+
if (isWrapped(proto.clearAll)) {
328+
this._unwrap(proto, 'clearAll');
329+
}
330+
331+
this._wrap(proto, 'clearAll', this._getPatchedClearAll.bind(this));
332+
}
333+
334+
private _getPatchedClearAll(original: ClearAllFn): ClearAllFn {
335+
const instrumentation = this;
336+
337+
return function patchedClearAll(
338+
this: DataloaderInternal,
339+
...args: Parameters<typeof original>
340+
) {
341+
if (!instrumentation.shouldCreateSpans()) {
342+
return original.call(this, ...args);
343+
}
344+
345+
const parent = context.active();
346+
const span = instrumentation.tracer.startSpan(
347+
instrumentation.getSpanName(this, 'clearAll'),
348+
{ kind: SpanKind.CLIENT },
349+
parent
350+
);
351+
352+
const ret = context.with(trace.setSpan(parent, span), () => {
353+
return original.call(this, ...args);
354+
});
355+
356+
span.end();
357+
358+
return ret;
359+
};
360+
}
252361
}

0 commit comments

Comments
 (0)