const fs = require('fs'); const path = require('path'); const LOG_LEVELS = { debug: 10, info: 20, warn: 30, error: 40, }; function formatLocalTimestamp(date = new Date()) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hour = String(date.getHours()).padStart(2, '0'); const minute = String(date.getMinutes()).padStart(2, '0'); const second = String(date.getSeconds()).padStart(2, '0'); const millisecond = String(date.getMilliseconds()).padStart(3, '0'); return `${year}-${month}-${day} ${hour}:${minute}:${second}.${millisecond}`; } function normalizeLogLevel(level) { const normalized = String(level || 'info').trim().toLowerCase(); return LOG_LEVELS[normalized] ? normalized : 'info'; } function createLogger(loggingConfig = {}) { const settings = { enabled: loggingConfig.enabled !== false, console: loggingConfig.console !== false, dir: loggingConfig.dir || path.join(process.cwd(), 'logs'), filePrefix: loggingConfig.filePrefix || 'jh2028-service', level: normalizeLogLevel(loggingConfig.level), }; let currentDate = ''; let currentFilePath = ''; function getDatePart(date = new Date()) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}${month}${day}`; } function ensureLogFilePath() { if (!settings.enabled) { return null; } const today = getDatePart(); if (currentFilePath && currentDate === today) { return currentFilePath; } fs.mkdirSync(settings.dir, { recursive: true }); currentDate = today; currentFilePath = path.join(settings.dir, `${settings.filePrefix}-${today}.log`); return currentFilePath; } function shouldWrite(level) { return LOG_LEVELS[level] >= LOG_LEVELS[settings.level]; } function write(level, message) { const normalizedLevel = normalizeLogLevel(level); if (!shouldWrite(normalizedLevel)) { return; } const line = `[${formatLocalTimestamp()}] [${normalizedLevel.toUpperCase()}] ${message}`; if (settings.console) { if (normalizedLevel === 'error') { console.error(line); } else if (normalizedLevel === 'warn') { console.warn(line); } else { console.log(line); } } const logFilePath = ensureLogFilePath(); if (logFilePath) { try { fs.appendFileSync(logFilePath, `${line}\n`, 'utf8'); } catch (error) { console.error(`[LOGGER] 写入日志文件失败: ${error.message}`); } } } return { debug(message) { write('debug', message); }, info(message) { write('info', message); }, warn(message) { write('warn', message); }, error(message) { write('error', message); }, getLogFilePath() { return ensureLogFilePath(); }, async close() { currentDate = ''; }, }; } module.exports = { createLogger, formatLocalTimestamp, normalizeLogLevel, };