Skip to content

Go SDK

github.com/wearzdk/kestrel/sdks/go — independent Go module, stdlib only, no transitive dependencies.

Install

bash
go get github.com/wearzdk/kestrel/sdks/go@latest

Initialize

The common case — one project, one process — uses the package-level Init:

go
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:

go
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:

go
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

go
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:

go
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.

Released under the MIT License.