# Creative: Runtime Logs Cleanup & Tail (CP-3) 📌 **CREATIVE PHASE START: Cleanup Semantics & Tail Limits** ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## 1️⃣ PROBLEM **Description:** Sync cleanup больших `.log` файлов на HTTP worker; tail/preview без OOM. Нужны чёткие лимиты и режимы очистки, совместимые с sidecar `docker logs -f >> file` (файл пересоздаётся при рестарте sidecar). **Requirements:** - Cleanup — **синхронный** HTTP (решение заказчика) - Audit: `size_before`, `size_after`, `action` - Sidecar продолжает писать в тот же путь после truncate - Защита от чтения гигабайтных файлов в tail **Constraints:** - Без `jobs.Registry` для cleanup - Request timeout: разумный предел на handler (context с deadline 60s для cleanup) - Файлы: только allowlisted basenames (CP-4) ## 2️⃣ OPTIONS — Cleanup mode | Option | Описание | |--------|----------| | **A** | **Truncate** по умолчанию (`os.Truncate(0)` или `O_TRUNC`) — файл остаётся, inode может сохраниться | | **B** | **Delete** по умолчанию — `os.Remove`, sidecar создаст при следующей записи | | **C** | Rotate: rename to `.old` + create new | | **D** | Truncate только < N MB, иначе reject | ## 3️⃣ ANALYSIS — Cleanup | Criterion | A Truncate | B Delete | C Rotate | D Size gate | |-----------|------------|----------|----------|-------------| | Sidecar совместимость | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | | Predictable filename | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | | Sync latency | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | | Audit clarity | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | **Key insight:** sidecar открывает файл через shell redirect `>>`; **truncate** обнуляет содержимое без смены имени в list — оператор видит тот же `evobgp-all.log`. Delete допустим как явная опция (файл исчезнет из list до следующей строки sidecar). ## 4️⃣ DECISION — Cleanup **Default:** `mode=truncate` (query param, default when omitted). **Optional:** `mode=delete` — только operator, UI second action «Удалить файл полностью». **Max file size for cleanup:** **512 MiB** — выше reject `413` / problem `file_too_large` (защита sync worker). Документировать в OpenAPI. **Handler timeout:** `60s` context на cleanup; для типичных log < 512 MiB truncate/delete — миллисекунды. **Audit:** всегда запись после успешной операции; при ошибке — no audit, `500`. ## 2️⃣ OPTIONS — Tail / preview | Option | Lines default | Bytes cap | |--------|---------------|-----------| | **T1** | 200 lines | 256 KiB | | **T2** | 500 lines | 1 MiB | | **T3** | 1000 lines | 512 KiB | ## 4️⃣ DECISION — Tail **Query params** `GET /v1/runtime-logs/files/{filename}`: | Param | Default | Max | Note | |-------|---------|-----|------| | `lines` | 200 | 2000 | Читать с конца файла | | `bytes` | — | 262144 (256 KiB) | Альтернатива lines; если оба — **min** лимит | | `grep` | — | max 128 chars | Опционально; фильтр после чтения tail chunk | **Implementation:** read last N bytes (cap 256 KiB), split lines, take last `lines` (cap 2000). Не mmap всего файла. **grep:** простой `strings.Contains` post-filter (не regex) — снижает ReDoS risk. ## 5️⃣ IMPLEMENTATION NOTES - `internal/runtimelogs/tail.go` — `TailFile(path, opts) ([]byte, truncated bool, err)` - `internal/runtimelogs/cleanup.go` — `Cleanup(path, mode) (sizeBefore, sizeAfter int64, err)` - OpenAPI enum `RuntimeLogCleanupMode: truncate | delete` - Response cleanup: `{ "audit_id", "filename", "action", "size_before", "size_after" }` - UI: primary button «Очистить (обнулить)»; secondary «Удалить файл» ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📌 **CREATIVE PHASE END: Cleanup & Tail**