import { colors } from '@gongt/ts-stl-library/debug/_color_server'; import { IDebugger } from '@gongt/ts-stl-library/debug/create-logger'; import { levels, LOG_LEVEL } from '@gongt/ts-stl-library/debug/levels'; import { currentLevel, loggers } from '@gongt/ts-stl-library/debug/vars'; import { transports } from 'winston'; import { getWinstonExtraLoggers } from './winston-extra'; const winston = require('winston'); /** @internal */ export function createLoggerServer(level: LOG_LEVEL = LOG_LEVEL.INFO, title: string): IDebugger { if (!LOG_LEVEL.hasOwnProperty(level)) { throw new Error(`unknown log level: ${level}`); } const id = title + ':' + LOG_LEVEL[level]; if (loggers[id]) { return loggers[id]; } const logger = createLoggerObject(title); const levelName = LOG_LEVEL[level]; let logFn = logger[levelName].bind(logger); const log_func: any = level === LOG_LEVEL.DATA? (...args) => { if (typeof args[0] === 'string') { args[0] = '\x1B[2;38;5;10m' + args[0] + '\x1B[0m'; } else { args.unshift('\x1B[2;38;5;10m%j\x1B[0m'); } args[0] = args[0].replace(/%O/i, '%j'); // NOTE: right click and "black box script" // to prevent wrong source location while // logging return logFn(...args); } : (message, ...args) => { if (typeof message === 'string') { message = message.replace(/%O/i, '%j'); } return logFn(message, ...args); }; Object.defineProperty(log_func, 'enabled', { get() { return level <= currentLevel; }, }); Object.defineProperty(log_func, 'fn', { get() { return logFn; }, }); Object.defineProperty(log_func, 'level', { get() { return logger.level; }, set(v) { console.warn('log level can not modify after created'); logger.level = v; }, }); loggers.push(log_func); loggers[id] = log_func; return log_func; } let cache: {[id: string]: any} = {}; let to: NodeJS.Timer = null; function clearRefs() { if (!to) { to = setTimeout(() => { to = null; cache = {}; }, 5000); } } function createLoggerObject(title: string|undefined) { if (cache[title]) { clearRefs(); return cache[title]; } const myFormat = winston.format.printf(info => { return `[${info.level}][${info.label}] ${info.message}`; }); const logger = winston.createLogger({ level: LOG_LEVEL[currentLevel], id: title, format: winston.format.combine( winston.format.splat(), winston.format.label({label: title}), winston.format.colorize({colors}), winston.format.prettyPrint(), myFormat, ), levels: levels, transports: [new transports.Console()], }); logger.on('error', (err) => { console.error('error during logging: %s', err); }); for (const {constructor, options} of getWinstonExtraLoggers()) { logger.add(constructor, { timestamp: false, showLevel: true, prettyPrint: true, colorize: true, align: true, label: title, ...options, }); } cache[title] = logger; return logger; } process.on('unhandledRejection', (reason, p) => { console.error('UnhandledPromiseRejection: %s', reason? reason.stack || reason.message : '{*no reason*}'); console.error('\x1B[38;5;9;1m=========================\nUnhandledPromiseRejection:\n%s\n=========================\x1B[0m', reason? reason.stack || reason.message : 'undefined'); });