import { LookupAddress } from 'dns' ; import { diag , Span , SpanKind } from '@opentelemetry/api' ; import { InstrumentationBase , InstrumentationNodeModuleDefinition , isWrapped , safeExecuteInTheMiddle , } from '@opentelemetry/instrumentation' ; import * as semver from 'semver' ; import { AddressFamily } from './enums/AddressFamily' ; import { Dns , DnsInstrumentationConfig , LookupCallbackSignature , LookupPromiseSignature , } from './types' ; import * as utils from './utils' ; import { VERSION } from './version' ; /**
 * Dns instrumentation for Opentelemetry
 */ export class DnsInstrumentation extends InstrumentationBase < Dns > { constructor ( protected override _config = { } ) { super ( '@opentelemetry/instrumentation-dns' , VERSION , _config ) ; } init ( ) { return [ new InstrumentationNodeModuleDefinition < Dns > ( 'dns' , [ '*' ] , moduleExports => { diag . debug ( 'Applying patch for dns' ) ; if ( isWrapped ( moduleExports . lookup ) ) { this . _unwrap ( moduleExports , 'lookup' ) ; } this . _wrap ( moduleExports , 'lookup' , this . _getLookup ( ) as any ) ; if ( semver . gte ( process . version , '10.6.0' ) ) { this . _wrap ( moduleExports . promises , 'lookup' , this . _getLookup ( ) as any ) ; } return moduleExports ; } , moduleExports => { if ( moduleExports === undefined ) return ; diag . debug ( 'Removing patch for dns' ) ; this . _unwrap ( moduleExports , 'lookup' ) ; if ( semver . gte ( process . version , '10.6.0' ) ) { this . _unwrap ( moduleExports . promises , 'lookup' ) ; } } ) , ] ; } /**
     * Get the patched lookup function
     */ private _getLookup ( ) { return ( original ) => { return this . _getPatchLookupFunction ( original ) ; } ; } /**
     * Creates spans for lookup operations, restoring spans' context if applied.
     */ private _getPatchLookupFunction ( original ) { diag . debug ( 'patch lookup function' ) ; const plugin = this ; return function patchedLookup ( this , hostname , ... args ) { if ( utils . isIgnored ( hostname , plugin . _config . ignoreHostnames , ( e ) => diag . error ( 'caught ignoreHostname error: ' , e ) ) ) { return original . apply ( this , [ hostname , ... args ] ) ; } const argsCount = args . length ; diag . debug ( 'wrap lookup callback function and starts span' ) ; const name = utils . getOperationName ( 'lookup' ) ; const span = plugin . tracer . startSpan ( name , { kind : SpanKind . CLIENT , } ) ; const originalCallback = args [ argsCount - 1 ] ; if ( typeof originalCallback === 'function' ) { args [ argsCount - 1 ] = plugin . _wrapLookupCallback ( originalCallback , span ) ; return safeExecuteInTheMiddle ( ( ) => original . apply ( this , [ hostname , ... args ] ) , error => { if ( error != null ) { utils . setError ( error , span , process . version ) ; span . end ( ) ; } } ) ; } else { const promise = safeExecuteInTheMiddle ( ( ) => ( original as LookupPromiseSignature ) . apply ( this , [ hostname , ... args , ] ) , error => { if ( error != null ) { utils . setError ( error , span , process . version ) ; span . end ( ) ; } } ) ; promise . then ( result => { utils . setLookupAttributes ( span , result as LookupAddress ) ; span . end ( ) ; } , ( e ) => { utils . setError ( e , span , process . version ) ; span . end ( ) ; } ) ; return promise ; } } ; } /**
     * Wrap lookup callback function
     */ private _wrapLookupCallback ( original , span ) { return function wrappedLookupCallback ( this , err , address , family ? ) : void { diag . debug ( 'executing wrapped lookup callback function' ) ; if ( err !== null ) { utils . setError ( err , span , process . version ) ; } else { utils . setLookupAttributes ( span , address , family ) ; } span . end ( ) ; diag . debug ( 'executing original lookup callback function' ) ; return original . apply ( this , arguments ) ; } ; } }