Go SDK
github.com/wearzdk/kestrel/sdks/go — independent Go module, stdlib only, no transitive dependencies.
Install
go get github.com/wearzdk/kestrel/sdks/go@latestInitialize
The common case — one project, one process — uses the package-level Init:
import kestrel "github.com/wearzdk/kestrel/sdks/go"
if err := kestrel.Init(
"https://kestrel.example.com",
os.Getenv("KESTREL_TOKEN"),
kestrel.WithRelease(os.Getenv("GIT_COMMIT")),
); err != nil {
panic(err)
}If you need an isolated client (multi-project, tests), use kestrel.NewClient(endpoint, token, opts...) instead and call methods on the returned *Client. Clients are safe to share across goroutines.
Recover panics
The idiomatic way to attach Kestrel to an existing service is one defer at the panic boundary:
func handle(w http.ResponseWriter, r *http.Request) {
defer kestrel.RecoverAndSwallow(r.Context()) // capture, then 500
// ...your handler...
}Variants:
kestrel.Recover(ctx)— captures and re-panics. Use when the surrounding code already has its own recovery (the runtime's default panic handler, or a framework's middleware).kestrel.RecoverAndSwallow(ctx)— captures and stops the panic from propagating. Use at HTTP / RPC boundaries where you want a clean 500 response instead of a crashed goroutine.
slog handler
Wire structured logging through Kestrel without changing log call sites:
import "log/slog"
base := slog.NewJSONHandler(os.Stdout, nil) // your usual handler
// nil client → use the one configured by kestrel.Init.
h := kestrel.NewSlogHandler(base, nil, slog.LevelError)
slog.SetDefault(slog.New(h))
// Anywhere downstream:
slog.Error("payment failed", "txn", txnID, "err", err)
// ...is now both written to stdout AND posted as a Kestrel event.Below the threshold, the wrapper is a pass-through — no allocation, no network. Only Error (and above) trigger an upload.
Manual capture
if err := doThing(ctx); err != nil {
kestrel.Capture(ctx, err, map[string]any{"request_id": reqID})
return err
}Flush before exit
Async sends use a goroutine pool. In short-lived programs (CLIs, serverless handlers), call kestrel.Flush(ctx) before returning so in-flight events make it out:
defer func() {
flushCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = kestrel.Flush(flushCtx)
}()What it doesn't do
The SDK does not wrap errors.Is / errors.As, instrument net/http, hook into database/sql, or modify any package you didn't explicitly hand to it. The three entry points above (Recover, slog handler, Capture) are the integration surface.
Releases
Tag with git tag sdks/go/vX.Y.Z to publish a new module version — Go's module proxy picks it up automatically. The SDK versions independently of the server and the other SDKs.