import * as os from 'os' ; import * as pino from 'pino' ; import * as QuickLRU from 'quick-lru' ; import { v4 as uuidV4 } from 'uuid' ; import { ConsoleLogger , Injectable } from '@nestjs/common' ; import { ConfigService } from '@fc/config' ; import * as colors from './constants' ; import { LoggerConfig } from './dto' ; import { LoggerLevelNames } from './enum' ; import { ILoggerBusinessEvent , ILoggerColorParams } from './interfaces' ; import { nestLevelsMap , pinoLevelsMap } from './log-maps.map' ; import * as utils from './utils' ; see chrome const IS_TRACE_OUTPUT = true ; see https @ Injectable ( ) export class LoggerService extends ConsoleLogger { /**
     * This variable store the colors used by each
     * libraries to display the logs in Chrome Debug Tools.
     */ private libraryColors : ILoggerColorParams ; private containerColors : ILoggerColorParams ; private containerName : string ; private externalLogger : any ; see https private cache : QuickLRU < string , any > ; constructor ( private readonly config ) { super ( null ) ; const { level , path } = this . config . get < LoggerConfig > ( 'Logger' ) ; this . setContainerColors ( ) ; this . externalLogger = pino ( { formatters : { level ( label , _number ) { return { level : label } ; } , } , level : pinoLevelsMap [ level ] , } , pino . destination ( path ) ) ; if ( ! this . isDev ( ) ) { this . overrideNativeConsole ( ) ; } this . cache = new QuickLRU ( { maxSize : 128 } ) ; } private getIdentifiedLog ( log ) { const logId = uuidV4 ( ) ; return { ... log , logId , } ; } param { LoggerLevelNames } level param { any } log param { any } context private internalLogger ( level , log , context ) { super [ level ] ( log , context ) ; todo see https author brice
         *  date if ( this . isOutputTrace ( ) && log && context ) { console [ level ] ( log , context ) ; } } private canLog ( level ) { return pinoLevelsMap [ this . externalLogger . level ] <= pinoLevelsMap [ level ] ; } private isDev ( ) { return ! ! this . config . get < LoggerConfig > ( 'Logger' ) . isDevelopment ; } private isOutputTrace ( ) { return this . isDev ( ) && IS_TRACE_OUTPUT ; } private technicalLogger ( level , log , context ? ) { if ( ! this . canLog ( level ) ) { return ; } let message = log ; if ( ! this . isDev ( ) ) { try { message = JSON . stringify ( log ) ; } catch ( error ) { this . internalLogger ( nestLevelsMap . warn , 'could not JSON stringify a log' , context ) ; message = log ; } } this . internalLogger ( nestLevelsMap [ level ] , message , context ) ; } private businessLogger ( level , log , context ? ) { this . trace ( { log , context } , level ) ; if ( this . canLog ( level ) ) { this . externalLogger [ level ] ( this . getIdentifiedLog ( log ) ) ; } } private overrideNativeConsole ( ) { const methods = [ 'log' , 'error' , 'debug' , 'info' , 'warn' ] ; const context = 'Native Console' ; methods . forEach ( ( method ) => { TODO see https console [ method ] = ( ... args ) => this [ method ] ( args . join ( '\n' ) , context ) ; } ) ; } log ( log , context ? ) { if ( this . isDev ( ) ) { this . technicalLogger ( LoggerLevelNames . LOG , log , context ) ; } } verbose ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . VERBOSE , log , context ) ; } debug ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . DEBUG , log , context ) ; } info ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . INFO , log , context ) ; } warn ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . WARN , log , context ) ; } error ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . ERROR , log , context ) ; } fatal ( log , context ? ) { this . technicalLogger ( LoggerLevelNames . FATAL , log , context ) ; } businessEvent ( log , context ? ) { this . businessLogger ( LoggerLevelNames . INFO , log , context ) ; } returns { void } private setContainerColors ( ) { this . containerName = os . hostname ( ) || 'n/a' ; this . containerColors = utils . getColorsFromText ( this . containerName ) ; } param { ILoggerColorParams } colors returns { void } setLibraryColors ( colors ) { this . libraryColors = colors ; } param { string } context returns { void } setContext ( context ) { super . setContext ( context ) ; let libraryName ; if ( this . cache . has ( context ) ) { libraryName = this . cache . get ( context ) ; } else { libraryName = this . getLibraryName ( context ) ; this . cache . set ( context , libraryName ) ; } let color ; if ( this . cache . has ( libraryName ) ) { color = this . cache . get ( libraryName ) ; } else { color = utils . getColorsFromText ( libraryName ) ; this . cache . set ( libraryName , color ) ; } this . setLibraryColors ( color ) ; } param { string } context returns { string } private getLibraryName ( context ) { const hasContext = this . cache . has ( context ) ; let libraryName = 'logger' ; if ( context ) { if ( hasContext ) { libraryName = this . cache . get ( context ) ; } else { libraryName = utils . slugLibName ( context ) ; this . cache . set ( context , libraryName ) ; } } return libraryName ; } param { string } classMethodName returns { ILoggerColorParams } private getClassMethodColor ( classMethodName ) { const { loggerColorClassCategoryEnum : categories , loggerClassMethodColorsConstant : methodColors , } = colors ; const categoryClassName = Object . keys ( categories ) . find ( ( cat ) => classMethodName . includes ( `${ cat }.` ) ) ; const BACKGROUND_COLOR = categories [ categoryClassName ] || methodColors . BACKGROUND_COLOR ; return { ... methodColors , BACKGROUND_COLOR , } ; } param { Array < ILoggerColorParams > } allColors returns { Array < string > } private getDebuggerCssColors ( allColors ) { return allColors . map ( ( color ) : string => { const colorHash = JSON . stringify ( color ) ; let cssStyle ; if ( this . cache . has ( colorHash ) ) { cssStyle = this . cache . get ( colorHash ) ; } else { cssStyle = utils . getStyle ( color ) ; this . cache . set ( colorHash , cssStyle ) ; } return cssStyle ; } ) ; } param { string } dateTime param { string } containerName param { string } libraryName param { string } classMethodName returns { string } private getDebuggerMetadata ( dateTime , containerName , libraryName , classMethodName ) { return `%c${ dateTime }%c${ containerName }%c${ libraryName }%c${ classMethodName }()` ; } warn param { string } logger returns { Function } private getConsoleCommand ( level = LoggerLevelNames . LOG ) { const levelKey = level . toUpperCase ( ) ; if ( LoggerLevelNames [ levelKey ] ) { return console [ LoggerLevelNames [ levelKey ] ] ; } return console [ LoggerLevelNames . LOG ] ; } see chrome param { any } msg param { string } level returns { void } trace ( msg ? , level = LoggerLevelNames . LOG ) { if ( ! this . isOutputTrace ( ) ) { return ; } const dateTime = utils . getDateTime ( ) ; const containerName = this . containerName ; const libraryName = this . getLibraryName ( this . context ) ; const classMethodName = utils . getClassMethodCaller ( ) ; const metadata = this . getDebuggerMetadata ( dateTime , containerName , libraryName , classMethodName ) ; const allColors = [ colors . loggerTimeColorsConstant , this . containerColors , this . libraryColors , this . getClassMethodColor ( classMethodName ) , ] ; const loggerColors = this . getDebuggerCssColors ( allColors ) ; const command = this . getConsoleCommand ( level ) ; command ( metadata , ... loggerColors , msg ) ; } }