Skip to main content

Diagnostics

Diagnostics warn about patterns no single query would show you. They count within a scope, usually one web request, and cost a little per statement.

Setting it up​

db, err := ant.Open[AppDB](ctx, postgres.Dialect, dsn,
ant.WithDiagnostics(ant.Diagnostics{
RepeatLimit: 10,
Budget: 500 * time.Millisecond,
Alert: func(ctx context.Context, a ant.Alert) {
slog.Warn("database", "kind", a.Kind, "message", a.Message, "sql", a.SQL)
},
}),
)

The default Alert logs through slog.

A scope per request​

ant.Watch starts counting. Without a scope, repeats and budgets don't count.

func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r.WithContext(ant.Watch(r.Context())))
})
}

What it finds​

KindMeans
repeatedOne statement ran more than RepeatLimit times in a scope, which is what N+1 looks like
budgetStatements spent longer than Budget in total, which a slow-query log can't see if each is fast
cartesianA query joined two to-many relations, which multiplies rows. This warns with or without a scope