dsh-log 0.2.0
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/INTEGRATION.md +216 -0
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/client.js +460 -0
- package/dist/config.js +221 -0
- package/dist/host.js +55 -0
- package/dist/node.js +124 -0
- package/dist/phones.js +266 -0
- package/dist/store.js +421 -0
- package/event-list.template.json +6 -0
- package/package.json +35 -0
package/dist/store.js
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
// AUTO-GENERATED by node packages/dsh-log/build.mjs — DO NOT EDIT. Source: packages/dsh-log/src/store.ts
|
|
2
|
+
import {
|
|
3
|
+
LOG_DEBOUNCE_MS,
|
|
4
|
+
LEGACY_LOG_DIR_NAME,
|
|
5
|
+
LEGACY_SWITCH_FILE_NAME,
|
|
6
|
+
resolveHostLogConfig,
|
|
7
|
+
resolveLogFileName,
|
|
8
|
+
formatDailyFileName
|
|
9
|
+
} from "./config.js";
|
|
10
|
+
import { createLogPhones } from "./phones.js";
|
|
11
|
+
const LOG_DIR_NAME = LEGACY_LOG_DIR_NAME;
|
|
12
|
+
const LOG_SWITCH_FILE = LEGACY_SWITCH_FILE_NAME;
|
|
13
|
+
const formatLogFileName = formatDailyFileName;
|
|
14
|
+
function hashText(text) {
|
|
15
|
+
let h = 5381;
|
|
16
|
+
const s = String(text || "");
|
|
17
|
+
for (let i = 0; i < s.length; i++) h = (h << 5) + h + s.charCodeAt(i) >>> 0;
|
|
18
|
+
return ("0000000" + h.toString(16)).slice(-8);
|
|
19
|
+
}
|
|
20
|
+
function createLogStore(deps, configInput) {
|
|
21
|
+
const input = deps || {};
|
|
22
|
+
const fs = input.fs;
|
|
23
|
+
const timer = input.timer;
|
|
24
|
+
const getCacheDir = input.getCacheDir;
|
|
25
|
+
const getPlatform = input.getPlatform;
|
|
26
|
+
const defaultCwd = input.DEFAULT_CWD || "";
|
|
27
|
+
const config = resolveHostLogConfig(
|
|
28
|
+
configInput === void 0 ? { pluginId: "wf" } : configInput
|
|
29
|
+
);
|
|
30
|
+
let queue = [];
|
|
31
|
+
let dropped = 0;
|
|
32
|
+
let switchEnabled = false;
|
|
33
|
+
let switchSampleRate = 1;
|
|
34
|
+
let switchLoaded = false;
|
|
35
|
+
let flushTimer = null;
|
|
36
|
+
let flushing = false;
|
|
37
|
+
let flushQueued = false;
|
|
38
|
+
let pendingPersistFail = null;
|
|
39
|
+
let persistFailOutstanding = false;
|
|
40
|
+
function notePersistFail(op, reason, dir) {
|
|
41
|
+
if (!pendingPersistFail) pendingPersistFail = { op, reason, dir: String(dir || "") };
|
|
42
|
+
try {
|
|
43
|
+
scheduleFlush(false);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
void e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
let headerInfo = null;
|
|
49
|
+
function currentPid() {
|
|
50
|
+
try {
|
|
51
|
+
const g = globalThis;
|
|
52
|
+
return (g.process && typeof g.process.pid === "number" ? g.process.pid : 0) || 0;
|
|
53
|
+
} catch (e) {
|
|
54
|
+
void e;
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function currentStartedAt() {
|
|
59
|
+
try {
|
|
60
|
+
return headerInfo && headerInfo.startedAt ? headerInfo.startedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
61
|
+
} catch (e) {
|
|
62
|
+
void e;
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function later(fn, ms) {
|
|
67
|
+
try {
|
|
68
|
+
if (timer !== void 0 && timer !== null && typeof timer.timeout === "function") {
|
|
69
|
+
return timer.timeout(fn, ms);
|
|
70
|
+
}
|
|
71
|
+
} catch (e) {
|
|
72
|
+
void e;
|
|
73
|
+
}
|
|
74
|
+
return setTimeout(fn, ms);
|
|
75
|
+
}
|
|
76
|
+
function joinPath(a, b) {
|
|
77
|
+
return String(a).replace(/\/+$/, "") + "/" + String(b).replace(/^\/+/, "");
|
|
78
|
+
}
|
|
79
|
+
async function joinLogPath(dir, name) {
|
|
80
|
+
try {
|
|
81
|
+
const platform = typeof getPlatform === "function" ? await getPlatform() : null;
|
|
82
|
+
if (platform && platform.path && typeof platform.path.join === "function") {
|
|
83
|
+
return platform.path.join(dir, name);
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {
|
|
86
|
+
void e;
|
|
87
|
+
}
|
|
88
|
+
return joinPath(dir, name);
|
|
89
|
+
}
|
|
90
|
+
async function resolveTarget(pathStr) {
|
|
91
|
+
try {
|
|
92
|
+
const platform = typeof getPlatform === "function" ? await getPlatform() : null;
|
|
93
|
+
if (platform && platform.fs && typeof platform.fs.resolve === "function") {
|
|
94
|
+
return await platform.fs.resolve(pathStr);
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
void e;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
if (fs !== void 0 && fs !== null && typeof fs.resolve === "function") {
|
|
101
|
+
return await fs.resolve(pathStr);
|
|
102
|
+
}
|
|
103
|
+
} catch (e2) {
|
|
104
|
+
void e2;
|
|
105
|
+
}
|
|
106
|
+
return pathStr;
|
|
107
|
+
}
|
|
108
|
+
async function readTarget(target) {
|
|
109
|
+
if (fs !== void 0 && fs !== null && typeof fs.readText === "function") {
|
|
110
|
+
return await fs.readText(target);
|
|
111
|
+
}
|
|
112
|
+
const platform = typeof getPlatform === "function" ? await getPlatform() : null;
|
|
113
|
+
if (platform && platform.fs && typeof platform.fs.readText === "function") {
|
|
114
|
+
return await platform.fs.readText(target);
|
|
115
|
+
}
|
|
116
|
+
throw new Error("\u6587\u4EF6\u670D\u52A1\u4E0D\u53EF\u8BFB");
|
|
117
|
+
}
|
|
118
|
+
async function writeTarget(target, text) {
|
|
119
|
+
if (fs !== void 0 && fs !== null && typeof fs.writeText === "function") {
|
|
120
|
+
return await fs.writeText(target, text);
|
|
121
|
+
}
|
|
122
|
+
const platform = typeof getPlatform === "function" ? await getPlatform() : null;
|
|
123
|
+
if (platform && platform.fs && typeof platform.fs.writeText === "function") {
|
|
124
|
+
return await platform.fs.writeText(target, text);
|
|
125
|
+
}
|
|
126
|
+
throw new Error("\u6587\u4EF6\u670D\u52A1\u4E0D\u53EF\u5199");
|
|
127
|
+
}
|
|
128
|
+
async function ensureLogDir(logDir) {
|
|
129
|
+
try {
|
|
130
|
+
const platform = typeof getPlatform === "function" ? await getPlatform() : null;
|
|
131
|
+
if (platform && platform.fs && typeof platform.fs.mkdir === "function") {
|
|
132
|
+
try {
|
|
133
|
+
await platform.fs.mkdir(logDir);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
void e;
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
} catch (e) {
|
|
140
|
+
void e;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
if (fs !== void 0 && fs !== null && typeof fs.mkdir === "function") await fs.mkdir(logDir);
|
|
144
|
+
} catch (e2) {
|
|
145
|
+
void e2;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function isEnabled(level) {
|
|
149
|
+
if (level === "error" || level === "warn") return true;
|
|
150
|
+
return switchEnabled === true;
|
|
151
|
+
}
|
|
152
|
+
function dropForRoom(level) {
|
|
153
|
+
if (level === "error" || level === "warn") {
|
|
154
|
+
for (let i = 0; i < queue.length; i++) {
|
|
155
|
+
if (queue[i].level !== "error" && queue[i].level !== "warn") {
|
|
156
|
+
queue.splice(i, 1);
|
|
157
|
+
dropped += 1;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
dropped += 1;
|
|
163
|
+
}
|
|
164
|
+
function log(level, event, fields) {
|
|
165
|
+
if (!isEnabled(level)) return;
|
|
166
|
+
if (queue.length >= config.maxQueue) {
|
|
167
|
+
dropForRoom(level);
|
|
168
|
+
if (queue.length >= config.maxQueue) return;
|
|
169
|
+
}
|
|
170
|
+
queue.push({
|
|
171
|
+
ts: Date.now(),
|
|
172
|
+
level,
|
|
173
|
+
event: String(event || ""),
|
|
174
|
+
fields: fields && typeof fields === "object" ? fields : {}
|
|
175
|
+
});
|
|
176
|
+
if (level === "error" || level === "warn") scheduleFlush(true);
|
|
177
|
+
else scheduleFlush(false);
|
|
178
|
+
}
|
|
179
|
+
function scheduleFlush(immediate) {
|
|
180
|
+
if (immediate) {
|
|
181
|
+
if (flushTimer !== null) {
|
|
182
|
+
try {
|
|
183
|
+
clearTimeout(flushTimer);
|
|
184
|
+
} catch (e) {
|
|
185
|
+
void e;
|
|
186
|
+
}
|
|
187
|
+
flushTimer = null;
|
|
188
|
+
}
|
|
189
|
+
later(flushNow, 0);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (flushTimer !== null) return;
|
|
193
|
+
flushTimer = later(flushNow, LOG_DEBOUNCE_MS);
|
|
194
|
+
}
|
|
195
|
+
function flush() {
|
|
196
|
+
if (flushTimer !== null) {
|
|
197
|
+
try {
|
|
198
|
+
clearTimeout(flushTimer);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
void e;
|
|
201
|
+
}
|
|
202
|
+
flushTimer = null;
|
|
203
|
+
}
|
|
204
|
+
later(flushNow, 0);
|
|
205
|
+
return { ok: true };
|
|
206
|
+
}
|
|
207
|
+
async function flushNow() {
|
|
208
|
+
flushTimer = null;
|
|
209
|
+
if (flushing) {
|
|
210
|
+
flushQueued = true;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
flushing = true;
|
|
214
|
+
try {
|
|
215
|
+
while (queue.length > 0) {
|
|
216
|
+
const batch = queue.splice(0, queue.length);
|
|
217
|
+
try {
|
|
218
|
+
if (await writeBatch(batch)) persistFailOutstanding = false;
|
|
219
|
+
} catch (e) {
|
|
220
|
+
void e;
|
|
221
|
+
dropped += batch.length;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} finally {
|
|
225
|
+
flushing = false;
|
|
226
|
+
if (pendingPersistFail) {
|
|
227
|
+
const f = pendingPersistFail;
|
|
228
|
+
pendingPersistFail = null;
|
|
229
|
+
if (!persistFailOutstanding) {
|
|
230
|
+
persistFailOutstanding = true;
|
|
231
|
+
try {
|
|
232
|
+
log("warn", "log.persist.fail", { op: f.op, reason: f.reason, dirHash: hashText(f.dir) });
|
|
233
|
+
} catch (e) {
|
|
234
|
+
void e;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (flushQueued) {
|
|
239
|
+
flushQueued = false;
|
|
240
|
+
if (queue.length > 0) scheduleFlush(false);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function writeBatch(batch) {
|
|
245
|
+
if (!batch || batch.length === 0) return true;
|
|
246
|
+
const lines = [];
|
|
247
|
+
for (let i = 0; i < batch.length; i++) {
|
|
248
|
+
try {
|
|
249
|
+
lines.push(
|
|
250
|
+
JSON.stringify({ ts: batch[i].ts, level: batch[i].level, event: batch[i].event, fields: batch[i].fields })
|
|
251
|
+
);
|
|
252
|
+
} catch (e) {
|
|
253
|
+
void e;
|
|
254
|
+
dropped += 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (lines.length === 0) return true;
|
|
258
|
+
const text = lines.join("\n") + "\n";
|
|
259
|
+
let failDir = "";
|
|
260
|
+
try {
|
|
261
|
+
const dir = typeof getCacheDir === "function" ? await getCacheDir() : null;
|
|
262
|
+
if (!dir) {
|
|
263
|
+
dropped += lines.length;
|
|
264
|
+
notePersistFail("writeBatch", "no-dir", "");
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
const logDir = await joinLogPath(dir, config.logDirName);
|
|
268
|
+
failDir = logDir;
|
|
269
|
+
await ensureLogDir(logDir);
|
|
270
|
+
const fileName = resolveLogFileName(config, /* @__PURE__ */ new Date(), currentPid(), currentStartedAt());
|
|
271
|
+
const target = await resolveTarget(await joinLogPath(logDir, fileName));
|
|
272
|
+
let existing = "";
|
|
273
|
+
try {
|
|
274
|
+
existing = await readTarget(target);
|
|
275
|
+
} catch (eRead) {
|
|
276
|
+
void eRead;
|
|
277
|
+
existing = "";
|
|
278
|
+
}
|
|
279
|
+
await writeTarget(target, String(existing || "") + text);
|
|
280
|
+
return true;
|
|
281
|
+
} catch (eWrite) {
|
|
282
|
+
void eWrite;
|
|
283
|
+
dropped += lines.length;
|
|
284
|
+
notePersistFail("writeBatch", "write-fail", failDir);
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function getDroppedCount() {
|
|
289
|
+
return dropped;
|
|
290
|
+
}
|
|
291
|
+
function getSwitchState() {
|
|
292
|
+
return { enabled: switchEnabled, sampleRate: switchSampleRate };
|
|
293
|
+
}
|
|
294
|
+
async function loadSwitch() {
|
|
295
|
+
if (switchLoaded) return getSwitchState();
|
|
296
|
+
switchLoaded = true;
|
|
297
|
+
try {
|
|
298
|
+
const dir = typeof getCacheDir === "function" ? await getCacheDir() : null;
|
|
299
|
+
if (!dir) return getSwitchState();
|
|
300
|
+
const target = await resolveTarget(await joinLogPath(dir, config.switchFileName));
|
|
301
|
+
const txt = await readTarget(target);
|
|
302
|
+
if (!txt) return getSwitchState();
|
|
303
|
+
const parsed = JSON.parse(txt);
|
|
304
|
+
if (parsed && typeof parsed.enabled === "boolean") switchEnabled = parsed.enabled;
|
|
305
|
+
if (parsed && typeof parsed.sampleRate === "number") switchSampleRate = parsed.sampleRate;
|
|
306
|
+
} catch (e) {
|
|
307
|
+
void e;
|
|
308
|
+
notePersistFail("readBack", "read-fail", "");
|
|
309
|
+
}
|
|
310
|
+
return getSwitchState();
|
|
311
|
+
}
|
|
312
|
+
async function persistSwitch() {
|
|
313
|
+
let failDir = "";
|
|
314
|
+
try {
|
|
315
|
+
const dir = typeof getCacheDir === "function" ? await getCacheDir() : null;
|
|
316
|
+
if (!dir) {
|
|
317
|
+
notePersistFail("persistSwitch", "no-dir", "");
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
failDir = String(dir || "");
|
|
321
|
+
const target = await resolveTarget(await joinLogPath(dir, config.switchFileName));
|
|
322
|
+
await writeTarget(target, JSON.stringify({ enabled: switchEnabled, sampleRate: switchSampleRate }));
|
|
323
|
+
} catch (e) {
|
|
324
|
+
void e;
|
|
325
|
+
notePersistFail("persistSwitch", "write-fail", failDir);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async function setSwitch(enabled, sampleRate) {
|
|
329
|
+
switchEnabled = enabled === true;
|
|
330
|
+
if (typeof sampleRate === "number" && isFinite(sampleRate)) switchSampleRate = sampleRate;
|
|
331
|
+
await persistSwitch();
|
|
332
|
+
return getSwitchState();
|
|
333
|
+
}
|
|
334
|
+
async function writeStartupHeader() {
|
|
335
|
+
try {
|
|
336
|
+
const dir = typeof getCacheDir === "function" ? await getCacheDir() : null;
|
|
337
|
+
const pid = currentPid();
|
|
338
|
+
headerInfo = { pid, startedAt: (/* @__PURE__ */ new Date()).toISOString(), dir: dir || defaultCwd || "" };
|
|
339
|
+
log("info", "host.start", { pid: headerInfo.pid, startedAt: headerInfo.startedAt, dir: headerInfo.dir });
|
|
340
|
+
} catch (e) {
|
|
341
|
+
void e;
|
|
342
|
+
}
|
|
343
|
+
return headerInfo;
|
|
344
|
+
}
|
|
345
|
+
function getHeaderInfo() {
|
|
346
|
+
return headerInfo;
|
|
347
|
+
}
|
|
348
|
+
async function handleLogBatch(args) {
|
|
349
|
+
try {
|
|
350
|
+
const entries = args && Array.isArray(args.entries) ? args.entries : [];
|
|
351
|
+
for (let i = 0; i < entries.length; i++) {
|
|
352
|
+
const item = entries[i] || {};
|
|
353
|
+
try {
|
|
354
|
+
log(item.level, item.event, item.fields);
|
|
355
|
+
} catch (e) {
|
|
356
|
+
void e;
|
|
357
|
+
dropped += 1;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return { ok: true, accepted: entries.length, dropped: getDroppedCount() };
|
|
361
|
+
} catch (e) {
|
|
362
|
+
void e;
|
|
363
|
+
return { ok: true, accepted: 0, dropped: getDroppedCount() };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const phones = createLogPhones({
|
|
367
|
+
fs,
|
|
368
|
+
getCacheDir,
|
|
369
|
+
getPlatform,
|
|
370
|
+
DEFAULT_CWD: defaultCwd,
|
|
371
|
+
config,
|
|
372
|
+
joinPath,
|
|
373
|
+
joinLogPath,
|
|
374
|
+
resolveTarget,
|
|
375
|
+
readTarget,
|
|
376
|
+
writeTarget,
|
|
377
|
+
log,
|
|
378
|
+
getSwitchState,
|
|
379
|
+
getHeaderInfo,
|
|
380
|
+
loadSwitch,
|
|
381
|
+
setSwitch
|
|
382
|
+
});
|
|
383
|
+
async function handleLogExport(args) {
|
|
384
|
+
return phones.handleLogExport(args);
|
|
385
|
+
}
|
|
386
|
+
async function handleLogClear(args) {
|
|
387
|
+
return phones.handleLogClear(args);
|
|
388
|
+
}
|
|
389
|
+
async function handleLogGetSwitch() {
|
|
390
|
+
return phones.handleLogGetSwitch();
|
|
391
|
+
}
|
|
392
|
+
async function handleLogSetSwitch(args) {
|
|
393
|
+
return phones.handleLogSetSwitch(args);
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
config,
|
|
397
|
+
isEnabled,
|
|
398
|
+
log,
|
|
399
|
+
flush,
|
|
400
|
+
flushNow,
|
|
401
|
+
getDroppedCount,
|
|
402
|
+
loadSwitch,
|
|
403
|
+
setSwitch,
|
|
404
|
+
getSwitchState,
|
|
405
|
+
writeStartupHeader,
|
|
406
|
+
getHeaderInfo,
|
|
407
|
+
handleLogBatch,
|
|
408
|
+
handleLogExport,
|
|
409
|
+
handleLogClear,
|
|
410
|
+
handleLogGetSwitch,
|
|
411
|
+
handleLogSetSwitch
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
export {
|
|
415
|
+
LOG_DEBOUNCE_MS,
|
|
416
|
+
LOG_DIR_NAME,
|
|
417
|
+
LOG_SWITCH_FILE,
|
|
418
|
+
createLogStore,
|
|
419
|
+
formatDailyFileName,
|
|
420
|
+
formatLogFileName
|
|
421
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-log",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "可复用的日志系统:宿主落盘引擎(当前插件的日志能力抽成的独立包,地图 #556)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "王辰浩",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
"./host": "./dist/host.js",
|
|
13
|
+
"./client": "./dist/client.js",
|
|
14
|
+
"./node": "./dist/node.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"event-list.template.json",
|
|
19
|
+
"INTEGRATION.md",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
29
|
+
"build": "node build.mjs",
|
|
30
|
+
"test": "node --test tests/host.test.mjs tests/eventList.test.mjs tests/client.test.mjs tests/node.test.mjs"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typescript": "5.6.3"
|
|
34
|
+
}
|
|
35
|
+
}
|