@reliverse/relinka 1.6.1 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -345
- package/dist/mod.d.ts +49 -0
- package/dist/mod.js +182 -0
- package/package.json +17 -38
- package/LICENSE +0 -21
- package/bin/alias.d.ts +0 -8
- package/bin/alias.js +0 -8
- package/bin/impl.d.ts +0 -50
- package/bin/impl.js +0 -605
- package/bin/mod.d.ts +0 -3
- package/bin/mod.js +0 -14
- package/bin/setup.d.ts +0 -144
- package/bin/setup.js +0 -90
- package/bin/types.d.ts +0 -2
- package/bin/types.js +0 -0
package/bin/impl.js
DELETED
|
@@ -1,605 +0,0 @@
|
|
|
1
|
-
import os from "node:os";
|
|
2
|
-
import path from "@reliverse/pathkit";
|
|
3
|
-
import { re } from "@reliverse/relico";
|
|
4
|
-
import fs from "@reliverse/relifso";
|
|
5
|
-
import { loadConfig } from "c12";
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_RELINKA_CONFIG,
|
|
8
|
-
ENABLE_DEV_DEBUG,
|
|
9
|
-
EXIT_GUARD
|
|
10
|
-
} from "./setup.js";
|
|
11
|
-
function isUnicodeSupported() {
|
|
12
|
-
if (process.env.TERM_PROGRAM === "vscode" || process.env.WT_SESSION || process.env.TERM_PROGRAM === "iTerm.app" || process.env.TERM_PROGRAM === "hyper" || process.env.TERMINAL_EMULATOR === "JetBrains-JediTerm" || process.env.ConEmuTask === "{cmd::Cmder}" || process.env.TERM === "xterm-256color") {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
if (process.platform === "win32") {
|
|
16
|
-
const osRelease = os.release();
|
|
17
|
-
const match = /(\d+)\.(\d+)/.exec(osRelease);
|
|
18
|
-
if (match && Number.parseInt(match[1] ?? "0", 10) >= 10) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (process.env.TERM_PROGRAM === "mintty") {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
let currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
29
|
-
let isConfigInitialized = false;
|
|
30
|
-
let resolveRelinkaConfig;
|
|
31
|
-
let userTerminalCwd;
|
|
32
|
-
export const loadRelinkaConfig = new Promise((res) => {
|
|
33
|
-
resolveRelinkaConfig = res;
|
|
34
|
-
});
|
|
35
|
-
export async function relinkaConfig(options = {}) {
|
|
36
|
-
if (!userTerminalCwd) {
|
|
37
|
-
userTerminalCwd = process.cwd();
|
|
38
|
-
}
|
|
39
|
-
const config = await loadRelinkaConfig;
|
|
40
|
-
if (options.supportFreshLogFile && isFreshLogFileEnabled(config)) {
|
|
41
|
-
try {
|
|
42
|
-
const logFilePath = getLogFilePath(config);
|
|
43
|
-
await fs.ensureDir(path.dirname(logFilePath));
|
|
44
|
-
await fs.writeFile(logFilePath, "");
|
|
45
|
-
if (isVerboseEnabled(config)) {
|
|
46
|
-
}
|
|
47
|
-
} catch (_err) {
|
|
48
|
-
if (isVerboseEnabled(config)) {
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return config;
|
|
53
|
-
}
|
|
54
|
-
const logBuffers = /* @__PURE__ */ new Map();
|
|
55
|
-
const activeTimers = [];
|
|
56
|
-
let bufferFlushTimer = null;
|
|
57
|
-
let lastCleanupTime = 0;
|
|
58
|
-
let cleanupScheduled = false;
|
|
59
|
-
async function initializeConfig() {
|
|
60
|
-
try {
|
|
61
|
-
let result;
|
|
62
|
-
try {
|
|
63
|
-
result = await loadConfig({
|
|
64
|
-
name: "dler",
|
|
65
|
-
// name: "relinka",
|
|
66
|
-
cwd: process.cwd(),
|
|
67
|
-
dotenv: false,
|
|
68
|
-
packageJson: false,
|
|
69
|
-
rcFile: false,
|
|
70
|
-
globalRc: false,
|
|
71
|
-
defaults: {}
|
|
72
|
-
});
|
|
73
|
-
if (result.config?.relinka) {
|
|
74
|
-
currentConfig = { ...DEFAULT_RELINKA_CONFIG, ...result.config.relinka };
|
|
75
|
-
if (ENABLE_DEV_DEBUG) {
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
79
|
-
if (ENABLE_DEV_DEBUG) {
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
const relinkaResult = await loadConfig({
|
|
84
|
-
name: "relinka",
|
|
85
|
-
cwd: process.cwd(),
|
|
86
|
-
dotenv: false,
|
|
87
|
-
packageJson: false,
|
|
88
|
-
rcFile: false,
|
|
89
|
-
globalRc: false,
|
|
90
|
-
defaults: DEFAULT_RELINKA_CONFIG
|
|
91
|
-
});
|
|
92
|
-
currentConfig = relinkaResult.config;
|
|
93
|
-
if (ENABLE_DEV_DEBUG) {
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
isConfigInitialized = true;
|
|
97
|
-
resolveRelinkaConfig?.(currentConfig);
|
|
98
|
-
resolveRelinkaConfig = void 0;
|
|
99
|
-
if (ENABLE_DEV_DEBUG) {
|
|
100
|
-
}
|
|
101
|
-
} catch (_err) {
|
|
102
|
-
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
103
|
-
isConfigInitialized = true;
|
|
104
|
-
resolveRelinkaConfig?.(currentConfig);
|
|
105
|
-
resolveRelinkaConfig = void 0;
|
|
106
|
-
} finally {
|
|
107
|
-
setupBufferFlushTimer();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function setupBufferFlushTimer() {
|
|
111
|
-
if (bufferFlushTimer) {
|
|
112
|
-
clearInterval(bufferFlushTimer);
|
|
113
|
-
activeTimers.splice(activeTimers.indexOf(bufferFlushTimer), 1);
|
|
114
|
-
}
|
|
115
|
-
const maxAge = getMaxBufferAge(currentConfig);
|
|
116
|
-
bufferFlushTimer = setInterval(flushDueBuffers, Math.min(maxAge / 2, 2500));
|
|
117
|
-
bufferFlushTimer.unref();
|
|
118
|
-
activeTimers.push(bufferFlushTimer);
|
|
119
|
-
function flushDueBuffers() {
|
|
120
|
-
const now = Date.now();
|
|
121
|
-
for (const [fp, buf] of logBuffers) {
|
|
122
|
-
if (buf.entries.length && now - buf.lastFlush >= maxAge) {
|
|
123
|
-
flushLogBuffer(currentConfig, fp).catch(console.error);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
initializeConfig().catch((_err) => {
|
|
129
|
-
if (!isConfigInitialized) {
|
|
130
|
-
currentConfig = { ...DEFAULT_RELINKA_CONFIG };
|
|
131
|
-
isConfigInitialized = true;
|
|
132
|
-
if (resolveRelinkaConfig) {
|
|
133
|
-
resolveRelinkaConfig(currentConfig);
|
|
134
|
-
resolveRelinkaConfig = void 0;
|
|
135
|
-
}
|
|
136
|
-
setupBufferFlushTimer();
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
function isVerboseEnabled(config) {
|
|
140
|
-
return config.verbose ?? DEFAULT_RELINKA_CONFIG.verbose ?? false;
|
|
141
|
-
}
|
|
142
|
-
function isColorEnabled(config) {
|
|
143
|
-
return !(config.disableColors ?? DEFAULT_RELINKA_CONFIG.disableColors);
|
|
144
|
-
}
|
|
145
|
-
function shouldSaveLogs(config) {
|
|
146
|
-
return config.saveLogsToFile ?? DEFAULT_RELINKA_CONFIG.saveLogsToFile ?? false;
|
|
147
|
-
}
|
|
148
|
-
function getMaxLogFiles(config) {
|
|
149
|
-
return config.dirs?.maxLogFiles ?? 0;
|
|
150
|
-
}
|
|
151
|
-
function getBaseLogName(config) {
|
|
152
|
-
const logFileConfig = config.logFile || DEFAULT_RELINKA_CONFIG.logFile || {};
|
|
153
|
-
return logFileConfig.outputPath ?? "logs.log";
|
|
154
|
-
}
|
|
155
|
-
function getBufferSize(config) {
|
|
156
|
-
return config.bufferSize ?? DEFAULT_RELINKA_CONFIG.bufferSize ?? 4096;
|
|
157
|
-
}
|
|
158
|
-
function getMaxBufferAge(config) {
|
|
159
|
-
return config.maxBufferAge ?? DEFAULT_RELINKA_CONFIG.maxBufferAge ?? 5e3;
|
|
160
|
-
}
|
|
161
|
-
function getCleanupInterval(config) {
|
|
162
|
-
return config.cleanupInterval ?? DEFAULT_RELINKA_CONFIG.cleanupInterval ?? 1e4;
|
|
163
|
-
}
|
|
164
|
-
function isFreshLogFileEnabled(config) {
|
|
165
|
-
return config.logFile?.freshLogFile ?? DEFAULT_RELINKA_CONFIG.logFile?.freshLogFile ?? false;
|
|
166
|
-
}
|
|
167
|
-
function isDevEnv() {
|
|
168
|
-
return process.env.NODE_ENV === "development";
|
|
169
|
-
}
|
|
170
|
-
function getDateString(date = /* @__PURE__ */ new Date()) {
|
|
171
|
-
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(
|
|
172
|
-
date.getDate()
|
|
173
|
-
).padStart(2, "0")}`;
|
|
174
|
-
}
|
|
175
|
-
function getTimestamp(config) {
|
|
176
|
-
if (!config.timestamp?.enabled) {
|
|
177
|
-
return "";
|
|
178
|
-
}
|
|
179
|
-
const now = /* @__PURE__ */ new Date();
|
|
180
|
-
const format = config.timestamp?.format || "YYYY-MM-DD HH:mm:ss.SSS";
|
|
181
|
-
return format.replace("YYYY", String(now.getFullYear())).replace("MM", String(now.getMonth() + 1).padStart(2, "0")).replace("DD", String(now.getDate()).padStart(2, "0")).replace("HH", String(now.getHours()).padStart(2, "0")).replace("mm", String(now.getMinutes()).padStart(2, "0")).replace("ss", String(now.getSeconds()).padStart(2, "0")).replace("SSS", String(now.getMilliseconds()).padStart(3, "0"));
|
|
182
|
-
}
|
|
183
|
-
function getLogFilePath(config) {
|
|
184
|
-
const logFileConfig = config.logFile || DEFAULT_RELINKA_CONFIG.logFile || {};
|
|
185
|
-
const nameWithDate = logFileConfig.nameWithDate || "disable";
|
|
186
|
-
const outputPath = getBaseLogName(config);
|
|
187
|
-
const dir = path.dirname(outputPath);
|
|
188
|
-
let filename = path.basename(outputPath);
|
|
189
|
-
if (nameWithDate !== "disable") {
|
|
190
|
-
const dateString = getDateString();
|
|
191
|
-
if (nameWithDate === "append-before") {
|
|
192
|
-
filename = `${dateString}-${filename}`;
|
|
193
|
-
} else if (nameWithDate === "append-after") {
|
|
194
|
-
const nameWithoutExt = filename.replace(/\.log$/, "");
|
|
195
|
-
filename = `${nameWithoutExt}-${dateString}.log`;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (filename && !filename.endsWith(".log")) {
|
|
199
|
-
filename += ".log";
|
|
200
|
-
}
|
|
201
|
-
const effectiveFilename = filename || "logs.log";
|
|
202
|
-
const finalPath = dir === "." ? effectiveFilename : path.join(dir, effectiveFilename);
|
|
203
|
-
const baseCwd = userTerminalCwd || process.cwd();
|
|
204
|
-
return path.resolve(baseCwd, finalPath);
|
|
205
|
-
}
|
|
206
|
-
function getLevelStyle(config, level) {
|
|
207
|
-
const allLevels = config.levels || DEFAULT_RELINKA_CONFIG.levels || {};
|
|
208
|
-
const levelConfig = allLevels[level];
|
|
209
|
-
if (!levelConfig) {
|
|
210
|
-
return {
|
|
211
|
-
symbol: `[${level.toUpperCase()}]`,
|
|
212
|
-
color: "dim",
|
|
213
|
-
spacing: 3
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
if (level === "null") {
|
|
217
|
-
return {
|
|
218
|
-
symbol: "",
|
|
219
|
-
color: levelConfig.color,
|
|
220
|
-
spacing: 0
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
const { symbol, fallbackSymbol, color, spacing } = levelConfig;
|
|
224
|
-
const effectiveSymbol = isUnicodeSupported() ? symbol : fallbackSymbol || `[${level.toUpperCase()}]`;
|
|
225
|
-
return {
|
|
226
|
-
symbol: effectiveSymbol,
|
|
227
|
-
color,
|
|
228
|
-
spacing: spacing ?? 3
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
function formatDetails(details) {
|
|
232
|
-
if (details === void 0) {
|
|
233
|
-
return "";
|
|
234
|
-
}
|
|
235
|
-
if (details instanceof Error) {
|
|
236
|
-
return `
|
|
237
|
-
Stack Trace: ${details.stack || details.message}`;
|
|
238
|
-
}
|
|
239
|
-
if (typeof details === "object" && details !== null) {
|
|
240
|
-
try {
|
|
241
|
-
return ` ${JSON.stringify(details, null, 2)}`;
|
|
242
|
-
} catch {
|
|
243
|
-
return " [object Object]";
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return ` ${String(details)}`;
|
|
247
|
-
}
|
|
248
|
-
function formatLogMessage(config, level, msg, details) {
|
|
249
|
-
const timestamp = getTimestamp(config);
|
|
250
|
-
const detailsStr = formatDetails(details);
|
|
251
|
-
const { symbol, spacing } = getLevelStyle(config, level);
|
|
252
|
-
const symbolWithSpaces = symbol ? `${symbol}${" ".repeat(spacing)}` : "";
|
|
253
|
-
const prefix = timestamp ? `[${timestamp}] ` : "";
|
|
254
|
-
let content = `${prefix}${symbolWithSpaces}${msg}${detailsStr}`;
|
|
255
|
-
if (level === "box") {
|
|
256
|
-
content = formatBox(content);
|
|
257
|
-
}
|
|
258
|
-
return content;
|
|
259
|
-
}
|
|
260
|
-
const consoleMethodMap = {
|
|
261
|
-
error: console.error,
|
|
262
|
-
fatal: console.error,
|
|
263
|
-
warn: console.warn,
|
|
264
|
-
info: console.info,
|
|
265
|
-
success: console.log,
|
|
266
|
-
verbose: console.log,
|
|
267
|
-
log: console.log,
|
|
268
|
-
internal: console.log,
|
|
269
|
-
step: console.log,
|
|
270
|
-
box: console.log,
|
|
271
|
-
message: console.log,
|
|
272
|
-
null: console.log
|
|
273
|
-
};
|
|
274
|
-
function logToConsole(config, level, formattedMessage) {
|
|
275
|
-
if (!isColorEnabled(config)) {
|
|
276
|
-
const method2 = consoleMethodMap[level] || console.log;
|
|
277
|
-
method2(formattedMessage);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
const { color } = getLevelStyle(config, level);
|
|
281
|
-
const colorFn = re[color] || re.dim;
|
|
282
|
-
const method = consoleMethodMap[level] || console.log;
|
|
283
|
-
method(`${colorFn(formattedMessage)}\x1B[0m`);
|
|
284
|
-
}
|
|
285
|
-
async function getLogFilesSortedByDate(config) {
|
|
286
|
-
const logDirectoryPath = userTerminalCwd || process.cwd();
|
|
287
|
-
try {
|
|
288
|
-
const files = await fs.readdir(logDirectoryPath);
|
|
289
|
-
const logFiles = [];
|
|
290
|
-
for (const file of files) {
|
|
291
|
-
const filePath = path.join(logDirectoryPath, file);
|
|
292
|
-
try {
|
|
293
|
-
const stats = await fs.stat(filePath);
|
|
294
|
-
if (stats.isFile() && file.endsWith(".log")) {
|
|
295
|
-
logFiles.push(file);
|
|
296
|
-
} else if (stats.isDirectory()) {
|
|
297
|
-
try {
|
|
298
|
-
const subFiles = await fs.readdir(filePath);
|
|
299
|
-
for (const subFile of subFiles) {
|
|
300
|
-
if (subFile.endsWith(".log")) {
|
|
301
|
-
logFiles.push(path.join(file, subFile));
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
} catch (_subDirErr) {
|
|
305
|
-
if (isVerboseEnabled(config)) {
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
} catch (_err) {
|
|
310
|
-
if (isVerboseEnabled(config)) {
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (logFiles.length === 0) {
|
|
315
|
-
return [];
|
|
316
|
-
}
|
|
317
|
-
const fileInfoPromises = logFiles.map(async (fileName) => {
|
|
318
|
-
const filePath = path.join(logDirectoryPath, fileName);
|
|
319
|
-
try {
|
|
320
|
-
const stats = await fs.stat(filePath);
|
|
321
|
-
if (stats.isFile()) {
|
|
322
|
-
return { path: filePath, mtime: stats.mtime.getTime() };
|
|
323
|
-
}
|
|
324
|
-
return null;
|
|
325
|
-
} catch (_err) {
|
|
326
|
-
if (isVerboseEnabled(config)) {
|
|
327
|
-
}
|
|
328
|
-
return null;
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
const logFileInfos = (await Promise.all(fileInfoPromises)).filter(
|
|
332
|
-
(info) => info !== null
|
|
333
|
-
);
|
|
334
|
-
return logFileInfos.sort((a, b) => b.mtime - a.mtime);
|
|
335
|
-
} catch (_readErr) {
|
|
336
|
-
if (isVerboseEnabled(config)) {
|
|
337
|
-
}
|
|
338
|
-
return [];
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
async function deleteFiles(filePaths, config) {
|
|
342
|
-
if (filePaths.length === 0) {
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
const results = await Promise.allSettled(filePaths.map((filePath) => fs.unlink(filePath)));
|
|
346
|
-
const errors = results.map(
|
|
347
|
-
(result, index) => result.status === "rejected" ? { path: filePaths[index], error: result.reason } : null
|
|
348
|
-
).filter(Boolean);
|
|
349
|
-
if (errors.length > 0 && isVerboseEnabled(config)) {
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
let sigintHandler;
|
|
353
|
-
let sigtermHandler;
|
|
354
|
-
export async function relinkaShutdown() {
|
|
355
|
-
activeTimers.forEach((timer) => {
|
|
356
|
-
clearTimeout(timer);
|
|
357
|
-
});
|
|
358
|
-
activeTimers.length = 0;
|
|
359
|
-
cleanupScheduled = false;
|
|
360
|
-
if (sigintHandler) {
|
|
361
|
-
process.off("SIGINT", sigintHandler);
|
|
362
|
-
}
|
|
363
|
-
if (sigtermHandler) {
|
|
364
|
-
process.off("SIGTERM", sigtermHandler);
|
|
365
|
-
}
|
|
366
|
-
await flushAllLogBuffers();
|
|
367
|
-
}
|
|
368
|
-
async function cleanupOldLogFiles(config) {
|
|
369
|
-
const maxFiles = getMaxLogFiles(config);
|
|
370
|
-
const cleanupInterval = getCleanupInterval(config);
|
|
371
|
-
if (!shouldSaveLogs(config) || maxFiles <= 0) {
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
const now = Date.now();
|
|
375
|
-
if (now - lastCleanupTime < cleanupInterval) {
|
|
376
|
-
if (!cleanupScheduled) {
|
|
377
|
-
cleanupScheduled = true;
|
|
378
|
-
const delay = cleanupInterval - (now - lastCleanupTime);
|
|
379
|
-
const timer = setTimeout(() => {
|
|
380
|
-
cleanupScheduled = false;
|
|
381
|
-
lastCleanupTime = Date.now();
|
|
382
|
-
const index = activeTimers.indexOf(timer);
|
|
383
|
-
if (index !== -1) {
|
|
384
|
-
activeTimers.splice(index, 1);
|
|
385
|
-
}
|
|
386
|
-
cleanupOldLogFiles(config).catch((_err) => {
|
|
387
|
-
if (isVerboseEnabled(config)) {
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
}, delay);
|
|
391
|
-
timer.unref();
|
|
392
|
-
activeTimers.push(timer);
|
|
393
|
-
}
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
lastCleanupTime = now;
|
|
397
|
-
try {
|
|
398
|
-
const sortedLogFiles = await getLogFilesSortedByDate(config);
|
|
399
|
-
if (sortedLogFiles.length > maxFiles) {
|
|
400
|
-
const filesToDelete = sortedLogFiles.slice(maxFiles).map((f) => f.path);
|
|
401
|
-
if (filesToDelete.length > 0) {
|
|
402
|
-
await deleteFiles(filesToDelete, config);
|
|
403
|
-
if (isVerboseEnabled(config)) {
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
} catch (_err) {
|
|
408
|
-
if (isVerboseEnabled(config)) {
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
async function appendToLogFileImmediate(config, absoluteLogFilePath, logMessage) {
|
|
413
|
-
try {
|
|
414
|
-
await fs.ensureDir(path.dirname(absoluteLogFilePath));
|
|
415
|
-
await fs.appendFile(absoluteLogFilePath, `${logMessage}
|
|
416
|
-
`);
|
|
417
|
-
} catch (_err) {
|
|
418
|
-
if (isVerboseEnabled(config)) {
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
let logWriteChain = Promise.resolve();
|
|
423
|
-
function addToLogBuffer(config, filePath, message) {
|
|
424
|
-
const bufferSize = getBufferSize(config);
|
|
425
|
-
let buffer = logBuffers.get(filePath);
|
|
426
|
-
if (!buffer) {
|
|
427
|
-
buffer = {
|
|
428
|
-
filePath,
|
|
429
|
-
entries: [],
|
|
430
|
-
size: 0,
|
|
431
|
-
lastFlush: Date.now()
|
|
432
|
-
};
|
|
433
|
-
logBuffers.set(filePath, buffer);
|
|
434
|
-
}
|
|
435
|
-
buffer.entries.push(message);
|
|
436
|
-
buffer.size += message.length + 1;
|
|
437
|
-
if (buffer.size >= bufferSize) {
|
|
438
|
-
return flushLogBuffer(config, filePath);
|
|
439
|
-
}
|
|
440
|
-
return Promise.resolve();
|
|
441
|
-
}
|
|
442
|
-
function flushLogBuffer(config, filePath) {
|
|
443
|
-
const buffer = logBuffers.get(filePath);
|
|
444
|
-
if (!buffer || buffer.entries.length === 0) {
|
|
445
|
-
return Promise.resolve();
|
|
446
|
-
}
|
|
447
|
-
const content = `${buffer.entries.join("\n")}
|
|
448
|
-
`;
|
|
449
|
-
buffer.entries = [];
|
|
450
|
-
buffer.size = 0;
|
|
451
|
-
buffer.lastFlush = Date.now();
|
|
452
|
-
logWriteChain = logWriteChain.then(() => {
|
|
453
|
-
return appendToLogFileImmediate(config, filePath, content);
|
|
454
|
-
}).catch((_err) => {
|
|
455
|
-
if (isVerboseEnabled(config)) {
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
return logWriteChain;
|
|
459
|
-
}
|
|
460
|
-
function queueLogWrite(config, absoluteLogFilePath, logMessage) {
|
|
461
|
-
return addToLogBuffer(config, absoluteLogFilePath, logMessage);
|
|
462
|
-
}
|
|
463
|
-
export async function flushAllLogBuffers() {
|
|
464
|
-
const filePaths = Array.from(logBuffers.keys());
|
|
465
|
-
await Promise.all(filePaths.map((path2) => flushLogBuffer(currentConfig, path2)));
|
|
466
|
-
}
|
|
467
|
-
function internalFatalLogAndThrow(message, ...args) {
|
|
468
|
-
const formatted = formatLogMessage(currentConfig, "fatal", message, args);
|
|
469
|
-
logToConsole(currentConfig, "fatal", formatted);
|
|
470
|
-
if (shouldSaveLogs(currentConfig)) {
|
|
471
|
-
try {
|
|
472
|
-
const absoluteLogFilePath = getLogFilePath(currentConfig);
|
|
473
|
-
fs.ensureDirSync(path.dirname(absoluteLogFilePath));
|
|
474
|
-
fs.appendFileSync(absoluteLogFilePath, `${formatted}
|
|
475
|
-
`);
|
|
476
|
-
} catch (_err) {
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
if (isDevEnv()) {
|
|
480
|
-
debugger;
|
|
481
|
-
}
|
|
482
|
-
throw new Error(`Fatal error: ${message}`);
|
|
483
|
-
}
|
|
484
|
-
export function shouldNeverHappen(message, ...args) {
|
|
485
|
-
return internalFatalLogAndThrow(message, ...args);
|
|
486
|
-
}
|
|
487
|
-
export function truncateString(msg, maxLength = 100) {
|
|
488
|
-
if (!msg || msg.length <= maxLength) {
|
|
489
|
-
return msg;
|
|
490
|
-
}
|
|
491
|
-
return `${msg.slice(0, maxLength - 1)}\u2026`;
|
|
492
|
-
}
|
|
493
|
-
export function casesHandled(unexpectedCase) {
|
|
494
|
-
debugger;
|
|
495
|
-
throw new Error(
|
|
496
|
-
`A case was not handled for value: ${truncateString(String(unexpectedCase ?? "unknown"))}`
|
|
497
|
-
);
|
|
498
|
-
}
|
|
499
|
-
function registerExitHandlers() {
|
|
500
|
-
if (globalThis[EXIT_GUARD]) {
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
globalThis[EXIT_GUARD] = true;
|
|
504
|
-
process.once("beforeExit", () => {
|
|
505
|
-
void flushAllLogBuffers();
|
|
506
|
-
});
|
|
507
|
-
sigintHandler = () => {
|
|
508
|
-
void flushAllLogBuffers().finally(() => process.exit(0));
|
|
509
|
-
};
|
|
510
|
-
sigtermHandler = () => {
|
|
511
|
-
void flushAllLogBuffers().finally(() => process.exit(0));
|
|
512
|
-
};
|
|
513
|
-
process.once("SIGINT", sigintHandler);
|
|
514
|
-
process.once("SIGTERM", sigtermHandler);
|
|
515
|
-
}
|
|
516
|
-
registerExitHandlers();
|
|
517
|
-
export const relinka = ((type, message, ...args) => {
|
|
518
|
-
if (type === "clear") {
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
if (message === "") {
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
const levelName = type.toLowerCase();
|
|
525
|
-
if (levelName === "fatal") {
|
|
526
|
-
return internalFatalLogAndThrow(message, ...args);
|
|
527
|
-
}
|
|
528
|
-
if (levelName === "verbose" && !isVerboseEnabled(currentConfig)) {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
const details = args.length > 1 ? args : args[0];
|
|
532
|
-
const formatted = formatLogMessage(currentConfig, levelName, message, details);
|
|
533
|
-
logToConsole(currentConfig, levelName, formatted);
|
|
534
|
-
if (shouldSaveLogs(currentConfig) && levelName !== "fatal") {
|
|
535
|
-
const absoluteLogFilePath = getLogFilePath(currentConfig);
|
|
536
|
-
queueLogWrite(currentConfig, absoluteLogFilePath, formatted).catch((_err) => {
|
|
537
|
-
if (isVerboseEnabled(currentConfig)) {
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
if (getMaxLogFiles(currentConfig) > 0) {
|
|
541
|
-
cleanupOldLogFiles(currentConfig).catch((_err) => {
|
|
542
|
-
if (isVerboseEnabled(currentConfig)) {
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
relinka.error = (message, ...args) => relinka("error", message, ...args);
|
|
549
|
-
relinka.fatal = (message, ...args) => relinka("fatal", message, ...args);
|
|
550
|
-
relinka.info = (message, ...args) => relinka("info", message, ...args);
|
|
551
|
-
relinka.success = (message, ...args) => relinka("success", message, ...args);
|
|
552
|
-
relinka.verbose = (message, ...args) => relinka("verbose", message, ...args);
|
|
553
|
-
relinka.warn = (message, ...args) => relinka("warn", message, ...args);
|
|
554
|
-
relinka.log = (message, ...args) => relinka("log", message, ...args);
|
|
555
|
-
relinka.internal = (message, ...args) =>
|
|
556
|
-
relinka.null = (message, ...args) => relinka("null", message, ...args);
|
|
557
|
-
relinka.step = (message, ...args) => relinka("step", message, ...args);
|
|
558
|
-
relinka.box = (message, ...args) => relinka("box", message, ...args);
|
|
559
|
-
relinka.clear = () => relinka("clear", "");
|
|
560
|
-
relinka.message = (message, ...args) => relinka("message", message, ...args);
|
|
561
|
-
export async function relinkaAsync(type, message, ...args) {
|
|
562
|
-
if (message === "") {
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
await relinkaConfig({ supportFreshLogFile: false });
|
|
566
|
-
const levelName = type.toLowerCase();
|
|
567
|
-
if (levelName === "fatal") {
|
|
568
|
-
shouldNeverHappen(message, ...args);
|
|
569
|
-
}
|
|
570
|
-
if (levelName === "verbose" && !isVerboseEnabled(currentConfig)) {
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
const details = args.length > 1 ? args : args[0];
|
|
574
|
-
const formatted = formatLogMessage(currentConfig, levelName, message, details);
|
|
575
|
-
logToConsole(currentConfig, levelName, formatted);
|
|
576
|
-
if (shouldSaveLogs(currentConfig)) {
|
|
577
|
-
const absoluteLogFilePath = getLogFilePath(currentConfig);
|
|
578
|
-
try {
|
|
579
|
-
await queueLogWrite(currentConfig, absoluteLogFilePath, formatted);
|
|
580
|
-
if (getMaxLogFiles(currentConfig) > 0) {
|
|
581
|
-
await cleanupOldLogFiles(currentConfig);
|
|
582
|
-
}
|
|
583
|
-
} catch (_err) {
|
|
584
|
-
if (isVerboseEnabled(currentConfig)) {
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
export function defineConfig(config) {
|
|
590
|
-
return config;
|
|
591
|
-
}
|
|
592
|
-
export function formatBox(text) {
|
|
593
|
-
const lines = text.split("\n");
|
|
594
|
-
const maxWidth = Math.max(...lines.map((line) => line.length));
|
|
595
|
-
const width = maxWidth + 4;
|
|
596
|
-
const top = `\u250C${"\u2500".repeat(width)}\u2510`;
|
|
597
|
-
const bottom = `\u2514${"\u2500".repeat(width)}\u2518`;
|
|
598
|
-
const content = lines.map((line) => {
|
|
599
|
-
const padding = width - line.length;
|
|
600
|
-
return `\u2502 ${line}${" ".repeat(padding - 2)}\u2502`;
|
|
601
|
-
}).join("\n");
|
|
602
|
-
return `${top}
|
|
603
|
-
${content}
|
|
604
|
-
${bottom}`;
|
|
605
|
-
}
|
package/bin/mod.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export { log, logger, message, step } from "./alias.js";
|
|
2
|
-
export { casesHandled, defineConfig, flushAllLogBuffers, formatBox, loadRelinkaConfig, relinka, relinkaAsync, relinkaConfig, relinkaShutdown, shouldNeverHappen, truncateString, } from "./impl.js";
|
|
3
|
-
export type { LogFileInfo, LogLevel, LogLevelConfig, LogLevelsConfig, RelinkaConfig, RelinkaConfigOptions, RelinkaDirsConfig, RelinkaFunction, } from "./setup.js";
|
package/bin/mod.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export { log, logger, message, step } from "./alias.js";
|
|
2
|
-
export {
|
|
3
|
-
casesHandled,
|
|
4
|
-
defineConfig,
|
|
5
|
-
flushAllLogBuffers,
|
|
6
|
-
formatBox,
|
|
7
|
-
loadRelinkaConfig,
|
|
8
|
-
relinka,
|
|
9
|
-
relinkaAsync,
|
|
10
|
-
relinkaConfig,
|
|
11
|
-
relinkaShutdown,
|
|
12
|
-
shouldNeverHappen,
|
|
13
|
-
truncateString
|
|
14
|
-
} from "./impl.js";
|