log -f
This commit is contained in:
parent
e1b53fc54d
commit
84a341ebf9
|
|
@ -57,7 +57,15 @@ const restartApp = async (app: string) => {
|
|||
await post(`/api/apps/${app}/restart`)
|
||||
}
|
||||
|
||||
async function logApp(name: string) {
|
||||
const printLog = (line: LogLine) =>
|
||||
console.log(`${new Date(line.time).toLocaleTimeString()} ${line.text}`)
|
||||
|
||||
async function logApp(name: string, options: { follow?: boolean }) {
|
||||
if (options.follow) {
|
||||
await tailLogs(name)
|
||||
return
|
||||
}
|
||||
|
||||
const logs: LogLine[] | undefined = await get(`/api/apps/${name}/logs`)
|
||||
if (!logs) {
|
||||
console.error(`App not found: ${name}`)
|
||||
|
|
@ -68,8 +76,37 @@ async function logApp(name: string) {
|
|||
return
|
||||
}
|
||||
for (const line of logs) {
|
||||
const time = new Date(line.time).toLocaleTimeString()
|
||||
console.log(`${time} ${line.text}`)
|
||||
printLog(line)
|
||||
}
|
||||
}
|
||||
|
||||
async function tailLogs(name: string) {
|
||||
const url = join(HOST, `/api/apps/${name}/logs/stream`)
|
||||
const res = await fetch(url)
|
||||
if (!res.ok) {
|
||||
console.error(`App not found: ${name}`)
|
||||
return
|
||||
}
|
||||
if (!res.body) return
|
||||
|
||||
const reader = res.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
let buffer = ''
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) break
|
||||
|
||||
buffer += decoder.decode(value, { stream: true })
|
||||
const lines = buffer.split('\n\n')
|
||||
buffer = lines.pop() ?? ''
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const data = JSON.parse(line.slice(6)) as LogLine
|
||||
printLog(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,11 +156,13 @@ program
|
|||
.command('logs')
|
||||
.description('Show logs for an app')
|
||||
.argument('<name>', 'app name')
|
||||
.option('-f, --follow', 'follow log output')
|
||||
.action(logApp)
|
||||
|
||||
program
|
||||
.command('log', { hidden: true })
|
||||
.argument('<name>', 'app name')
|
||||
.option('-f, --follow', 'follow log output')
|
||||
.action(logApp)
|
||||
|
||||
program
|
||||
|
|
|
|||
|
|
@ -80,6 +80,31 @@ app.get('/api/apps/:app/logs', c => {
|
|||
return c.json(app.logs ?? [])
|
||||
})
|
||||
|
||||
app.sse('/api/apps/:app/logs/stream', (send, c) => {
|
||||
const appName = c.req.param('app')
|
||||
const targetApp = allApps().find(a => a.name === appName)
|
||||
if (!targetApp) return
|
||||
|
||||
let lastLogCount = 0
|
||||
|
||||
const sendNewLogs = () => {
|
||||
const currentApp = allApps().find(a => a.name === appName)
|
||||
if (!currentApp) return
|
||||
|
||||
const logs = currentApp.logs ?? []
|
||||
const newLogs = logs.slice(lastLogCount)
|
||||
lastLogCount = logs.length
|
||||
|
||||
for (const line of newLogs) {
|
||||
send(line)
|
||||
}
|
||||
}
|
||||
|
||||
sendNewLogs()
|
||||
const unsub = onChange(sendNewLogs)
|
||||
return () => unsub()
|
||||
})
|
||||
|
||||
app.post('/api/apps/:app/start', c => {
|
||||
const appName = c.req.param('app')
|
||||
if (!appName) return c.json({ error: 'App not found' }, 404)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user