import { Writeable, WriteableOptions } from '../lib/stream'; import errorCodes from '../lib/error'; import createDebuggerLogger from '../lib/debugLogger'; import { Logger, LogType, LogInfo } from './Logger'; import { Format } from './logger-format'; import { LEVEL } from '../constants'; const debuggerLogger = createDebuggerLogger('iot-logger-transport'); const { ERR_METHOD_NOT_IMPLEMENTED, ERR_INVALID_OPT_VALUE, } = errorCodes; export interface LoggerTransportOptions extends WriteableOptions { name: string; level?: LogType; format?: Format; } export class LoggerTransport extends Writeable { readonly name: string; readonly level: LogType; private intervalFormat: Format; private parent: Logger; constructor({ name, level, format, ...opts }: LoggerTransportOptions) { super(opts); if (!name) { throw new ERR_INVALID_OPT_VALUE('name', name); } this.name = String(name); this.level = level; if (format instanceof Format) { this.intervalFormat = format; } } get format() { return this.intervalFormat; } set format(format: Format) { if (format instanceof Format) { this.intervalFormat = format; } } load(logger: Logger) { this.parent = logger; } // eslint-disable-next-line @typescript-eslint/naming-convention protected _write(log: LogInfo, cb) { const arr = this.resolveLogs([log]); if (arr.length) { this.log(arr[0], cb); } else { cb(); } } // eslint-disable-next-line @typescript-eslint/naming-convention protected _writev(logs: LogInfo[], cb) { const arr = this.resolveLogs(logs); if (arr.length) { this.logBatch(arr, cb); } else { cb(); } } // eslint-disable-next-line @typescript-eslint/naming-convention protected _destroy() { this.parent = null; this.destroy(); } protected destroy() { // 不要抛错(非关键路径) debuggerLogger.warn(new ERR_METHOD_NOT_IMPLEMENTED('destroy()')); } protected log(_log: LogInfo, _cb) { throw new ERR_METHOD_NOT_IMPLEMENTED('log()'); } protected logBatch(_logs: LogInfo[], _cb) { throw new ERR_METHOD_NOT_IMPLEMENTED('logBatch()'); } private resolveLogs(logs: LogInfo[]): LogInfo[] { const curLevel = typeof this.parent.levels[this.level] === 'number' ? this.level : this.parent.level; const levels = this.parent.levels; const filterLogs = logs.filter(item => levels[curLevel] >= levels[item[LEVEL]]); // eslint-disable-next-line array-callback-return return filterLogs.map((item) => { if (!this.format) { return { ...item }; } try { return this.format.transform({ ...item, }) as LogInfo; } catch (err) { debuggerLogger.error('exec format error', err); } }).filter(item => !!item); } }