From 408aa3ba7de46bb6e12af8ae2595498ed8393fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 15:46:01 -0400 Subject: [PATCH] Merge Dashboards & Dev Tools; WaterfallSpan; port to public ChartSpec --- trace_waterfall.go | 10 +++++----- trace_waterfall_test.go | 12 ++++++------ uptime_bar.go | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/trace_waterfall.go b/trace_waterfall.go index 9ac6b6b..5483fa4 100644 --- a/trace_waterfall.go +++ b/trace_waterfall.go @@ -14,8 +14,8 @@ import ( "mujicaui/theme" ) -// TraceSpan is one timed operation of a request; Parent is "" for the root. -type TraceSpan struct { +// WaterfallSpan is one timed operation of a request; Parent is "" for the root. +type WaterfallSpan struct { ID, Parent string Name string Service string @@ -45,7 +45,7 @@ type traceState struct { } // TraceWaterfall lays spans out by parent and time; choosing a span shows its detail. -func TraceWaterfall(c *ui.Context, spans []TraceSpan, opts TraceWaterfallOptions) ChoiceResult { +func TraceWaterfall(c *ui.Context, spans []WaterfallSpan, opts TraceWaterfallOptions) ChoiceResult { if opts.Height < 0 { panic("mujica: TraceWaterfall Height is negative") } @@ -89,7 +89,7 @@ func TraceWaterfall(c *ui.Context, spans []TraceSpan, opts TraceWaterfallOptions } // traceLayout orders spans depth-first by start, only when the spans change. -func traceLayout(st *traceState, spans []TraceSpan) { +func traceLayout(st *traceState, spans []WaterfallSpan) { key := fmt.Sprintf("%d", len(spans)) if len(spans) > 0 { key += fmt.Sprintf("%p", &spans[0]) @@ -135,7 +135,7 @@ func traceLayout(st *traceState, spans []TraceSpan) { } // traceSpanRow shows a span's name indented by depth beside its bar; it reports a choice. -func traceSpanRow(c *ui.Context, s TraceSpan, depth int, total time.Duration, slot int, selected bool) bool { +func traceSpanRow(c *ui.Context, s WaterfallSpan, depth int, total time.Duration, slot int, selected bool) bool { k := Tokens(c) d := Density(c) u := d.Unit() diff --git a/trace_waterfall_test.go b/trace_waterfall_test.go index a15ad5a..54ccd23 100644 --- a/trace_waterfall_test.go +++ b/trace_waterfall_test.go @@ -8,14 +8,14 @@ import ( "github.com/egoist/mygo/ui" ) -var traceSample = []TraceSpan{ +var traceSample = []WaterfallSpan{ {ID: "db", Parent: "api", Name: "SELECT guests", Service: "postgres", Start: 40 * time.Millisecond, Duration: 90 * time.Millisecond}, {ID: "root", Name: "GET /ball", Service: "gateway", Duration: 320 * time.Millisecond}, {ID: "api", Parent: "root", Name: "ListGuests", Service: "api", Start: 20 * time.Millisecond, Duration: 200 * time.Millisecond}, {ID: "pay", Parent: "root", Name: "Charge", Service: "payments", Start: 230 * time.Millisecond, Duration: 80 * time.Millisecond, Error: true}, } -func traceTester(spans []TraceSpan, changes *int) *ui.Tester { +func traceTester(spans []WaterfallSpan, changes *int) *ui.Tester { return ui.NewTester(func(c *ui.Context) { Use(c, Settings{}) if TraceWaterfall(c, spans, TraceWaterfallOptions{}).Changed() { @@ -54,10 +54,10 @@ func TestTraceWaterfallRulesAndMany(t *testing.T) { if !tt.HasText("No spans") { t.Fatal("empty") } - many := make([]TraceSpan, 100000) - many[0] = TraceSpan{ID: "0", Name: "root", Duration: time.Second} + many := make([]WaterfallSpan, 100000) + many[0] = WaterfallSpan{ID: "0", Name: "root", Duration: time.Second} for i := 1; i < len(many); i++ { - many[i] = TraceSpan{ID: fmt.Sprint(i), Parent: "0", Name: fmt.Sprint("span ", i), Start: time.Duration(i) * time.Microsecond, Duration: time.Microsecond} + many[i] = WaterfallSpan{ID: fmt.Sprint(i), Parent: "0", Name: fmt.Sprint("span ", i), Start: time.Duration(i) * time.Microsecond, Duration: time.Microsecond} } tt = traceTester(many, &n) if got := len(tt.Texts()); got > 400 { @@ -68,7 +68,7 @@ func TestTraceWaterfallRulesAndMany(t *testing.T) { t.Fatal("cycle did not panic") } }() - traceTester([]TraceSpan{{ID: "a", Parent: "b", Name: "a"}, {ID: "b", Parent: "a", Name: "b"}}, &n) + traceTester([]WaterfallSpan{{ID: "a", Parent: "b", Name: "a"}, {ID: "b", Parent: "a", Name: "b"}}, &n) } func TestTraceWaterfallSnapshot(t *testing.T) { diff --git a/uptime_bar.go b/uptime_bar.go index 9c1fe37..c92eda8 100644 --- a/uptime_bar.go +++ b/uptime_bar.go @@ -60,9 +60,9 @@ func UptimeBar(c *ui.Context, days []UptimeDay, opts UptimeBarOptions) ChartResu return 0 } words := [...]string{msg(c, "uptime_bar.ok"), msg(c, "uptime_bar.degraded"), msg(c, "uptime_bar.down"), msg(c, "uptime_bar.nodata")} - res, _ := ch.build(chartSpec{ - n: n, - draw: func(p *ui.Painter, r ui.Rect, active int) { + res, _ := ch.build(ChartSpec{ + Marks: n, + Draw: func(p *ui.Painter, r ui.Rect, active int) { b := band(r) for i, d := range days { x, w := internal.Snap(p, b.Start(i)), max(b.Width(), 1) @@ -76,11 +76,11 @@ func UptimeBar(c *ui.Context, days []UptimeDay, opts UptimeBarOptions) ChartResu } } }, - pick: func(r ui.Rect, x, _ float32) int { + Pick: func(r ui.Rect, x, _ float32) int { b := band(r) return max(0, min(n-1, int((x-r.X)/b.Step()))) }, - readout: func(i int) string { + Readout: func(i int) string { d := days[i] s := fmt.Sprintf("%s ยท %s", d.Date.String(), words[level(d.Uptime)]) if !math.IsNaN(d.Uptime) {