Documentation
¶
Overview ¶
Package doctor is `weft doctor` (plan B5): it asks a running Studio what it is and how it is wired, and prints one line per check. Every line reads one field of GET /api/meta (Lines is the table) — beside it, for the runtime check, the two environment variables the doctor's own shell can see (WEFT_ENV, WEFT_STUDIO_URL), and for the discovery check the discovery file this shell reads (Target.Discovery, the command's resolver's). The doctor computes nothing Studio does not serve: a second source of truth would drift.
The logic lives here, apart from the command wiring (cmd/weft), so the command stays a thin client of it.
Index ¶
Examples ¶
Constants ¶
const Timeout = 5 * time.Second
Timeout bounds the one request the doctor makes: an unreachable or hung Studio is a clear first line, never a hang.
Variables ¶
var ErrUnhealthy = errors.New("doctor: a check failed")
ErrUnhealthy is Run's error when any check failed: the command exits 1.
var Lines = []Line{ {"studio", []string{"status", "weft_version", "studio_version"}}, {"token", []string{"status", "auth_required"}}, {"discovery", []string{"discovery_file", "db.path", "local:discovery"}}, {"db", []string{"db.kind", "db.path", "db.size"}}, {"content", []string{"content.ingest", "content.latest.run_id", "content.latest.mark", "content.latest.note", "content.latest.fix", "content.error"}}, {"data", []string{"content.latest.started", "content.latest.weft_version", "content.latest.service", "weft_version"}}, {"otlp", []string{"ingest_open", "capabilities"}}, {"ingest", []string{"ingest.dropped", "ingest.accepted", "ingest.refused", "ingest.last_error", "ingest.last_at"}}, {"runtimes", []string{"runtimes", "capabilities", "capabilities_off", "env:WEFT_ENV", "env:WEFT_STUDIO_URL"}}, {"panel", []string{"panel_version", "studio_version"}}, {"manifest", []string{"has_manifest", "manifest_check.source", "manifest_check.agents", "manifest_check.checked", "manifest_check.stale", "manifest_check.error"}}, }
Lines is the doctor's line table, in print order.
Functions ¶
func Run ¶
Run checks the Studio t names (t.Token "" sends none) and prints one line per check to w. getenv reads the doctor's own environment (the runtime check reports WEFT_ENV and WEFT_STUDIO_URL as this shell sees them). It returns ErrUnhealthy when a check failed — Studio not reachable, the token refused, a stale panel bundle — and nil otherwise; warnings (no runtime connected, content stripped, a stale weft.json, a discovery file naming another Studio) do not fail it.
Example ¶
ExampleRun checks a Studio with nothing connected to it: one line per check, each read from its /api/meta. No discovery file names it (an embedded Studio writes none): that line warns. With the playground on and no runtime connected the runtimes line warns, and its continuation lines name the variables this shell lacks (WEFT_ENV, WEFT_STUDIO_URL).
package main
import (
"context"
"fmt"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"github.com/weftgo/weft/internal/doctor"
"github.com/weftgo/weft/studio"
)
func main() {
dir, _ := os.MkdirTemp("", "doctor")
defer func() { _ = os.RemoveAll(dir) }()
srv := studio.New(studio.Open(filepath.Join(dir, "weft.db")), studio.Playground(true))
defer func() { _ = srv.Close() }()
ts := httptest.NewServer(srv.Handler())
defer ts.Close()
var out strings.Builder
err := doctor.Run(context.Background(), &out, doctor.Target{URL: ts.URL}, func(string) string { return "" })
for _, line := range strings.Split(strings.TrimSpace(out.String()), "\n") {
if f := strings.Fields(line); !strings.HasPrefix(line, " ") {
fmt.Println(f[0], f[1])
} else if strings.Contains(line, "WEFT_ENV is unset") {
fmt.Println(" names WEFT_ENV")
}
}
fmt.Println("err:", err)
}
Output: ok studio ok token warn discovery ok db ok content ok data ok otlp ok ingest warn runtimes names WEFT_ENV ok panel ok manifest err: <nil>
Types ¶
type Discovery ¶ added in v0.20.0
type Discovery struct {
// Off is WEFT_DISCOVERY=off in this shell: no file is read.
Off bool
// Path is the trusted file found, "" when none.
Path string
// URL, DB and PID are what the file names.
URL, DB string
PID int
}
Discovery is the discovery file the doctor's shell reads (the resolver's view of it, read with internal/discovery's trust rules).
type Line ¶
Line is one check the doctor prints: its label and the /api/meta fields (or "env:NAME" for a variable of the doctor's own shell, "local:discovery" for the discovery file it reads, or "status" for the meta response itself) it reads.
type Target ¶ added in v0.20.0
type Target struct {
// URL is the Studio's root URL.
URL string
// Token is the bearer to send, "" for none.
Token string
// Discovery is the discovery file this shell reads.
Discovery Discovery
}
Target is the Studio the doctor checks, found by cmd/weft's one resolver (--url, WEFT_STUDIO_URL, the discovery file, the default address), which names the source on stderr itself: the doctor's own lines do not repeat it.