v0.111.0: remote app-log diagnostics — error context capture (±5 lines, capped+redacted) + on-demand log tails via ACK pull pattern
- metrics: LogIssue.Context on first-occurrence errors (≤11 lines, ≤400 chars/line, warns carry none); RedactLine sanitizer (password/token/api-key/bearer/64-hex) applied to everything shipped; FetchContainerLogTail - report: 16KB per-report context budget (lowest-count issues dropped first); log_tail_requests ACK flag → next report ships log_tails (200 lines, ≤64KB/app head-truncated, ordered, redacted); consume-once drain - tests: synthetic-window context capture, caps, redaction, budget order, consume-once, fetch-error skip Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/metrics"
|
||||
)
|
||||
|
||||
func appWithIssue(name string, count, ctxBytes int) AppTelemetry {
|
||||
var ctx []string
|
||||
if ctxBytes > 0 {
|
||||
ctx = []string{strings.Repeat("c", ctxBytes)}
|
||||
}
|
||||
return AppTelemetry{
|
||||
AppName: name,
|
||||
Issues: []metrics.LogIssue{{Severity: "error", Message: name + " boom", Count: count, Context: ctx}},
|
||||
}
|
||||
}
|
||||
|
||||
// Part B caps — budget overflow drops context from the LOWEST-count issues first,
|
||||
// across apps. Red-proof: inverting the sort (highest first) keeps the wrong survivor.
|
||||
func TestEnforceContextBudget_DropsLowestCountFirst(t *testing.T) {
|
||||
apps := []AppTelemetry{
|
||||
appWithIssue("rare", 2, 600), // lowest count — first to lose context
|
||||
appWithIssue("frequent", 50, 600), // must keep context
|
||||
appWithIssue("medium", 10, 600), // dropped second
|
||||
}
|
||||
enforceContextBudget(apps, 1000) // total 1800 → must shed 800 → drop rare, then medium
|
||||
|
||||
if apps[0].Issues[0].Context != nil {
|
||||
t.Fatalf("lowest-count issue kept its context")
|
||||
}
|
||||
if apps[2].Issues[0].Context != nil {
|
||||
t.Fatalf("second-lowest issue kept its context (still over budget after one drop)")
|
||||
}
|
||||
if len(apps[1].Issues[0].Context) == 0 {
|
||||
t.Fatalf("highest-count issue LOST its context — wrong drop order")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnforceContextBudget_UnderBudgetUntouched(t *testing.T) {
|
||||
apps := []AppTelemetry{appWithIssue("a", 1, 100), appWithIssue("b", 2, 100)}
|
||||
enforceContextBudget(apps, 16*1024)
|
||||
if len(apps[0].Issues[0].Context) == 0 || len(apps[1].Issues[0].Context) == 0 {
|
||||
t.Fatalf("under-budget contexts must be untouched")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user