doctor
API
doctor
packageAPI reference for the doctor
package.
Imports
(8)
T
type
Severity
app/doctor/doctor.go:12-12
type Severity string
S
struct
Check
app/doctor/doctor.go:20-24
type Check struct
Fields
| Name | Type | Description |
|---|---|---|
| Severity | Severity | json:"severity" |
| Name | string | json:"name" |
| Message | string | json:"message" |
Uses
S
struct
Route
app/doctor/doctor.go:26-29
type Route struct
Fields
| Name | Type | Description |
|---|---|---|
| Method | string | json:"method" |
| Path | string | json:"path" |
S
struct
Source
app/doctor/doctor.go:31-33
type Source struct
Fields
| Name | Type | Description |
|---|---|---|
| Routes | []Route | json:"routes" |
S
struct
Report
app/doctor/doctor.go:35-37
type Report struct
Methods
Failures
Method
Returns
int
func (Report) Failures() int
{
n := 0
for _, check := range r.Checks {
if check.Severity == Fail {
n++
}
}
return n
}
Warnings
Method
Returns
int
func (Report) Warnings() int
{
n := 0
for _, check := range r.Checks {
if check.Severity == Warn {
n++
}
}
return n
}
WriteText
Method
Parameters
Returns
error
func (Report) WriteText(w io.Writer) error
{
if _, err := fmt.Fprintln(w, "foundation doctor"); err != nil {
return err
}
if _, err := fmt.Fprintln(w); err != nil {
return err
}
for _, check := range r.Checks {
if _, err := fmt.Fprintf(w, "%s %s: %s\n", check.Severity, check.Name, check.Message); err != nil {
return err
}
}
return nil
}
Fields
| Name | Type | Description |
|---|---|---|
| Checks | []Check | json:"checks" |
F
function
CheckSource
app/doctor/doctor.go:39-46
func CheckSource(src Source) Report
{
var checks []Check
checks = append(checks, checkRoutes(src.Routes)...)
checks = append(checks, checkHealth(src.Routes))
return Report{Checks: checks}
}
F
function
Run
Parameters
src
Returns
error
app/doctor/doctor.go:89-91
func Run(src Source) error
{
return RunWithEnv(src, os.Getenv("FOUNDATION_DOCTOR"), os.Stdout)
}
Uses
F
function
RunWithEnv
app/doctor/doctor.go:93-116
func RunWithEnv(src Source, mode string, w io.Writer) error
{
report := CheckSource(src)
mode = strings.ToLower(strings.TrimSpace(mode))
if mode == "" {
mode = "print"
}
switch mode {
case "off":
return nil
case "json":
return report.WriteJSON(w)
case "fail":
if err := report.WriteText(w); err != nil {
return err
}
if failures := report.Failures(); failures > 0 {
return fmt.Errorf("foundation doctor: %d failure(s)", failures)
}
return nil
default:
return report.WriteText(w)
}
}
Uses
F
function
checkRoutes
app/doctor/doctor.go:118-145
func checkRoutes(routes []Route) []Check
{
if len(routes) == 0 {
return []Check{{
Severity: Fail,
Name: "routes",
Message: "no routes registered",
}}
}
seen := make(map[string]bool, len(routes))
for _, route := range routes {
key := route.Method + " " + route.Path
if seen[key] {
return []Check{{
Severity: Fail,
Name: "routes",
Message: "duplicate route " + key,
}}
}
seen[key] = true
}
return []Check{{
Severity: OK,
Name: "routes",
Message: fmt.Sprintf("%d route(s) registered", len(routes)),
}}
}
F
function
checkHealth
app/doctor/doctor.go:147-174
func checkHealth(routes []Route) Check
{
paths := make([]string, 0, len(routes))
for _, route := range routes {
if route.Method == "GET" {
paths = append(paths, route.Path)
}
}
sort.Strings(paths)
hasLive := false
hasReady := false
for _, path := range paths {
if path == "/health" || path == "/health/live" {
hasLive = true
}
if path == "/health/ready" {
hasReady = true
}
}
if hasLive && hasReady {
return Check{Severity: OK, Name: "health", Message: "liveness and readiness routes registered"}
}
if hasLive {
return Check{Severity: Warn, Name: "health", Message: "liveness route registered without readiness route"}
}
return Check{Severity: Warn, Name: "health", Message: "no health route registered"}
}
Uses
F
function
TestCheckSourceRoutesAndHealth
Parameters
t
app/doctor/doctor_test.go:9-21
func TestCheckSourceRoutesAndHealth(t *testing.T)
{
report := CheckSource(Source{Routes: []Route{
{Method: "GET", Path: "/health/live"},
{Method: "GET", Path: "/health/ready"},
}})
if report.Failures() != 0 {
t.Fatalf("Failures() = %d, want 0", report.Failures())
}
if report.Warnings() != 0 {
t.Fatalf("Warnings() = %d, want 0", report.Warnings())
}
}
F
function
TestCheckSourceFailsWithoutRoutes
Parameters
t
app/doctor/doctor_test.go:23-29
func TestCheckSourceFailsWithoutRoutes(t *testing.T)
{
report := CheckSource(Source{})
if report.Failures() != 1 {
t.Fatalf("Failures() = %d, want 1", report.Failures())
}
}
F
function
TestRunWithEnvPrintsText
Parameters
t
app/doctor/doctor_test.go:31-41
func TestRunWithEnvPrintsText(t *testing.T)
{
var buf bytes.Buffer
err := RunWithEnv(Source{Routes: []Route{{Method: "GET", Path: "/ping"}}}, "print", &buf)
if err != nil {
t.Fatalf("RunWithEnv() error = %v", err)
}
if !strings.Contains(buf.String(), "foundation doctor") {
t.Fatalf("output = %q", buf.String())
}
}
F
function
TestRunWithEnvFailsOnFailures
Parameters
t
app/doctor/doctor_test.go:43-50
func TestRunWithEnvFailsOnFailures(t *testing.T)
{
var buf bytes.Buffer
err := RunWithEnv(Source{}, "fail", &buf)
if err == nil {
t.Fatal("RunWithEnv() error = nil, want error")
}
}
F
function
TestRunWithEnvWritesJSON
Parameters
t
app/doctor/doctor_test.go:52-62
func TestRunWithEnvWritesJSON(t *testing.T)
{
var buf bytes.Buffer
err := RunWithEnv(Source{Routes: []Route{{Method: "GET", Path: "/ping"}}}, "json", &buf)
if err != nil {
t.Fatalf("RunWithEnv() error = %v", err)
}
if !strings.Contains(buf.String(), `"checks"`) {
t.Fatalf("output = %q", buf.String())
}
}