chenyc
2026-05-20 c8ba0f92b3f84273a78f06de25359db20c1b2a4d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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,
};