diff options
| author | Aiden Cline <[email protected]> | 2026-04-11 22:07:34 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-11 22:07:34 -0500 |
| commit | fc01cad2b842a4025e7a04dc79130e843b1d56b7 (patch) | |
| tree | af7b5694b69e4e22dc6c4a249d92f3d29a6ead4b | |
| parent | c1ddc0ea2d6733925569a6a8f937ce9aa6b04cdd (diff) | |
| download | opencode-fc01cad2b842a4025e7a04dc79130e843b1d56b7.tar.gz opencode-fc01cad2b842a4025e7a04dc79130e843b1d56b7.zip | |
fix: ensure logger cleanup properly orders list before deleting files (#22101)
| -rw-r--r-- | packages/opencode/src/util/log.ts | 17 | ||||
| -rw-r--r-- | packages/opencode/test/util/log.test.ts | 44 |
2 files changed, 51 insertions, 10 deletions
diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index 2ca4c0a3d..1b962e38e 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -3,7 +3,6 @@ import fs from "fs/promises" import { createWriteStream } from "fs" import { Global } from "../global" import z from "zod" -import { Glob } from "./glob" export namespace Log { export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" }) @@ -15,6 +14,8 @@ export namespace Log { WARN: 2, ERROR: 3, } + const keep = 10 + const rx = /^\d{4}-\d{2}-\d{2}T\d{6}\.log$/ let level: Level = "INFO" @@ -78,15 +79,11 @@ export namespace Log { } async function cleanup(dir: string) { - const files = await Glob.scan("????-??-??T??????.log", { - cwd: dir, - absolute: true, - include: "file", - }) - if (files.length <= 5) return - - const filesToDelete = files.slice(0, -10) - await Promise.all(filesToDelete.map((file) => fs.unlink(file).catch(() => {}))) + const files = (await fs.readdir(dir).catch(() => [])).filter((file) => rx.test(file)).sort() + if (files.length <= keep) return + + const doomed = files.slice(0, -keep) + await Promise.all(doomed.map((file) => fs.unlink(path.join(dir, file)).catch(() => {}))) } function formatError(error: Error, depth = 0): string { diff --git a/packages/opencode/test/util/log.test.ts b/packages/opencode/test/util/log.test.ts new file mode 100644 index 000000000..33e64fcd0 --- /dev/null +++ b/packages/opencode/test/util/log.test.ts @@ -0,0 +1,44 @@ +import { afterEach, expect, test } from "bun:test" +import fs from "fs/promises" +import path from "path" +import { Global } from "../../src/global" +import { Log } from "../../src/util/log" +import { tmpdir } from "../fixture/fixture" + +const log = Global.Path.log + +afterEach(() => { + Global.Path.log = log +}) + +async function files(dir: string) { + let last = "" + let same = 0 + + for (let i = 0; i < 50; i++) { + const list = (await fs.readdir(dir)).sort() + const next = JSON.stringify(list) + same = next === last ? same + 1 : 0 + if (same >= 2 && list.length === 11) return list + last = next + await Bun.sleep(10) + } + + return (await fs.readdir(dir)).sort() +} + +test("init cleanup keeps the newest timestamped logs", async () => { + await using tmp = await tmpdir() + Global.Path.log = tmp.path + + const list = Array.from({ length: 12 }, (_, i) => `2000-01-${String(i + 1).padStart(2, "0")}T000000.log`) + + await Promise.all(list.map((file) => fs.writeFile(path.join(tmp.path, file), file))) + + await Log.init({ print: false, dev: false }) + + const next = await files(tmp.path) + + expect(next).not.toContain(list[0]!) + expect(next).toContain(list.at(-1)!) +}) |
