feat: system logs - email log + system log with admin UI
- db: email_logs (sent/failed) + system_logs (info/warn/error) tables, auto-migrated for existing installs - backend/logger.js: logEmail/logSystem with try/catch (never breaks flow) - mailer: log send result (SMTP unconfigured/sent/failed + error msg) - webhook: log blocked-internal, non-2xx response, send failure - server: error middleware records 500 errors to system_logs - routes/logs.js: GET /logs/emails + /logs/system (admin/owner, filters) - UI: 系统日志 page (owner/admin) with system/email tabs + filters - API docs updated
This commit is contained in:
@@ -128,6 +128,7 @@ function loadBusinessRoutes() {
|
||||
businessRouter.use('/polls', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/polls'));
|
||||
businessRouter.use('/features', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/features'));
|
||||
businessRouter.use('/bans', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/bans'));
|
||||
businessRouter.use('/logs', methodGuard(['GET']), generalLimiter, require('./routes/logs'));
|
||||
businessRouter.use('/external', require('./routes/external'));
|
||||
|
||||
businessRouter.get('/verify', (req, res) => res.redirect(`/#/verify?token=${req.query.token}`));
|
||||
@@ -197,6 +198,7 @@ app.use((err, req, res, next) => {
|
||||
if (err.message?.includes('不支持的文件类型')) return res.status(400).json({ error: err.message });
|
||||
if (err.message?.includes('文件内容与声明类型不符')) return res.status(400).json({ error: '文件类型校验失败' });
|
||||
console.error(err);
|
||||
try { require('./logger').logSystem('error', 'server', err.message || '服务器内部错误', { path: req.path, method: req.method, stack: String(err.stack).slice(0, 1000) }); } catch {}
|
||||
res.status(500).json({ error: '服务器内部错误' });
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user