feat: add endpoints to list and read log files; enhance log retrieval functionality

This commit is contained in:
Tengku Achmad 2025-12-05 15:28:14 +07:00
parent 405f150724
commit 164e62c234
1 changed files with 65 additions and 1 deletions

View File

@ -338,7 +338,7 @@ app.get('/api/config', (_req, res) => {
}) })
/** /**
* Get recent logs (dev/debug only) * Get recent logs from memory (dev/debug only)
* GET /api/logs?limit=100&level=debug|info|warn|error&q=keyword * GET /api/logs?limit=100&level=debug|info|warn|error&q=keyword
*/ */
app.get('/api/logs', (req, res) => { app.get('/api/logs', (req, res) => {
@ -360,6 +360,70 @@ app.get('/api/logs', (req, res) => {
res.json({ count: sliced.length, items: sliced }) res.json({ count: sliced.length, items: sliced })
}) })
/**
* List all log files in logs directory
* GET /api/logs/files
*/
app.get('/api/logs/files', (req, res) => {
if (!LOG_EXPOSE_API) {
return res.status(403).json({ error: 'FORBIDDEN', message: 'Log API disabled. Set LOG_EXPOSE_API=true to enable.' })
}
try {
const files = fs.readdirSync(LOG_DIR)
.filter(f => f.startsWith('LOGS_') && f.endsWith('.log'))
.map(f => {
const stats = fs.statSync(path.join(LOG_DIR, f))
return {
filename: f,
size: stats.size,
modified: stats.mtime,
path: `/api/logs/files/${f}`
}
})
.sort((a, b) => b.modified - a.modified)
res.json({ count: files.length, files })
} catch (e) {
logError('logs.files.error', { message: e?.message })
res.status(500).json({ error: 'READ_ERROR', message: e?.message || 'Failed to read log files' })
}
})
/**
* Read specific log file
* GET /api/logs/files/:filename
*/
app.get('/api/logs/files/:filename', (req, res) => {
if (!LOG_EXPOSE_API) {
return res.status(403).json({ error: 'FORBIDDEN', message: 'Log API disabled. Set LOG_EXPOSE_API=true to enable.' })
}
try {
const { filename } = req.params
// SECURITY: VALIDATE FILENAME TO PREVENT DIRECTORY TRAVERSAL
if (!filename.match(/^LOGS_\d{8}\.log$/)) {
return res.status(400).json({ error: 'INVALID_FILENAME', message: 'Invalid log filename format' })
}
const filePath = path.join(LOG_DIR, filename)
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'NOT_FOUND', message: 'Log file not found' })
}
const content = fs.readFileSync(filePath, 'utf8')
const lines = content.split('\n').filter(Boolean)
res.json({
filename,
lines: lines.length,
content: lines
})
} catch (e) {
logError('logs.file.read.error', { message: e?.message, filename: req.params.filename })
res.status(500).json({ error: 'READ_ERROR', message: e?.message || 'Failed to read log file' })
}
})
/** /**
* Update payment toggles at runtime (dev only) * Update payment toggles at runtime (dev only)
* POST /api/config * POST /api/config