Sentralisert logging av alle ressurskrevende operasjoner til resource_usage_log-tabellen (opprettet i migrasjon 009). Ny kode: - resource_usage.rs: hjelpemodul med log() og find_collection_for_node() - bandwidth.rs: Caddy JSON-logg-parser med nattlig batch-jobb (kl 03:00) Logging lagt til i handlere: - AI: summarize, ai_edges (token-telling via LiteLLM usage-felt), agent (placeholder — claude CLI gir ikke token-info) - Whisper: duration_seconds, model, language, mode - TTS: refaktorert til sentralisert modul, lagt til collection_id - CAS: logger nye filer ved upload (ikke dedup) - LiveKit: logger join-hendelser (faktisk deltaker-minutter krever webhook-integrasjon i fremtiden) Caddy-config: JSON access logging aktivert for sidelinja.org og synops.no i /srv/synops/config/caddy/Caddyfile (utenfor repo). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
68 lines
2 KiB
Rust
68 lines
2 KiB
Rust
// Ressursforbruk-logging — sentralisert hjelpemodul.
|
|
//
|
|
// Alle ressurskrevende operasjoner logger til `resource_usage_log`-tabellen
|
|
// som siste steg etter vellykket operasjon. Feilede jobber logges ikke.
|
|
//
|
|
// Ref: docs/features/ressursforbruk.md
|
|
|
|
use sqlx::PgPool;
|
|
use uuid::Uuid;
|
|
|
|
/// Logger en ressurshendelse til `resource_usage_log`.
|
|
///
|
|
/// - `target_node_id`: Noden som ble behandlet
|
|
/// - `triggered_by`: Brukeren som utløste det (None for system-jobber)
|
|
/// - `collection_id`: Samlingen det skjedde i (None hvis ukjent)
|
|
/// - `resource_type`: "ai", "whisper", "tts", "cas", "bandwidth", "livekit"
|
|
/// - `detail`: JSONB med type-spesifikke felter (se docs/features/ressursforbruk.md)
|
|
pub async fn log(
|
|
db: &PgPool,
|
|
target_node_id: Uuid,
|
|
triggered_by: Option<Uuid>,
|
|
collection_id: Option<Uuid>,
|
|
resource_type: &str,
|
|
detail: serde_json::Value,
|
|
) -> Result<(), String> {
|
|
sqlx::query(
|
|
r#"
|
|
INSERT INTO resource_usage_log (target_node_id, triggered_by, collection_id, resource_type, detail)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
"#,
|
|
)
|
|
.bind(target_node_id)
|
|
.bind(triggered_by)
|
|
.bind(collection_id)
|
|
.bind(resource_type)
|
|
.bind(&detail)
|
|
.execute(db)
|
|
.await
|
|
.map_err(|e| format!("Ressurslogging feilet: {e}"))?;
|
|
|
|
tracing::debug!(
|
|
target_node_id = %target_node_id,
|
|
resource_type = %resource_type,
|
|
"Ressursforbruk logget"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Finn samlings-ID for en node via belongs_to-edge.
|
|
/// Returnerer None hvis noden ikke tilhører en samling.
|
|
pub async fn find_collection_for_node(db: &PgPool, node_id: Uuid) -> Option<Uuid> {
|
|
sqlx::query_scalar::<_, Uuid>(
|
|
r#"
|
|
SELECT e.target_id FROM edges e
|
|
JOIN nodes n ON n.id = e.target_id
|
|
WHERE e.source_id = $1
|
|
AND e.edge_type = 'belongs_to'
|
|
AND n.node_kind = 'collection'
|
|
LIMIT 1
|
|
"#,
|
|
)
|
|
.bind(node_id)
|
|
.fetch_optional(db)
|
|
.await
|
|
.ok()
|
|
.flatten()
|
|
}
|