mirror of
https://github.com/pockethost/pockethost.git
synced 2025-06-07 14:46:41 +00:00
fix: log handle leak
This commit is contained in:
parent
1f5c86a7b2
commit
f9f0a4f391
@ -37,7 +37,7 @@ server.on('message', (msg, rinfo) => {
|
|||||||
|
|
||||||
const { process: instanceId, severity, message } = parsed
|
const { process: instanceId, severity, message } = parsed
|
||||||
|
|
||||||
const logger = InstanceLogger(instanceId, `exec`)
|
const logger = InstanceLogger(instanceId, `exec`, { ttl: 5000 })
|
||||||
if (severity === 'info') {
|
if (severity === 'info') {
|
||||||
logger.info(message)
|
logger.info(message)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,37 +1,53 @@
|
|||||||
import { DEBUG, mkInstanceDataPath } from '$constants'
|
import { mkInstanceDataPath } from '$constants'
|
||||||
import { LoggerService, createCleanupManager } from '$shared'
|
import { createCleanupManager, LoggerService } from '$shared'
|
||||||
import { asyncExitHook } from '$util'
|
import { asyncExitHook, mergeConfig } from '$util'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import { Tail } from 'tail'
|
import { Tail } from 'tail'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
|
|
||||||
type UnsubFunc = () => void
|
type UnsubFunc = () => void
|
||||||
|
|
||||||
|
export type InstanceLoggerApi = {
|
||||||
|
info: (msg: string) => void
|
||||||
|
error: (msg: string) => void
|
||||||
|
tail: (linesBack: number, data: (line: winston.LogEntry) => void) => UnsubFunc
|
||||||
|
shutdown: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InstanceLoggerOptions = {
|
||||||
|
ttl: number
|
||||||
|
}
|
||||||
|
|
||||||
const loggers: {
|
const loggers: {
|
||||||
[key: string]: {
|
[key: string]: InstanceLoggerApi
|
||||||
info: (msg: string) => void
|
|
||||||
error: (msg: string) => void
|
|
||||||
tail: (
|
|
||||||
linesBack: number,
|
|
||||||
data: (line: winston.LogEntry) => void,
|
|
||||||
) => UnsubFunc
|
|
||||||
}
|
|
||||||
} = {}
|
} = {}
|
||||||
|
|
||||||
export function InstanceLogger(instanceId: string, target: string) {
|
export function InstanceLogger(
|
||||||
|
instanceId: string,
|
||||||
|
target: string,
|
||||||
|
options: Partial<InstanceLoggerOptions> = {},
|
||||||
|
) {
|
||||||
|
const { dbg, info } = LoggerService().create(instanceId).breadcrumb(target)
|
||||||
|
const { ttl } = mergeConfig<InstanceLoggerOptions>({ ttl: 0 }, options)
|
||||||
|
|
||||||
|
dbg({ ttl })
|
||||||
|
|
||||||
const loggerKey = `${instanceId}_${target}`
|
const loggerKey = `${instanceId}_${target}`
|
||||||
if (loggers[loggerKey]) {
|
if (loggers[loggerKey]) {
|
||||||
|
dbg(`Logger exists, using cache`)
|
||||||
return loggers[loggerKey]!
|
return loggers[loggerKey]!
|
||||||
}
|
}
|
||||||
|
|
||||||
const logDirectory = mkInstanceDataPath(instanceId, `logs`)
|
const logDirectory = mkInstanceDataPath(instanceId, `logs`)
|
||||||
if (!fs.existsSync(logDirectory)) {
|
if (!fs.existsSync(logDirectory)) {
|
||||||
console.log(`Creating ${logDirectory}`)
|
dbg(`Creating ${logDirectory}`)
|
||||||
fs.mkdirSync(logDirectory, { recursive: true })
|
fs.mkdirSync(logDirectory, { recursive: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
||||||
|
|
||||||
|
const cm = createCleanupManager()
|
||||||
|
|
||||||
const logger = winston.createLogger({
|
const logger = winston.createLogger({
|
||||||
format: winston.format.combine(
|
format: winston.format.combine(
|
||||||
winston.format.timestamp(),
|
winston.format.timestamp(),
|
||||||
@ -55,25 +71,50 @@ export function InstanceLogger(instanceId: string, target: string) {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
cm.add(() => {
|
||||||
|
dbg(`Deleting and closing`)
|
||||||
|
delete loggers[loggerKey]
|
||||||
|
logger.close()
|
||||||
|
})
|
||||||
|
|
||||||
const { error, warn } = LoggerService()
|
const { error, warn } = LoggerService()
|
||||||
.create('InstanceLogger')
|
.create('InstanceLogger')
|
||||||
.breadcrumb(instanceId)
|
.breadcrumb(instanceId)
|
||||||
.breadcrumb(target)
|
.breadcrumb(target)
|
||||||
|
|
||||||
|
const resetTtl = (() => {
|
||||||
|
let tid: ReturnType<typeof setTimeout>
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (!ttl) return
|
||||||
|
clearTimeout(tid)
|
||||||
|
tid = setTimeout(() => {
|
||||||
|
dbg(`Logger timeout`)
|
||||||
|
api.shutdown()
|
||||||
|
}, ttl)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
info: (msg: string) => {
|
info: (msg: string) => {
|
||||||
|
resetTtl()
|
||||||
|
dbg(`info: `, msg)
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
},
|
},
|
||||||
error: (msg: string) => {
|
error: (msg: string) => {
|
||||||
|
resetTtl()
|
||||||
|
dbg(`error: `, msg)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
},
|
},
|
||||||
tail: (
|
tail: (
|
||||||
linesBack: number,
|
linesBack: number,
|
||||||
data: (line: winston.LogEntry) => void,
|
data: (line: winston.LogEntry) => void,
|
||||||
): UnsubFunc => {
|
): UnsubFunc => {
|
||||||
|
if (ttl) {
|
||||||
|
throw new Error(`Cannot tail with ttl active`)
|
||||||
|
}
|
||||||
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
const logFile = mkInstanceDataPath(instanceId, `logs`, `${target}.log`)
|
||||||
|
|
||||||
const cm = createCleanupManager()
|
|
||||||
let tid: any
|
let tid: any
|
||||||
cm.add(() => clearTimeout(tid))
|
cm.add(() => clearTimeout(tid))
|
||||||
const check = () => {
|
const check = () => {
|
||||||
@ -111,12 +152,7 @@ export function InstanceLogger(instanceId: string, target: string) {
|
|||||||
unsub()
|
unsub()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
shutdown: () => cm.shutdown(),
|
||||||
if (DEBUG()) {
|
|
||||||
const { dbg } = LoggerService().create(`Logger`).breadcrumb(instanceId)
|
|
||||||
api.tail(0, (entry) => {
|
|
||||||
dbg(entry.message)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loggers[loggerKey] = api
|
loggers[loggerKey] = api
|
||||||
|
@ -80,7 +80,10 @@ export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
|||||||
res.write(evt)
|
res.write(evt)
|
||||||
})
|
})
|
||||||
|
|
||||||
res.on('close', unsub)
|
res.on('close', () => {
|
||||||
|
unsub()
|
||||||
|
instanceLogger.shutdown()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user