mirror of
https://github.com/pockethost/pockethost.git
synced 2025-03-30 15:08:30 +00:00
enh: live log size and rotation controls
This commit is contained in:
parent
fec6d4fa59
commit
993faed077
@ -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 {
|
||||
ensureInstanceDirectoryStructure,
|
||||
@ -25,6 +27,29 @@ export type LogEntry = {
|
||||
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(
|
||||
instanceId: string,
|
||||
volume: string,
|
||||
@ -42,25 +67,42 @@ export function InstanceLogWriter(
|
||||
`${target}.log`,
|
||||
)
|
||||
|
||||
const appendLogEntry = (msg: string, stream: 'stdout' | 'stderr') => {
|
||||
appendFile(
|
||||
logFile,
|
||||
stringify({
|
||||
message: msg,
|
||||
stream,
|
||||
time: new Date().toISOString(),
|
||||
}) + '\n',
|
||||
)
|
||||
}
|
||||
const appendLogEntry = async (msg: string, stream: 'stdout' | 'stderr') =>
|
||||
limiter.schedule(logFile, async () => {
|
||||
try {
|
||||
if (existsSync(logFile)) {
|
||||
// Check file size
|
||||
const stats = await stat(logFile)
|
||||
const MAX_SIZE = 1024 // 10MB in bytes
|
||||
|
||||
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 = {
|
||||
info: (msg: string) => {
|
||||
dbg(msg)
|
||||
appendLogEntry(msg, 'stdout')
|
||||
return appendLogEntry(msg, 'stdout')
|
||||
},
|
||||
error: (msg: string) => {
|
||||
dbg(msg)
|
||||
appendLogEntry(msg, 'stderr')
|
||||
return appendLogEntry(msg, 'stderr')
|
||||
},
|
||||
}
|
||||
|
||||
@ -110,7 +152,10 @@ export function InstanceLogReader(
|
||||
|
||||
unsub = () => tail.close()
|
||||
} catch (e) {
|
||||
warn(e)
|
||||
if ((e as any).code === 'ENOENT') {
|
||||
} else {
|
||||
warn(e)
|
||||
}
|
||||
tid = setTimeout(check, 1000)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user