feat: log structured reconnect diagnostics for kiosk display layers (#2)
Build Ground Station / build (push) Successful in 1m2s
Build Ground Station / build (push) Successful in 1m2s
This commit was merged in pull request #13.
This commit is contained in:
@@ -44,6 +44,28 @@ func buildTarget(name string) ([]display.Layer, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// wireDiagnostics gives every layer the shared structured reconnect hook so
|
||||
// each layer reports its own reconnect boundaries, identified by target and
|
||||
// layer name.
|
||||
func wireDiagnostics(target string, layers []display.Layer) {
|
||||
for i := range layers {
|
||||
layers[i].Options = display.Options{
|
||||
Target: target,
|
||||
Layer: layers[i].Name,
|
||||
Diagnostic: func(d display.Diagnostic) {
|
||||
log.Printf("display reconnect: %s", formatDiagnostic(d))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formatDiagnostic renders one reconnect diagnostic as key=value fields so
|
||||
// reconnects stay greppable and machine-parseable in the journal.
|
||||
func formatDiagnostic(d display.Diagnostic) string {
|
||||
return fmt.Sprintf("target=%s layer=%s event=%s error=%q retry_delay=%s",
|
||||
d.Target, d.Layer, d.Event, d.Err, d.RetryDelay)
|
||||
}
|
||||
|
||||
func main() {
|
||||
target := flag.String("target", "x11", "display target: x11 (Viture) today; mipi planned")
|
||||
flag.Parse()
|
||||
@@ -52,11 +74,13 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
wireDiagnostics(*target, layers)
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
// Temporary X11 unavailability never exits this process; every layer
|
||||
// keeps retrying internally until the context is cancelled.
|
||||
// keeps retrying internally until the context is cancelled, reporting
|
||||
// each reconnect boundary through the structured diagnostic hook.
|
||||
display.RunLayers(ctx, layers)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.piksar.eu/piotr/groundstation/internal/display"
|
||||
)
|
||||
@@ -83,3 +85,41 @@ func TestBuildTargetRejectsUnknownTarget(t *testing.T) {
|
||||
t.Fatal("unknown target must fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatDiagnosticRendersStructuredFields(t *testing.T) {
|
||||
got := formatDiagnostic(display.Diagnostic{
|
||||
Target: "x11",
|
||||
Layer: "fallback-canvas",
|
||||
Event: display.EventOpenFailed,
|
||||
Err: errors.New("connect X11: refused"),
|
||||
RetryDelay: 500 * time.Millisecond,
|
||||
})
|
||||
want := `target=x11 layer=fallback-canvas event=open_failed error="connect X11: refused" retry_delay=500ms`
|
||||
if got != want {
|
||||
t.Fatalf("formatDiagnostic=%q want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireDiagnosticsTagsEveryLayerWithItsName(t *testing.T) {
|
||||
layers, err := buildTarget("x11")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wireDiagnostics("x11", layers)
|
||||
|
||||
for _, layer := range layers {
|
||||
if layer.Options.Target != "x11" {
|
||||
t.Fatalf("layer %q target=%q want x11", layer.Name, layer.Options.Target)
|
||||
}
|
||||
if layer.Options.Layer != layer.Name {
|
||||
t.Fatalf("layer %q diagnostic layer=%q", layer.Name, layer.Options.Layer)
|
||||
}
|
||||
if layer.Options.Diagnostic == nil {
|
||||
t.Fatalf("layer %q must carry the reconnect diagnostic hook", layer.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// The shared hook must be safe to call from any layer goroutine.
|
||||
layers[0].Options.Diagnostic(display.Diagnostic{Target: "x11", Layer: layers[0].Name})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user