enh: live log size and rotation controls

This commit is contained in:
Ben Allfree 2024-11-28 00:42:57 -08:00
parent fec6d4fa59
commit 993faed077

View File

@ -1,4 +1,6 @@
import { appendFile } from 'fs/promises' import Bottleneck from 'bottleneck'
import { existsSync } from 'fs'
import { appendFile, cp, stat, truncate } from 'fs/promises'
import { Tail } from 'tail' import { Tail } from 'tail'
import { import {
ensureInstanceDirectoryStructure, ensureInstanceDirectoryStructure,
@ -25,6 +27,29 @@ export type LogEntry = {
time: string time: string
} }
const MultiChannelLimiter = () => {
const channels = new Map<string, Bottleneck>()
setInterval(() => {
for (const [channel, limiter] of channels.entries()) {
if (limiter.empty()) {
console.log(`Deleting empty limiter for ${channel}`)
channels.delete(channel)
}
}
}, 1000)
return {
schedule(channel: string, fn: () => Promise<void>) {
if (!channels.has(channel)) {
channels.set(channel, new Bottleneck({ maxConcurrent: 1 }))
}
return channels.get(channel)!.schedule(fn)!
},
}
}
const limiter = MultiChannelLimiter()
export function InstanceLogWriter( export function InstanceLogWriter(
instanceId: string, instanceId: string,
volume: string, volume: string,
@ -42,25 +67,42 @@ export function InstanceLogWriter(
`${target}.log`, `${target}.log`,
) )
const appendLogEntry = (msg: string, stream: 'stdout' | 'stderr') => { const appendLogEntry = async (msg: string, stream: 'stdout' | 'stderr') =>
appendFile( limiter.schedule(logFile, async () => {
logFile, try {
stringify({ if (existsSync(logFile)) {
message: msg, // Check file size
stream, const stats = await stat(logFile)
time: new Date().toISOString(), const MAX_SIZE = 1024 // 10MB in bytes
}) + '\n',
) if (stats.size > MAX_SIZE) {
} await cp(logFile, `${logFile}.1`, {
force: true,
})
await truncate(logFile, 0)
}
}
dbg(msg)
await appendFile(
logFile,
stringify({
message: msg,
stream,
time: new Date().toISOString(),
}) + '\n',
)
} catch (e) {
error(`Failed to write log entry: ${e}`)
}
})
const api = { const api = {
info: (msg: string) => { info: (msg: string) => {
dbg(msg) return appendLogEntry(msg, 'stdout')
appendLogEntry(msg, 'stdout')
}, },
error: (msg: string) => { error: (msg: string) => {
dbg(msg) return appendLogEntry(msg, 'stderr')
appendLogEntry(msg, 'stderr')
}, },
} }
@ -110,7 +152,10 @@ export function InstanceLogReader(
unsub = () => tail.close() unsub = () => tail.close()
} catch (e) { } catch (e) {
warn(e) if ((e as any).code === 'ENOENT') {
} else {
warn(e)
}
tid = setTimeout(check, 1000) tid = setTimeout(check, 1000)
} }
} }