161 lines
4.1 KiB
JavaScript
161 lines
4.1 KiB
JavaScript
const fs = require("fs")
|
|
const path = require("path")
|
|
|
|
class Logger {
|
|
constructor(config = {}) {
|
|
this.config = {
|
|
level: config.level || "info",
|
|
saveToFile: config.saveToFile || true,
|
|
maxFileSize: config.maxFileSize || "10MB",
|
|
maxFiles: config.maxFiles || 5,
|
|
logDir: config.logDir || "./logs",
|
|
}
|
|
|
|
this.levels = {
|
|
debug: 0,
|
|
info: 1,
|
|
warn: 2,
|
|
error: 3,
|
|
success: 1,
|
|
}
|
|
|
|
this.colors = {
|
|
debug: "\x1b[36m", // Cyan
|
|
info: "\x1b[34m", // Blue
|
|
warn: "\x1b[33m", // Yellow
|
|
error: "\x1b[31m", // Red
|
|
success: "\x1b[32m", // Green
|
|
reset: "\x1b[0m",
|
|
}
|
|
|
|
this.initLogDirectory()
|
|
}
|
|
|
|
initLogDirectory() {
|
|
if (this.config.saveToFile && !fs.existsSync(this.config.logDir)) {
|
|
fs.mkdirSync(this.config.logDir, { recursive: true })
|
|
}
|
|
}
|
|
|
|
formatMessage(level, message, data = null) {
|
|
const timestamp = new Date().toISOString()
|
|
const upperLevel = level.toUpperCase().padEnd(7)
|
|
|
|
let logMessage = `[${timestamp}] [${upperLevel}] ${message}`
|
|
|
|
if (data) {
|
|
logMessage += ` ${JSON.stringify(data, null, 2)}`
|
|
}
|
|
|
|
return logMessage
|
|
}
|
|
|
|
shouldLog(level) {
|
|
return this.levels[level] >= this.levels[this.config.level]
|
|
}
|
|
|
|
writeToFile(message) {
|
|
if (!this.config.saveToFile) return
|
|
|
|
const logFile = path.join(this.config.logDir, `openbrawl-${new Date().toISOString().split("T")[0]}.log`)
|
|
|
|
try {
|
|
fs.appendFileSync(logFile, message + "\n")
|
|
this.rotateLogsIfNeeded(logFile)
|
|
} catch (error) {
|
|
console.error("Failed to write to log file:", error.message)
|
|
}
|
|
}
|
|
|
|
rotateLogsIfNeeded(logFile) {
|
|
try {
|
|
const stats = fs.statSync(logFile)
|
|
const maxSize = this.parseSize(this.config.maxFileSize)
|
|
|
|
if (stats.size > maxSize) {
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-")
|
|
const rotatedFile = logFile.replace(".log", `-${timestamp}.log`)
|
|
fs.renameSync(logFile, rotatedFile)
|
|
|
|
this.cleanOldLogs()
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to rotate logs:", error.message)
|
|
}
|
|
}
|
|
|
|
cleanOldLogs() {
|
|
try {
|
|
const files = fs
|
|
.readdirSync(this.config.logDir)
|
|
.filter((file) => file.startsWith("openbrawl-") && file.endsWith(".log"))
|
|
.map((file) => ({
|
|
name: file,
|
|
path: path.join(this.config.logDir, file),
|
|
time: fs.statSync(path.join(this.config.logDir, file)).mtime,
|
|
}))
|
|
.sort((a, b) => b.time - a.time)
|
|
|
|
if (files.length > this.config.maxFiles) {
|
|
files.slice(this.config.maxFiles).forEach((file) => {
|
|
fs.unlinkSync(file.path)
|
|
})
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to clean old logs:", error.message)
|
|
}
|
|
}
|
|
|
|
parseSize(sizeStr) {
|
|
const units = { B: 1, KB: 1024, MB: 1024 * 1024, GB: 1024 * 1024 * 1024 }
|
|
const match = sizeStr.match(/^(\d+)(B|KB|MB|GB)$/i)
|
|
|
|
if (!match) return 10 * 1024 * 1024 // Default 10MB
|
|
|
|
return Number.parseInt(match[1]) * units[match[2].toUpperCase()]
|
|
}
|
|
|
|
log(level, message, data = null) {
|
|
if (!this.shouldLog(level)) return
|
|
|
|
const formattedMessage = this.formatMessage(level, message, data)
|
|
const coloredMessage = `${this.colors[level]}${formattedMessage}${this.colors.reset}`
|
|
|
|
console.log(coloredMessage)
|
|
this.writeToFile(formattedMessage)
|
|
}
|
|
|
|
debug(message, data = null) {
|
|
this.log("debug", message, data)
|
|
}
|
|
|
|
info(message, data = null) {
|
|
this.log("info", message, data)
|
|
}
|
|
|
|
warn(message, data = null) {
|
|
this.log("warn", message, data)
|
|
}
|
|
|
|
error(message, data = null) {
|
|
this.log("error", message, data)
|
|
}
|
|
|
|
success(message, data = null) {
|
|
this.log("success", message, data)
|
|
}
|
|
|
|
packet(direction, type, size, data = null) {
|
|
const arrow = direction === "in" ? "📨" : "📤"
|
|
const message = `${arrow} ${direction.toUpperCase()} | Type: ${type} | Size: ${size} bytes`
|
|
this.debug(message, data)
|
|
}
|
|
|
|
connection(status, details = null) {
|
|
const emoji = status === "connected" ? "✅" : status === "disconnected" ? "❌" : "🔄"
|
|
this.info(`${emoji} Connection ${status}`, details)
|
|
}
|
|
}
|
|
|
|
module.exports = Logger
|