fix: ensure logger cleanup properly orders list before deleting files (#22101)
This commit is contained in:
@@ -3,7 +3,6 @@ import fs from "fs/promises"
|
|||||||
import { createWriteStream } from "fs"
|
import { createWriteStream } from "fs"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Glob } from "./glob"
|
|
||||||
|
|
||||||
export namespace Log {
|
export namespace Log {
|
||||||
export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" })
|
export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" })
|
||||||
@@ -15,6 +14,8 @@ export namespace Log {
|
|||||||
WARN: 2,
|
WARN: 2,
|
||||||
ERROR: 3,
|
ERROR: 3,
|
||||||
}
|
}
|
||||||
|
const keep = 10
|
||||||
|
const rx = /^\d{4}-\d{2}-\d{2}T\d{6}\.log$/
|
||||||
|
|
||||||
let level: Level = "INFO"
|
let level: Level = "INFO"
|
||||||
|
|
||||||
@@ -78,15 +79,11 @@ export namespace Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function cleanup(dir: string) {
|
async function cleanup(dir: string) {
|
||||||
const files = await Glob.scan("????-??-??T??????.log", {
|
const files = (await fs.readdir(dir).catch(() => [])).filter((file) => rx.test(file)).sort()
|
||||||
cwd: dir,
|
if (files.length <= keep) return
|
||||||
absolute: true,
|
|
||||||
include: "file",
|
|
||||||
})
|
|
||||||
if (files.length <= 5) return
|
|
||||||
|
|
||||||
const filesToDelete = files.slice(0, -10)
|
const doomed = files.slice(0, -keep)
|
||||||
await Promise.all(filesToDelete.map((file) => fs.unlink(file).catch(() => {})))
|
await Promise.all(doomed.map((file) => fs.unlink(path.join(dir, file)).catch(() => {})))
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatError(error: Error, depth = 0): string {
|
function formatError(error: Error, depth = 0): string {
|
||||||
|
|||||||
@@ -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)!)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user