everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
84 lines (82 loc) • 3.39 kB
JavaScript
import { stripAnsi } from "./dev-log-pipeline.mjs";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { join } from "node:path";
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
//#region src/dev-logs.ts
function getBosDir(configDir) {
return join(configDir, ".bos");
}
function getLogsDir(configDir) {
return join(getBosDir(configDir), "logs");
}
function formatLogLine(entry) {
const ts = new Date(entry.timestamp).toISOString();
const prefix = entry.isError ? "ERR" : "OUT";
const clean = stripAnsi(entry.line);
const head = `[${ts}] [${entry.source}] [${prefix}] `;
const pad = " ".repeat(head.length);
const [first, ...rest] = clean.split("\n");
return [`${head}${first}`, ...rest.map((line) => `${pad}${line}`)].join("\n");
}
async function createDevLogger(configDir, description) {
const dir = getLogsDir(configDir);
if (!existsSync(dir)) await mkdir(dir, { recursive: true });
const now = /* @__PURE__ */ new Date();
const ts = now.toISOString().replace(/[:.]/g, "-").slice(0, 19);
const logFile = join(dir, `dev-${ts}-${process.pid}.log`);
const latestFile = join(dir, `dev-latest-${process.pid}.log`);
const header = `# everything-dev dev session: ${description}\n# Started: ${now.toISOString()}\n\n`;
await writeFile(logFile, header, "utf8");
await writeFile(latestFile, header, "utf8");
let chain = Promise.resolve();
const enqueue = (fn) => {
chain = chain.then(fn, fn);
return chain;
};
return {
logFile,
latestFile,
write: (entry) => enqueue(async () => {
const line = `${formatLogLine(entry)}\n`;
await appendFile(logFile, line);
await appendFile(latestFile, line);
}),
readLatest: async (opts) => {
const text = await readFile(latestFile, "utf8").catch(() => "");
const tail = opts?.tail;
if (!tail || tail <= 0) return text;
const lines = text.split("\n");
return lines.slice(Math.max(0, lines.length - tail)).join("\n");
}
};
}
function resolveDevLatestFile(configDir) {
const dir = getLogsDir(configDir);
const latestFile = join(dir, "dev-latest.log");
if (existsSync(latestFile)) return latestFile;
const STARTED_RE = /^# Started: (.+)$/m;
const startedMsOf = (name) => {
const header = readFileSync(join(dir, name), "utf8").slice(0, 256);
const started = STARTED_RE.exec(header)?.[1];
const parsed = started ? Date.parse(started) : NaN;
return Number.isNaN(parsed) ? statSync(join(dir, name)).mtimeMs : parsed;
};
const pidOf = (name) => Number(/^dev-latest-(\d+)\.log$/.exec(name)?.[1] ?? 0);
const candidates = readdirSync(dir).filter((name) => /^dev-latest-\d+\.log$/.test(name)).map((name) => ({
name,
startedMs: startedMsOf(name),
pid: pidOf(name)
})).sort((a, b) => b.startedMs - a.startedMs || b.pid - a.pid || a.name.localeCompare(b.name));
return candidates.length > 0 ? join(dir, candidates[0].name) : latestFile;
}
async function readDevLatestLog(configDir, opts) {
const latestFile = resolveDevLatestFile(configDir);
const text = await readFile(latestFile, "utf8").catch(() => "");
const tail = opts?.tail;
if (!tail || tail <= 0) return text;
const lines = text.split("\n");
return lines.slice(Math.max(0, lines.length - tail)).join("\n");
}
//#endregion
export { createDevLogger, formatLogLine, getBosDir, getLogsDir, readDevLatestLog, resolveDevLatestFile };
//# sourceMappingURL=dev-logs.mjs.map