@@ -36,13 +36,13 @@ const MODULE_NAME = 'dataloader';
3636type 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
4441type LoadFn = ( typeof Dataloader . prototype ) [ 'load' ] ;
4542type 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
4747export 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 ) {
@@ -185,6 +186,13 @@ export class DataloaderInstrumentation extends InstrumentationBase<DataloaderIns
185186 const result = original
186187 . call ( this , ...args )
187188 . then ( value => {
189+ span . setAttribute ( 'cache.key' , [ args [ 0 ] ] ) ;
190+ span . setAttribute ( 'cache.hit' , value !== undefined ) ;
191+ span . setAttribute (
192+ 'cache.item_size' ,
193+ value ? JSON . stringify ( value ) . length : 0
194+ ) ;
195+
188196 span . end ( ) ;
189197 return value ;
190198 } )
@@ -243,10 +251,139 @@ export class DataloaderInstrumentation extends InstrumentationBase<DataloaderIns
243251 // .loadMany never rejects, as errors from internal .load
244252 // calls are caught by dataloader lib
245253 return original . call ( this , ...args ) . then ( value => {
254+ span . setAttribute ( 'cache.key' , Array . from ( args [ 0 ] ) ) ;
255+ span . setAttribute (
256+ 'cache.hit' ,
257+ value . every ( ( v : unknown ) => v !== undefined )
258+ ) ;
259+ span . setAttribute (
260+ 'cache.item_size' ,
261+ value . reduce (
262+ ( acc : number , v : unknown ) => acc + JSON . stringify ( v ) . length ,
263+ 0
264+ )
265+ ) ;
266+
246267 span . end ( ) ;
247268 return value ;
248269 } ) ;
249270 } ) ;
250271 } ;
251272 }
273+
274+ private _patchPrime ( proto : typeof Dataloader . prototype ) {
275+ if ( isWrapped ( proto . prime ) ) {
276+ this . _unwrap ( proto , 'prime' ) ;
277+ }
278+
279+ this . _wrap ( proto , 'prime' , this . _getPatchedPrime . bind ( this ) ) ;
280+ }
281+
282+ private _getPatchedPrime ( original : PrimeFn ) : PrimeFn {
283+ const instrumentation = this ;
284+
285+ return function patchedPrime (
286+ this : DataloaderInternal ,
287+ ...args : Parameters < typeof original >
288+ ) {
289+ if ( ! instrumentation . shouldCreateSpans ( ) ) {
290+ return original . call ( this , ...args ) ;
291+ }
292+
293+ const parent = context . active ( ) ;
294+ const span = instrumentation . tracer . startSpan (
295+ instrumentation . getSpanName ( this , 'prime' ) ,
296+ { kind : SpanKind . CLIENT } ,
297+ parent
298+ ) ;
299+
300+ const ret = context . with ( trace . setSpan ( parent , span ) , ( ) => {
301+ return original . call ( this , ...args ) ;
302+ } ) ;
303+
304+ span . setAttribute ( 'cache.key' , [ args [ 0 ] ] ) ;
305+ span . setAttribute (
306+ 'cache.item_size' ,
307+ args [ 1 ] ? JSON . stringify ( args [ 1 ] ) . length : 0
308+ ) ;
309+
310+ span . end ( ) ;
311+
312+ return ret ;
313+ } ;
314+ }
315+
316+ private _patchClear ( proto : typeof Dataloader . prototype ) {
317+ if ( isWrapped ( proto . clear ) ) {
318+ this . _unwrap ( proto , 'clear' ) ;
319+ }
320+
321+ this . _wrap ( proto , 'clear' , this . _getPatchedClear . bind ( this ) ) ;
322+ }
323+
324+ private _getPatchedClear ( original : ClearFn ) : ClearFn {
325+ const instrumentation = this ;
326+
327+ return function patchedClear (
328+ this : DataloaderInternal ,
329+ ...args : Parameters < typeof original >
330+ ) {
331+ if ( ! instrumentation . shouldCreateSpans ( ) ) {
332+ return original . call ( this , ...args ) ;
333+ }
334+
335+ const parent = context . active ( ) ;
336+ const span = instrumentation . tracer . startSpan (
337+ instrumentation . getSpanName ( this , 'clear' ) ,
338+ { kind : SpanKind . CLIENT } ,
339+ parent
340+ ) ;
341+
342+ const ret = context . with ( trace . setSpan ( parent , span ) , ( ) => {
343+ span . setAttribute ( 'cache.key' , [ args [ 0 ] ] ) ;
344+
345+ return original . call ( this , ...args ) ;
346+ } ) ;
347+
348+ span . end ( ) ;
349+
350+ return ret ;
351+ } ;
352+ }
353+
354+ private _patchClearAll ( proto : typeof Dataloader . prototype ) {
355+ if ( isWrapped ( proto . clearAll ) ) {
356+ this . _unwrap ( proto , 'clearAll' ) ;
357+ }
358+
359+ this . _wrap ( proto , 'clearAll' , this . _getPatchedClearAll . bind ( this ) ) ;
360+ }
361+
362+ private _getPatchedClearAll ( original : ClearAllFn ) : ClearAllFn {
363+ const instrumentation = this ;
364+
365+ return function patchedClearAll (
366+ this : DataloaderInternal ,
367+ ...args : Parameters < typeof original >
368+ ) {
369+ if ( ! instrumentation . shouldCreateSpans ( ) ) {
370+ return original . call ( this , ...args ) ;
371+ }
372+
373+ const parent = context . active ( ) ;
374+ const span = instrumentation . tracer . startSpan (
375+ instrumentation . getSpanName ( this , 'clearAll' ) ,
376+ { kind : SpanKind . CLIENT } ,
377+ parent
378+ ) ;
379+
380+ const ret = context . with ( trace . setSpan ( parent , span ) , ( ) => {
381+ return original . call ( this , ...args ) ;
382+ } ) ;
383+
384+ span . end ( ) ;
385+
386+ return ret ;
387+ } ;
388+ }
252389}
0 commit comments