87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
// 远程日志接收器
|
||
// 监听 HTTP 端口,接收日志内容推送(POST /log,JSON 或纯文本),
|
||
// 按日期追加存入 received_logs/ 文件夹。日志内容直接传输,不做文件传输。
|
||
import { createServer } from "node:http";
|
||
import { mkdir, appendFile } from "fs/promises";
|
||
import { existsSync } from "fs";
|
||
import { resolve } from "path";
|
||
|
||
const PORT = parseInt(process.env.RECEIVER_PORT || "3200", 10);
|
||
const LOG_DIR = resolve("received_logs");
|
||
|
||
function now(iso: string): string {
|
||
return iso ? iso : new Date().toISOString();
|
||
}
|
||
|
||
function fmtEntry(p: { level?: string; category?: string; message?: string; line?: string; ts?: string }): string {
|
||
const ts = now(p.ts);
|
||
const level = (p.level || "info").toUpperCase().padEnd(5);
|
||
const category = p.category || "receiver";
|
||
const message = p.message !== undefined ? p.message : "";
|
||
return `[${ts}] [${level}] [${category}] ${message}`;
|
||
}
|
||
|
||
const server = createServer(async (req, res) => {
|
||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
|
||
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
||
|
||
if (req.method === "OPTIONS") { res.writeHead(204); res.end(); return; }
|
||
|
||
const url = new URL(req.url || "/", `http://localhost:${PORT}`);
|
||
|
||
if (req.method === "GET") {
|
||
res.writeHead(200, { "Content-Type": "application/json" });
|
||
res.end(JSON.stringify({ status: "ok", name: "远程日志接收器", receivePath: "POST /log", port: PORT }));
|
||
return;
|
||
}
|
||
|
||
if (req.method === "POST" && (url.pathname === "/log" || url.pathname === "/")) {
|
||
let body = "";
|
||
try {
|
||
for await (const c of req) body += c;
|
||
} catch {
|
||
res.writeHead(400); res.end("bad request"); return;
|
||
}
|
||
|
||
let entry: string;
|
||
let level = "info";
|
||
let category = "receiver";
|
||
try {
|
||
const json = JSON.parse(body);
|
||
if (typeof json === "string") {
|
||
entry = json;
|
||
} else if (json.line) {
|
||
entry = json.line;
|
||
level = json.level || level;
|
||
category = json.category || category;
|
||
} else {
|
||
entry = fmtEntry({ level: json.level, category: json.category, message: json.message, ts: json.ts });
|
||
level = json.level || level;
|
||
category = json.category || category;
|
||
}
|
||
} catch {
|
||
entry = fmtEntry({ level, category, message: body, ts: new Date().toISOString() });
|
||
}
|
||
|
||
try {
|
||
if (!existsSync(LOG_DIR)) await mkdir(LOG_DIR, { recursive: true });
|
||
const ts = new Date().toISOString().slice(0, 10);
|
||
await appendFile(resolve(LOG_DIR, `received-${ts}.log`), entry + "\n", "utf-8");
|
||
res.writeHead(200, { "Content-Type": "application/json" });
|
||
res.end(JSON.stringify({ ok: true }));
|
||
} catch (e) {
|
||
res.writeHead(500, { "Content-Type": "application/json" });
|
||
res.end(JSON.stringify({ ok: false, error: (e as any).message }));
|
||
}
|
||
return;
|
||
}
|
||
|
||
res.writeHead(404);
|
||
res.end("Not Found");
|
||
});
|
||
|
||
server.listen(PORT, () => {
|
||
console.log(`[remote_receiver] 远程日志接收器已启动: http://127.0.0.1:${PORT}/log (存入 ${LOG_DIR})`);
|
||
});
|