import { readFile, rm, mkdtemp } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { appLogFilePath, clearAppLogs, listAppLogs, recordAppLog } from "@/lib/server/log-manager"; let runtimeDir = ""; let previousRuntimeDir: string | undefined; let previousLogDir: string | undefined; describe("server log manager", () => { beforeEach(async () => { runtimeDir = await mkdtemp(join(tmpdir(), "zhinian-logs-")); previousRuntimeDir = process.env.ZHINIAN_RUNTIME_DIR; previousLogDir = process.env.ZHINIAN_LOG_DIR; process.env.ZHINIAN_RUNTIME_DIR = runtimeDir; delete process.env.ZHINIAN_LOG_DIR; }); afterEach(async () => { restoreEnv("ZHINIAN_RUNTIME_DIR", previousRuntimeDir); restoreEnv("ZHINIAN_LOG_DIR", previousLogDir); await rm(runtimeDir, { force: true, recursive: true }); }); it("records, filters, and clears server logs", async () => { await recordAppLog({ level: "error", source: "api.test", message: "EvoLink API_KEY=super-secret failed", error: new Error("token=abc123 failed"), status: 500, request: new Request("http://local.test/api/test?x=1", { method: "POST" }), details: { Authorization: "Bearer secret-token", nested: { password: "123456", prompt: "商品海报" } } }); await recordAppLog({ level: "warning", source: "worker.test", message: "retry scheduled" }); const errors = await listAppLogs({ level: "error", q: "evolink" }); expect(errors).toHaveLength(1); expect(errors[0]).toMatchObject({ level: "error", source: "api.test", status: 500, method: "POST", path: "/api/test?x=1" }); expect(JSON.stringify(errors[0])).not.toContain("super-secret"); expect(JSON.stringify(errors[0])).not.toContain("secret-token"); expect(JSON.stringify(errors[0])).not.toContain("123456"); const raw = await readFile(appLogFilePath(), "utf8"); expect(raw).toContain("retry scheduled"); await clearAppLogs(); expect(await listAppLogs()).toHaveLength(0); }); }); function restoreEnv(name: string, value: string | undefined) { if (value === undefined) { delete process.env[name]; return; } process.env[name] = value; }