add structured logging with timestamps for docker/unraid log viewer
Build and Push Docker Image / build (push) Successful in 15s

all server output now prefixed with ISO timestamp and level [INFO/WARN/ERROR].
logs requests, scan start/complete, job lifecycle, errors. skips noisy SSE
endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 17:29:22 +01:00
parent 818b0d1396
commit 3682ee98e0
4 changed files with 43 additions and 7 deletions
+7 -3
View File
@@ -5,6 +5,7 @@ import { execStream } from '../services/ssh';
import type { Job, Node, MediaItem, MediaStream } from '../types';
import { predictExtractedFiles } from '../services/ffmpeg';
import { accessSync, constants } from 'node:fs';
import { log, error as logError } from '../lib/log';
const app = new Hono();
@@ -73,7 +74,7 @@ app.get('/', (c) => {
app.post('/start', (c) => {
const db = getDb();
const pending = db.prepare("SELECT * FROM jobs WHERE status = 'pending' ORDER BY created_at").all() as Job[];
for (const job of pending) runJob(job).catch((err) => console.error(`Job ${job.id} failed:`, err));
for (const job of pending) runJob(job).catch((err) => logError(`Job ${job.id} failed:`, err));
return c.json({ ok: true, started: pending.length });
});
@@ -100,7 +101,7 @@ app.post('/job/:id/run', async (c) => {
if (!result) return c.notFound();
return c.json(result);
}
runJob(job).catch((err) => console.error(`Job ${job.id} failed:`, err));
runJob(job).catch((err) => logError(`Job ${job.id} failed:`, err));
const result = loadJobRow(jobId);
if (!result) return c.notFound();
return c.json(result);
@@ -168,6 +169,7 @@ app.get('/events', (c) => {
// ─── Job execution ────────────────────────────────────────────────────────────
async function runJob(job: Job): Promise<void> {
log(`Job ${job.id} starting (item=${job.item_id}${job.node_id ? `, node=${job.node_id}` : ', local'})`);
const db = getDb();
if (!job.node_id) {
@@ -227,6 +229,7 @@ async function runJob(job: Job): Promise<void> {
const fullOutput = outputLines.join('\n');
db.prepare("UPDATE jobs SET status = 'done', exit_code = 0, output = ?, completed_at = datetime('now') WHERE id = ?").run(fullOutput, job.id);
log(`Job ${job.id} completed successfully`);
emitJobUpdate(job.id, 'done', fullOutput);
db.prepare("UPDATE review_plans SET status = 'done' WHERE item_id = ?").run(job.item_id);
@@ -242,8 +245,9 @@ async function runJob(job: Job): Promise<void> {
}
db.prepare('UPDATE review_plans SET subs_extracted = 1 WHERE item_id = ?').run(job.item_id);
}
} catch (subErr) { console.error('Failed to record extracted subtitle files:', subErr); }
} catch (subErr) { logError('Failed to record extracted subtitle files:', subErr); }
} catch (err) {
logError(`Job ${job.id} failed:`, err);
const fullOutput = outputLines.join('\n') + '\n' + String(err);
db.prepare("UPDATE jobs SET status = 'error', exit_code = 1, output = ?, completed_at = datetime('now') WHERE id = ?").run(fullOutput, job.id);
emitJobUpdate(job.id, 'error', fullOutput);