import { Color , LogLevel , OgmaLog , OgmaStream , OgmaWritableLevel } from '@ogma/common' ; import { style , Styler } from '@ogma/styler' ; import { hostname } from 'os' ; import { OgmaDefaults , OgmaOptions , PrintMessageOptions } from '../interfaces' ; import { OgmaPrintOptions } from '../interfaces/ogma-print-options' ; import { colorize , isNil } from '../utils' ; /**
 * The main logger instance
 */ export class Ogma { private options : OgmaOptions ; private pid : number ; private hostname : string ; private styler : Styler ; /**
     * An alias for `ogma.verbose`. `FINE` is what is printed as the log level
     */ public fine = this . verbose ; /**
     * An alias for `ogma.info`. `INFO` is what is printed as the log level
     */ public log = this . info ; constructor ( options ? ) { if ( options ?. logLevel ) { options . logLevel = options . logLevel . toUpperCase ( ) as keyof typeof LogLevel ; } options && Object . keys ( options ) . filter ( ( key ) => isNil ( options [ key ] ) ) . forEach ( ( key ) => delete options [ key ] ) ; this . options = { ... OgmaDefaults , ... ( options as OgmaOptions ) } ; this . pid = process . pid ; this . hostname = hostname ( ) ; if ( options ?. logLevel && LogLevel [ options . logLevel ] === undefined ) { this . options . logLevel = OgmaDefaults . logLevel ; this . warn ( `Ogma logLevel was set to ${ options . logLevel } which does not match a defined logLevel. Falling back to default instead.` ) ; } if ( ! this . options . stream . getColorDepth ) { this . setStreamColorDepth ( ) ; } this . styler = style . child ( this . options . stream as Pick < OgmaStream , 'getColorDepth' > ) ; } private setStreamColorDepth ( ) { let colorDepthVal ; if ( this . options . color ) { colorDepthVal = 4 ; } if ( this . options . color === false ) { colorDepthVal = 1 ; } if ( ! colorDepthVal && this . options . stream !== process . stdout && process . stdout . getColorDepth ) { colorDepthVal = process . stdout . getColorDepth ( ) ; } this . options . stream . getColorDepth = ( ) => colorDepthVal ?? 1 ; } private printMessage ( message , options ) { if ( options . level < LogLevel [ this . options . logLevel ] ) { return ; } let logString = '' ; if ( this . options . json ) { logString = this . formatJSON ( message , options ) ; } else { logString = this . formatStream ( message , options ) ; } this . options . stream . write ( `${ logString }\n` ) ; if ( this . options . verbose && ! this . options . json ) { const { context : _context , application : _application , correlationId : _correlationId , level : _level , formattedLevel : _formattedLevel , ... meta } = options ; this . options . stream . write ( this . formatStream ( meta , options ) ) ; } } private circularReplacer ( ) { const seen = new WeakSet ( ) ; return ( key , value ) : string => { if ( typeof value === 'symbol' ) { return this . wrapInBrackets ( value . toString ( ) ) ; } if ( typeof value === 'function' ) { return this . wrapInBrackets ( `Function: ${ value . name || '(anonymous)' }` ) ; } if ( typeof value === 'object' && value !== null ) { if ( seen . has ( value ) ) { return this . wrapInBrackets ( 'Circular' ) ; } seen . add ( value ) ; } if ( this . options . masks . includes ( key ) ) { return '*' . repeat ( value . toString ( ) . length ) ; } return value ; } ; } private toColor ( level , color ) { const levelString = this . wrapInBrackets ( this . options . levelMap [ LogLevel [ level ] ] ) . padEnd ( 7 ) ; return colorize ( levelString , color , this . styler , this . options . color ) ; } private wrapInBrackets ( valueToBeWrapper ) { return `[${ valueToBeWrapper }]` ; } private formatJSON ( message , { application = '' , correlationId = '' , context = '' , level , ... meta } ) { let json = { time : this . getTimestamp ( ) , } ; delete meta . formattedLevel ; const mappedLevel = this . options . levelMap [ LogLevel [ level ] as keyof typeof LogLevel ] ; json . application = application || this . options . application || undefined ; json . pid = this . pid ; json . hostname = this . hostname ; json . correlationId = correlationId ; json . context = context || this . options . context || undefined ; json . level = mappedLevel ; json . ool = LogLevel [ level ] as OgmaWritableLevel ; if ( this . options . levelKey ) { json [ this . options . levelKey ] = mappedLevel ; } if ( typeof message === 'object' ) { json = { ... json , ... message } ; } else { json . message = message ; } if ( meta && Object . keys ( meta ) . length ) { json . meta = meta ; } return JSON . stringify ( json , this . circularReplacer ( ) ) ; } private formatStream ( message , { application = '' , correlationId = '' , formattedLevel , context = '' } ) { if ( typeof message === 'object' && ! ( message instanceof Error ) ) { message = '\n' + JSON . stringify ( message , this . circularReplacer ( ) , 2 ) ; } application = this . toStreamColor ( application || this . options . application , Color . YELLOW ) ; context = this . toStreamColor ( context || this . options . context , Color . CYAN ) ; correlationId &&= this . wrapInBrackets ( correlationId ) ; const hostname = this . toStreamColor ( this . hostname , Color . MAGENTA ) ; const timestamp = this . wrapInBrackets ( this . getTimestamp ( ) ) ; return `${ timestamp } ${ formattedLevel } ${ hostname } ${ application } ${ this . wrapInBrackets ( this . pid . toString ( ) ) } ${ correlationId } ${ context } ${ message }` ; } private toStreamColor ( value , color ) { if ( ! value ) { return '' ; } return colorize ( this . wrapInBrackets ( value ) , color , this . styler , this . options . color ) ; } private getTimestamp ( ) { return new Date ( ) . toISOString ( ) ; } param message param meta public silly ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . SILLY , formattedLevel : this . toColor ( LogLevel . SILLY , Color . MAGENTA ) , ... meta , } ) ; } param message param meta public verbose ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . VERBOSE , formattedLevel : this . toColor ( LogLevel . VERBOSE , Color . GREEN ) , ... meta , } ) ; } param message param meta public debug ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . DEBUG , formattedLevel : this . toColor ( LogLevel . DEBUG , Color . BLUE ) , ... meta , } ) ; } param message param meta public info ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . INFO , formattedLevel : this . toColor ( LogLevel . INFO , Color . CYAN ) , ... meta , } ) ; } param message param meta public warn ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . WARN , formattedLevel : this . toColor ( LogLevel . WARN , Color . YELLOW ) , ... meta , } ) ; } param message param meta public error ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . ERROR , formattedLevel : this . toColor ( LogLevel . ERROR , Color . RED ) , ... meta , } ) ; } param message param meta public fatal ( message , meta ? ) { this . printMessage ( message , { level : LogLevel . FATAL , formattedLevel : this . styler . redBg . white . underline . apply ( this . wrapInBrackets ( LogLevel [ LogLevel . FATAL ] ) ) , ... meta , } ) ; } param error param meta public printError ( error , meta ? ) { this . error ( error . name , meta ) ; this . warn ( error . message , meta ) ; this . verbose ( '\n' + error . stack , meta ) ; } }