import bunyan from '@expo/bunyan' ; import isEmpty from 'lodash/isEmpty' ; import isPlainObject from 'lodash/isPlainObject' ; import { Readable } from 'stream' ; export enum LogLevel { trace = 'trace' , debug = 'debug' , info = 'info' , warn = 'warn' , error = 'error' , fatal = 'fatal' } type BunyanGetter = ( ) => bunyan ; export class Logger { loggerObj : bunyan ; loggerGetter ? : BunyanGetter ; extraFields : any ; constructor ( bunyanGetter ? , extraFields ? ) { this . loggerObj = bunyan . createLogger ( { name : 'xdl-detach' } ) ; this . loggerGetter = bunyanGetter ; this . extraFields = extraFields ; } configure ( loggerObj ) { this . loggerObj = loggerObj ; } withFields ( extraFields ) { const getter = this . loggerGetter || ( ( ) => this . loggerObj ) ; return new Logger ( getter , { ... this . extraFields , ... extraFields } ) ; } trace ( ... all ) { this . logLine ( LogLevel . trace , ... all ) ; } debug ( ... all ) { this . logLine ( LogLevel . debug , ... all ) ; } info ( ... all ) { this . logLine ( LogLevel . info , ... all ) ; } warn ( ... all ) { this . logLine ( LogLevel . warn , ... all ) ; } error ( ... all ) { this . logLine ( LogLevel . error , ... all ) ; } fatal ( ... all ) { this . logLine ( LogLevel . fatal , ... all ) ; } logLine ( level , ... args ) { const argsToLog = [ ... args ] ; const extraFieldsFromArgsExist = isPlainObject ( args [ 0 ] ) ; const extraFieldsFromArgs = extraFieldsFromArgsExist ? args [ 0 ] : { } ; if ( extraFieldsFromArgsExist ) { argsToLog . shift ( ) ; } const extraFields = { ... extraFieldsFromArgs , ... this . extraFields } ; if ( ! isEmpty ( extraFields ) ) { argsToLog . unshift ( extraFields ) ; } if ( this . loggerGetter ) { const loggerObj = this . loggerGetter ( ) ; loggerObj [ level ] ( ... argsToLog ) ; } else { this . loggerObj [ level ] ( ... argsToLog ) ; } } } const LoggerDetach = new Logger ( ) ; export default LoggerDetach ; export function pipeOutputToLogger ( { stdout , stderr } = { stdout : null , stderr : null } , extraFields = { } , { stdoutOnly = false , loggerLineTransformer , } = { } ) { if ( stdout ) { stdout . on ( 'data' , chunk => logMultiline ( chunk , { ... extraFields , source : 'stdout' } , loggerLineTransformer ) ) ; } if ( stderr ) { const source = stdoutOnly ? 'stdout' : 'stderr' ; stderr . on ( 'data' , chunk => logMultiline ( chunk , { ... extraFields , source } , loggerLineTransformer ) ) ; } } function logMultiline ( data , extraFields , loggerLineTransformer ? ) { if ( ! data ) { return ; } const lines = String ( data ) . split ( '\n' ) ; lines . forEach ( line => { const lineToPrint = loggerLineTransformer ? loggerLineTransformer ( line ) : line ; if ( lineToPrint ) { const args = [ lineToPrint ] ; if ( ! isEmpty ( extraFields ) ) { args . unshift ( extraFields ) ; } LoggerDetach . info ( ... args ) ; } } ) ; }