import { isObject } from '../../../utils/src/is-object'; export type Level = 'debug' | 'log' | 'info' | 'warn' | 'error'; export interface LoggerOptions { level: Level; bizName: string; } const levels: Record = { debug: -1, log: 0, info: 0, warn: 1, error: 2, }; const bizNameColors = [ '#daa569', '#00ffff', '#385e0f', '#7fffd4', '#00c957', '#b0e0e6', '#4169e1', '#6a5acd', '#87ceeb', '#ffff00', '#e3cf57', '#ff9912', '#eb8e55', '#ffe384', '#40e0d0', '#a39480', '#d2691e', '#ff7d40', '#f0e68c', '#bc8f8f', '#c76114', '#734a12', '#5e2612', '#0000ff', '#3d59ab', '#1e90ff', '#03a89e', '#33a1c9', '#a020f0', '#a066d3', '#da70d6', '#dda0dd', '#688e23', '#2e8b57', ]; const bodyColors: Record = { debug: '#fadb14', log: '#8c8c8c', info: '#52c41a', warn: '#fa8c16', error: '#ff4d4f', }; const levelMarks: Record = { debug: 'debug', log: 'log', info: 'info', warn: 'warn', error: 'error', }; const outputFunction: Record = { debug: console.log, log: console.log, info: console.log, warn: console.warn, error: console.error, }; const bizNameColorConfig: Record = {}; const shouldOutput = ( logLevel: string, targetLevel: string = 'warn', bizName: string, targetBizName: string, ): boolean => { const isLevelFit = (levels as any)[targetLevel] <= (levels as any)[logLevel]; const isBizNameFit = targetBizName === '*' || bizName.indexOf(targetBizName) > -1; return isLevelFit && isBizNameFit; }; const output = (logLevel: string, bizName: string) => { return (...args: any[]) => { return outputFunction[logLevel]?.apply(console, getLogArgs(args, bizName, logLevel)); }; }; const getColor = (bizName: string) => { if (!bizNameColorConfig[bizName]) { const color = bizNameColors[Object.keys(bizNameColorConfig).length % bizNameColors.length]; bizNameColorConfig[bizName] = color; } return bizNameColorConfig[bizName]; }; const getLogArgs = (args: any, bizName: string, logLevel: string) => { const color = getColor(bizName); const bodyColor = bodyColors[logLevel]; const argsArray = args[0]; let prefix = `%c[${bizName}]%c[${levelMarks[logLevel]}]:`; argsArray.forEach((arg: any) => { if (isObject(arg)) { prefix += '%o'; } else { prefix += '%s'; } }); let processedArgs = [prefix, `color: ${color}`, `color: ${bodyColor}`]; processedArgs = processedArgs.concat(argsArray); return processedArgs; }; const parseLogConf = (logConf: string, options: LoggerOptions) => { if (!logConf) { return { level: options.level, bizName: options.bizName, }; } if (logConf.indexOf(':') > -1) { const pair = logConf.split(':'); return { level: pair[0], bizName: pair[1] || '*', }; } return { level: logConf, bizName: '*', }; }; const defaultOptions: LoggerOptions = { level: 'warn', bizName: '*', }; export class Logger { bizName: string; targetBizName: string; targetLevel: string; constructor(options: LoggerOptions) { options = { ...defaultOptions, ...options }; const _location = location || {} as any; // __logConf__ 格式为 logLevel[:bizName], bizName is used as: targetBizName like '%bizName%' // 1. __logConf__=log or __logConf__=warn, etc. // 2. __logConf__=log:* or __logConf__=warn:*, etc. // 2. __logConf__=log:bizName or __logConf__=warn:partOfBizName, etc. const logConf = (((/__(?:logConf|logLevel)__=([^#/&]*)/.exec(_location.href)) || [])[1]); const targetOptions = parseLogConf(logConf, options); this.bizName = options.bizName; this.targetBizName = targetOptions.bizName; this.targetLevel = targetOptions.level; } debug(...args: any[]): void { if (!shouldOutput('debug', this.targetLevel, this.bizName, this.targetBizName)) { return; } return output('debug', this.bizName)(args); } log(...args: any[]): void { if (!shouldOutput('log', this.targetLevel, this.bizName, this.targetBizName)) { return; } return output('log', this.bizName)(args); } info(...args: any[]): void { if (!shouldOutput('info', this.targetLevel, this.bizName, this.targetBizName)) { return; } return output('info', this.bizName)(args); } warn(...args: any[]): void { if (!shouldOutput('warn', this.targetLevel, this.bizName, this.targetBizName)) { return; } return output('warn', this.bizName)(args); } error(...args: any[]): void { if (!shouldOutput('error', this.targetLevel, this.bizName, this.targetBizName)) { return; } return output('error', this.bizName)(args); } } export function createLogger(config: { level: Level; bizName: string }): Logger { return new Logger(config); }