import { LogLevel , LogData , PLUGIN_NAME } from '../record' ; import { eventWithTime , EventType , IncrementalSource , ReplayPlugin , } from '../../../types' ; /**
 * define an interface to replay log records
 * (data: logData) => void> function to display the log data
 */ type ReplayLogger = Partial < Record < LogLevel , ( data : LogData ) => void > > ; type LogReplayConfig = { level ? : LogLevel [ ] ; replayLogger ? : ReplayLogger ; } ; const ORIGINAL_ATTRIBUTE_NAME = '__rrweb_original__' ; type PatchedConsoleLog = { [ ORIGINAL_ATTRIBUTE_NAME ] : typeof console . log ; } ; const defaultLogConfig = { level : [ 'assert' , 'clear' , 'count' , 'countReset' , 'debug' , 'dir' , 'dirxml' , 'error' , 'group' , 'groupCollapsed' , 'groupEnd' , 'info' , 'log' , 'table' , 'time' , 'timeEnd' , 'timeLog' , 'trace' , 'warn' , ] , replayLogger : undefined , } ; class LogReplayPlugin { private config : LogReplayConfig ; constructor ( config ? ) { this . config = Object . assign ( defaultLogConfig , config ) ; } /**
     * generate a console log replayer which implement the interface ReplayLogger
     */ public getConsoleLogger ( ) { const replayLogger = { } ; for ( const level of this . config . level ! ) { if ( level === 'trace' ) { replayLogger [ level ] = ( data ) => { const logger = ( ( console . log as unknown ) as PatchedConsoleLog ) [ ORIGINAL_ATTRIBUTE_NAME ] ? ( ( console . log as unknown ) as PatchedConsoleLog ) [ ORIGINAL_ATTRIBUTE_NAME ] : console . log ; logger ( ... data . payload . map ( ( s ) => JSON . parse ( s ) ) , this . formatMessage ( data ) ) ; } ; } else { replayLogger [ level ] = ( data ) => { const logger = ( ( console [ level ] as unknown ) as PatchedConsoleLog ) [ ORIGINAL_ATTRIBUTE_NAME ] ? ( ( console [ level ] as unknown ) as PatchedConsoleLog ) [ ORIGINAL_ATTRIBUTE_NAME ] : console [ level ] ; logger ( ... data . payload . map ( ( s ) => JSON . parse ( s ) ) , this . formatMessage ( data ) ) ; } ; } } return replayLogger ; } param data private formatMessage ( data ) { if ( data . trace . length === 0 ) { return '' ; } const stackPrefix = '\n\tat ' ; let result = stackPrefix ; result += data . trace . join ( stackPrefix ) ; return result ; } } export const getReplayConsolePlugin = ( options ) => { const replayLogger = options ?. replayLogger || new LogReplayPlugin ( options ) . getConsoleLogger ( ) ; return { handler ( event , _isSync , context ) { let logData = null ; if ( event . type === EventType . IncrementalSnapshot && event . data . source === ( IncrementalSource . Log as IncrementalSource ) ) { logData = ( event . data as unknown ) as LogData ; } else if ( event . type === EventType . Plugin && event . data . plugin === PLUGIN_NAME ) { logData = event . data . payload as LogData ; } if ( logData ) { try { if ( typeof replayLogger [ logData . level ] === 'function' ) { replayLogger [ logData . level ] ! ( logData ) ; } } catch ( error ) { if ( context . replayer . config . showWarning ) { console . warn ( error ) ; } } } } , } ; } ;