Feat : Log recorder
This commit is contained in:
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { DatabaseSync } from 'node:sqlite';
|
||||
import type {
|
||||
AgentEvent,
|
||||
LogEntry,
|
||||
LogLevel,
|
||||
ObsSettings,
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
DEFAULT_OBS_SETTINGS,
|
||||
DEFAULT_RECORDING_SETTINGS,
|
||||
DEFAULT_WATCH_SETTINGS,
|
||||
isAgentEvent,
|
||||
normalizeBrowserSettings,
|
||||
normalizeRecordingSettings,
|
||||
normalizeWatchSettings,
|
||||
@@ -96,6 +98,10 @@ addColumnIfMissing('agents', 'browser_json', 'TEXT');
|
||||
// Preset d'enregistrement : réglable VM par VM, absent = aucune intervention
|
||||
// de l'agent sur les réglages d'OBS.
|
||||
addColumnIfMissing('agents', 'recording_json', 'TEXT');
|
||||
// Nature de l'évènement journalisé : classe l'entrée dans l'historique d'une VM.
|
||||
// Nul sur les entrées écrites avant cette colonne, et sur celles des agents non
|
||||
// mis à jour — l'interface s'en accommode.
|
||||
addColumnIfMissing('logs', 'event', 'TEXT');
|
||||
|
||||
// Enrichissement des profils surveillés : photo et historique de diffusion.
|
||||
addColumnIfMissing('watch_targets', 'avatar_url', 'TEXT');
|
||||
@@ -194,12 +200,20 @@ const stmts = {
|
||||
rotateToken: db.prepare('UPDATE agents SET token_hash = ? WHERE id = ?'),
|
||||
deleteAgent: db.prepare('DELETE FROM agents WHERE id = ?'),
|
||||
|
||||
insertLog: db.prepare('INSERT INTO logs (agent_id, level, message, ts) VALUES (?, ?, ?, ?)'),
|
||||
insertLog: db.prepare(
|
||||
'INSERT INTO logs (agent_id, level, message, ts, event) VALUES (?, ?, ?, ?, ?)',
|
||||
),
|
||||
recentLogs: db.prepare(`
|
||||
SELECT l.id, l.agent_id, l.level, l.message, l.ts, a.name AS agent_name
|
||||
SELECT l.id, l.agent_id, l.level, l.message, l.ts, l.event, a.name AS agent_name
|
||||
FROM logs l LEFT JOIN agents a ON a.id = l.agent_id
|
||||
ORDER BY l.id DESC LIMIT ?
|
||||
`),
|
||||
agentLogs: db.prepare(`
|
||||
SELECT l.id, l.agent_id, l.level, l.message, l.ts, l.event, a.name AS agent_name
|
||||
FROM logs l LEFT JOIN agents a ON a.id = l.agent_id
|
||||
WHERE l.agent_id = ?
|
||||
ORDER BY l.id DESC LIMIT ?
|
||||
`),
|
||||
pruneLogs: db.prepare(`
|
||||
DELETE FROM logs WHERE id NOT IN (SELECT id FROM logs ORDER BY id DESC LIMIT ?)
|
||||
`),
|
||||
@@ -466,11 +480,30 @@ interface LogRow {
|
||||
level: string;
|
||||
message: string;
|
||||
ts: number;
|
||||
event: string | null;
|
||||
}
|
||||
|
||||
function toLogEntry(row: LogRow): LogEntry {
|
||||
return {
|
||||
id: Number(row.id),
|
||||
agentId: row.agent_id,
|
||||
agentName: row.agent_name,
|
||||
level: row.level as LogLevel,
|
||||
message: row.message,
|
||||
ts: Number(row.ts),
|
||||
event: isAgentEvent(row.event) ? row.event : null,
|
||||
};
|
||||
}
|
||||
|
||||
export const logsRepo = {
|
||||
append(agentId: string | null, level: LogLevel, message: string, ts = Date.now()): LogEntry {
|
||||
const info = stmts.insertLog.run(agentId, level, message, ts);
|
||||
append(
|
||||
agentId: string | null,
|
||||
level: LogLevel,
|
||||
message: string,
|
||||
ts = Date.now(),
|
||||
event: AgentEvent | null = null,
|
||||
): LogEntry {
|
||||
const info = stmts.insertLog.run(agentId, level, message, ts, event);
|
||||
if (Math.random() < 0.02) stmts.pruneLogs.run(config.logRetention);
|
||||
const agent = agentId ? agentsRepo.get(agentId) : null;
|
||||
return {
|
||||
@@ -480,20 +513,18 @@ export const logsRepo = {
|
||||
level,
|
||||
message,
|
||||
ts,
|
||||
event,
|
||||
};
|
||||
},
|
||||
|
||||
recent(limit = 200): LogEntry[] {
|
||||
const rows = stmts.recentLogs.all(limit) as unknown as LogRow[];
|
||||
return rows
|
||||
.map((row) => ({
|
||||
id: Number(row.id),
|
||||
agentId: row.agent_id,
|
||||
agentName: row.agent_name,
|
||||
level: row.level as LogLevel,
|
||||
message: row.message,
|
||||
ts: Number(row.ts),
|
||||
}))
|
||||
.reverse();
|
||||
return rows.map(toLogEntry).reverse();
|
||||
},
|
||||
|
||||
/** Historique d'une VM, du plus ancien au plus récent. */
|
||||
forAgent(agentId: string, limit = 300): LogEntry[] {
|
||||
const rows = stmts.agentLogs.all(agentId, limit) as unknown as LogRow[];
|
||||
return rows.map(toLogEntry).reverse();
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user