import { context , diag , trace , isSpanContextValid , Span , } from '@opentelemetry/api' ; import { InstrumentationBase , InstrumentationNodeModuleDefinition , isWrapped , safeExecuteInTheMiddle , } from '@opentelemetry/instrumentation' ; import { BunyanInstrumentationConfig } from './types' ; import { VERSION } from './version' ; import type * as BunyanLogger from 'bunyan' ; export class BunyanInstrumentation extends InstrumentationBase < typeof BunyanLogger > { constructor ( config = { } ) { super ( '@opentelemetry/instrumentation-bunyan' , VERSION , config ) ; } protected init ( ) { return [ new InstrumentationNodeModuleDefinition < typeof BunyanLogger > ( 'bunyan' , [ '<2.0' ] , logger => { const proto = logger . prototype as any ; if ( isWrapped ( proto [ '_emit' ] ) ) { this . _unwrap ( proto , '_emit' ) ; } this . _wrap ( proto , '_emit' , this . _getPatchedEmit ( ) as any ) ; return logger ; } , logger => { if ( logger === undefined ) return ; this . _unwrap ( logger . prototype as any , '_emit' ) ; } ) , ] ; } override getConfig ( ) { return this . _config ; } override setConfig ( config ) { this . _config = config ; } private _getPatchedEmit ( ) { return ( original ) => { const instrumentation = this ; return function patchedEmit ( this , ... args ) { const span = trace . getSpan ( context . active ( ) ) ; if ( ! span ) { return original . apply ( this , args ) ; } const spanContext = span . spanContext ( ) ; if ( ! isSpanContextValid ( spanContext ) ) { return original . apply ( this , args ) ; } const record = args [ 0 ] as Record < string , string > ; record [ 'trace_id' ] = spanContext . traceId ; record [ 'span_id' ] = spanContext . spanId ; record [ 'trace_flags' ] = `0${ spanContext . traceFlags . toString ( 16 ) }` ; instrumentation . _callHook ( span , record ) ; return original . apply ( this , args ) ; } ; } ; } private _callHook ( span , record ) { const hook = this . getConfig ( ) . logHook ; if ( typeof hook !== 'function' ) { return ; } safeExecuteInTheMiddle ( ( ) => hook ( span , record ) , err => { if ( err ) { diag . error ( 'bunyan instrumentation: error calling logHook' , err ) ; } } , true ) ; } }