synops/docs/features/ressursforbruk.md
vegard eb81055ef4 Fullfører oppgave 15.7: Ressursforbruk-logging
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>
2026-03-18 04:24:54 +00:00

6.3 KiB

Ressursforbruk — Måling og synliggjøring

Konsept

Alle ressurskrevende operasjoner logges med naturlige enheter. Forbruket akkumuleres på tre akser: noden som ble behandlet, brukeren som utløste det, og samlingen det skjedde i.

Formålet er synliggjøring og innsikt, ikke fakturering.

Ressurstyper

Ressurstype Enhet Hva måles
ai tokens inn / tokens ut LLM-kall via AI Gateway
whisper sekunder prosessert lyd Transkripsjons-pipeline
tts tegn Tekst-til-tale-generering
cas bytes Lagring i CAS (store/delete)
bandwidth bytes ut Servering av mediefiler og publisert innhold
livekit deltaker-minutter WebRTC-sesjoner (møter, opptak)
graph noder / edges Opprettelse av noder og edges i grafen

Logg-skjema

CREATE TABLE resource_usage_log (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    target_node_id UUID NOT NULL REFERENCES nodes(id),
    triggered_by UUID REFERENCES nodes(id),  -- null for system-jobber
    collection_id UUID REFERENCES nodes(id),
    resource_type TEXT NOT NULL,  -- 'ai', 'whisper', 'tts', 'cas', 'bandwidth', 'livekit'
    detail JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_resource_usage_target ON resource_usage_log(target_node_id);
CREATE INDEX idx_resource_usage_triggered ON resource_usage_log(triggered_by);
CREATE INDEX idx_resource_usage_collection ON resource_usage_log(collection_id);
CREATE INDEX idx_resource_usage_type_time ON resource_usage_log(resource_type, created_at);

Detail-struktur per type

AI (LLM-kall)

{
    "model_level": "fast",       // "fast" | "smart" | "deep"
    "model_id": "gemini-2.0-flash",
    "tokens_in": 1240,
    "tokens_out": 380,
    "job_type": "auto_tag"       // hva jobben var
}

Modellnivåer:

Nivå Semantikk Typiske modeller
fast Billig, lav latens Gemini Flash, Haiku
smart Balansert Sonnet, Gemini Pro
deep Grundig, dyr Opus, GPT-4

Whisper (transkripsjon)

{
    "model": "medium",           // "small" | "medium" | "large-v3"
    "duration_seconds": 2520,    // lengde på prosessert lyd
    "language": "no",
    "mode": "batch"              // "live" | "batch"
}

TTS (tekst-til-tale)

{
    "provider": "elevenlabs",    // "elevenlabs" | "local"
    "characters": 8200,
    "voice_id": "norwegian_male_1"
}

CAS (lagring)

{
    "hash": "sha256-abc123...",
    "size_bytes": 84000000,
    "mime": "audio/mp3",
    "operation": "store"         // "store" | "delete"
}

Bandwidth (servering)

{
    "size_bytes": 84000000,
    "path": "/media/podcast/ep47.mp3",
    "client": "Apple Podcasts"   // parsert fra User-Agent
}

LiveKit (sanntid)

{
    "room_id": "meeting-abc123",
    "participant_minutes": 180,
    "tracks": 4                  // antall aktive lyd/video-spor
}

Graph (noder og edges)

Trenger ikke logges i resource_usage_log — kan telles direkte fra nodes og edges-tabellene med COUNT + GROUP BY created_by eller GROUP BY collection. Billig spørring, ingen ekstra lagring.

Vises i bruker- og samlingsvisning som kontekst:

Vegard:
  423 noder opprettet
  1 204 edges

Sidelinja:
  2 891 noder
  8 340 edges

Aggregering

Tre naturlige visninger, alle er GROUP BY-spørringer mot samme tabell:

Per node

Synlig i node-detaljer for eieren. Gir innsikt i hva en spesifikk node har kostet i ressurser.

Episode 47:
  AI (smart)     12k tokens inn, 3k ut — 4 jobber
  Whisper        42 min prosessert (medium)
  TTS            8 200 tegn
  CAS            84 MB lagret
  Båndbredde     2.3 GB servert
  LiveKit        180 deltaker-minutter
  12 noder, 34 edges

Per bruker

Synlig for brukeren selv i sin profil/innstillinger. Sum av alle noder brukeren har utløst arbeid på.

Vegard denne måneden:
  AI         fast: 42k / smart: 18k / deep: 3k tokens
  Whisper    3.2 timer prosessert
  TTS        24k tegn
  423 noder opprettet, 1 204 edges

Per samling

Synlig for samlingens eiere/admins. Sum av alt forbruk i samlingen. Nyttig for å forstå hvilke samlinger som bruker mest ressurser.

Sidelinja (mars 2026):
  AI         148k tokens totalt
  Whisper    12.4 timer prosessert
  CAS        2.1 GB lagret
  Båndbredde 48 GB servert
  2 891 noder, 8 340 edges

Triggered-by-regler

Scenario triggered_by
Bruker klikker "oppsummer" Brukeren
Bruker sender melding som trigger auto-tag Brukeren
Nattlig samlings-digest null (system)
Podcast-nedlasting av ekstern lytter null (system)

Når triggered_by er null, tilhører forbruket kun samlingen — det belaster ingen spesifikk bruker.

Logging-ansvar

Maskinrommet logger all ressursbruk. Hver handler (AI, Whisper, TTS, CAS, LiveKit) skriver til resource_usage_log som siste steg etter vellykket operasjon. Feilede jobber logges ikke — ingen ressurs ble forbrukt.

Båndbredde-logging skjer via Caddy-logg-parsing i nattlig batch-jobb (samme mønster som docs/features/podcast_statistikk.md).

Implementeringsstatus

Følgende ressurstyper logges til resource_usage_log:

Ressurstype Handler Status
ai summarize.rs, ai_edges.rs, agent.rs Implementert. Token-telling fra LiteLLM usage-feltet. Agent bruker claude CLI og logger 0 tokens (CLI gir ikke token-info).
whisper transcribe.rs Implementert. Logger duration_seconds, model, language, mode.
tts tts.rs Implementert. Logger provider, characters, voice_id.
cas intentions.rs (upload_media) Implementert. Logger kun nye filer (ikke dedup). hash, size_bytes, mime, operation.
livekit intentions.rs (join_communication) Implementert. Logger join-hendelser. Faktisk participant_minutes krever LiveKit webhook-integrasjon (fremtidig).
bandwidth bandwidth.rs Implementert. Nattlig jobb (kl 03:00) parser Caddy JSON-access-logger.

Sentralisert hjelpemodul

resource_usage.rs tilbyr log() og find_collection_for_node(). Alle handlers bruker denne for konsistent logging.

Caddy-oppsett

JSON access logging er konfigurert i Caddyfile for sidelinja.org og synops.no. Logger skrives til /var/log/caddy/access-*.log med 100 MiB rotasjon og 7 filer beholdt.