| | import path from 'path'; |
| | import _util from 'util'; |
| |
|
| | import 'colors'; |
| | import _ from 'lodash'; |
| | import fs from 'fs-extra'; |
| | import { format as dateFormat } from 'date-fns'; |
| |
|
| | import config from './config.ts'; |
| | import util from './util.ts'; |
| |
|
| | const isVercelEnv = process.env.VERCEL; |
| |
|
| | class LogWriter { |
| |
|
| | #buffers = []; |
| |
|
| | constructor() { |
| | !isVercelEnv && fs.ensureDirSync(config.system.logDirPath); |
| | !isVercelEnv && this.work(); |
| | } |
| |
|
| | push(content) { |
| | const buffer = Buffer.from(content); |
| | this.#buffers.push(buffer); |
| | } |
| |
|
| | writeSync(buffer) { |
| | !isVercelEnv && fs.appendFileSync(path.join(config.system.logDirPath, `/${util.getDateString()}.log`), buffer); |
| | } |
| |
|
| | async write(buffer) { |
| | !isVercelEnv && await fs.appendFile(path.join(config.system.logDirPath, `/${util.getDateString()}.log`), buffer); |
| | } |
| |
|
| | flush() { |
| | if(!this.#buffers.length) return; |
| | !isVercelEnv && fs.appendFileSync(path.join(config.system.logDirPath, `/${util.getDateString()}.log`), Buffer.concat(this.#buffers)); |
| | } |
| |
|
| | work() { |
| | if (!this.#buffers.length) return setTimeout(this.work.bind(this), config.system.logWriteInterval); |
| | const buffer = Buffer.concat(this.#buffers); |
| | this.#buffers = []; |
| | this.write(buffer) |
| | .finally(() => setTimeout(this.work.bind(this), config.system.logWriteInterval)) |
| | .catch(err => console.error("Log write error:", err)); |
| | } |
| |
|
| | } |
| |
|
| | class LogText { |
| |
|
| | |
| | level; |
| | |
| | text; |
| | |
| | source; |
| | |
| | time = new Date(); |
| |
|
| | constructor(level, ...params) { |
| | this.level = level; |
| | this.text = _util.format.apply(null, params); |
| | this.source = this.#getStackTopCodeInfo(); |
| | } |
| |
|
| | #getStackTopCodeInfo() { |
| | const unknownInfo = { name: "unknown", codeLine: 0, codeColumn: 0 }; |
| | const stackArray = new Error().stack.split("\n"); |
| | const text = stackArray[4]; |
| | if (!text) |
| | return unknownInfo; |
| | const match = text.match(/at (.+) \((.+)\)/) || text.match(/at (.+)/); |
| | if (!match || !_.isString(match[2] || match[1])) |
| | return unknownInfo; |
| | const temp = match[2] || match[1]; |
| | const _match = temp.match(/([a-zA-Z0-9_\-\.]+)\:(\d+)\:(\d+)$/); |
| | if (!_match) |
| | return unknownInfo; |
| | const [, scriptPath, codeLine, codeColumn] = _match as any; |
| | return { |
| | name: scriptPath ? scriptPath.replace(/.js$/, "") : "unknown", |
| | path: scriptPath || null, |
| | codeLine: parseInt(codeLine || 0), |
| | codeColumn: parseInt(codeColumn || 0) |
| | }; |
| | } |
| |
|
| | toString() { |
| | return `[${dateFormat(this.time, "yyyy-MM-dd HH:mm:ss.SSS")}][${this.level}][${this.source.name}<${this.source.codeLine},${this.source.codeColumn}>] ${this.text}`; |
| | } |
| |
|
| | } |
| |
|
| | class Logger { |
| |
|
| | |
| | config = {}; |
| | |
| | static Level = { |
| | Success: "success", |
| | Info: "info", |
| | Log: "log", |
| | Debug: "debug", |
| | Warning: "warning", |
| | Error: "error", |
| | Fatal: "fatal" |
| | }; |
| | |
| | static LevelColor = { |
| | [Logger.Level.Success]: "green", |
| | [Logger.Level.Info]: "brightCyan", |
| | [Logger.Level.Debug]: "white", |
| | [Logger.Level.Warning]: "brightYellow", |
| | [Logger.Level.Error]: "brightRed", |
| | [Logger.Level.Fatal]: "red" |
| | }; |
| | #writer; |
| |
|
| | constructor() { |
| | this.#writer = new LogWriter(); |
| | } |
| |
|
| | header() { |
| | this.#writer.writeSync(Buffer.from(`\n\n===================== LOG START ${dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")} =====================\n\n`)); |
| | } |
| |
|
| | footer() { |
| | this.#writer.flush(); |
| | this.#writer.writeSync(Buffer.from(`\n\n===================== LOG END ${dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss.SSS")} =====================\n\n`)); |
| | } |
| |
|
| | success(...params) { |
| | const content = new LogText(Logger.Level.Success, ...params).toString(); |
| | console.info(content[Logger.LevelColor[Logger.Level.Success]]); |
| | this.#writer.push(content + "\n"); |
| | } |
| |
|
| | info(...params) { |
| | const content = new LogText(Logger.Level.Info, ...params).toString(); |
| | console.info(content[Logger.LevelColor[Logger.Level.Info]]); |
| | this.#writer.push(content + "\n"); |
| | } |
| |
|
| | log(...params) { |
| | const content = new LogText(Logger.Level.Log, ...params).toString(); |
| | console.log(content[Logger.LevelColor[Logger.Level.Log]]); |
| | this.#writer.push(content + "\n"); |
| | } |
| |
|
| | debug(...params) { |
| | if(!config.system.debug) return; |
| | const content = new LogText(Logger.Level.Debug, ...params).toString(); |
| | console.debug(content[Logger.LevelColor[Logger.Level.Debug]]); |
| | this.#writer.push(content + "\n"); |
| | } |
| |
|
| | warn(...params) { |
| | const content = new LogText(Logger.Level.Warning, ...params).toString(); |
| | console.warn(content[Logger.LevelColor[Logger.Level.Warning]]); |
| | this.#writer.push(content + "\n"); |
| | } |
| |
|
| | error(...params) { |
| | const content = new LogText(Logger.Level.Error, ...params).toString(); |
| | console.error(content[Logger.LevelColor[Logger.Level.Error]]); |
| | this.#writer.push(content); |
| | } |
| |
|
| | fatal(...params) { |
| | const content = new LogText(Logger.Level.Fatal, ...params).toString(); |
| | console.error(content[Logger.LevelColor[Logger.Level.Fatal]]); |
| | this.#writer.push(content); |
| | } |
| |
|
| | destory() { |
| | this.#writer.destory(); |
| | } |
| |
|
| | } |
| |
|
| | export default new Logger(); |