Go SDK
Module github.com/kingtechies/linearjeph-sdk/go 1.0.0, MIT licensed, Go 1.21+, standard library only.
Install
go get github.com/kingtechies/linearjeph-sdk/goThe module lives in the public repository github.com/kingtechies/linearjeph-sdk (folder go/, tags go/vX.Y.Z). Pin a version with go get github.com/kingtechies/linearjeph-sdk/[email protected].
Quickstart
package main
import (
"net/http"
"os"
"time"
linearjeph "github.com/kingtechies/linearjeph-sdk/go"
)
func main() {
linearjeph.Init(linearjeph.Options{Key: os.Getenv("LINEARJEPH_KEY"), Release: "1.4.2"})
defer linearjeph.Flush(5 * time.Second)
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok")) })
http.ListenAndServe(":8080", linearjeph.Recover(mux))
}Get the key from Dashboard > Maintenance > your application > Reveal key. Go has no exit hook, so call Flush (or Close) before main returns; defer does not run on os.Exit or log.Fatal.
Options
Init(o Options) error returns an error only when Key is empty (the SDK then stays disabled). Calling it again replaces the configuration.
| Field | Type | Default | Meaning |
|---|---|---|---|
Key | string | required | Application ingest key. |
Endpoint | string | https://linearjeph.cc | Base URL; change only for a private deployment. |
Release | string | "" | Version or build identifier (max 100 chars). |
Environment | string | "production" | Max 40 chars. |
SampleRate | float64 | 1 | Fraction of errors and messages sent. 0 means 1 (send all); use a value in (0,1] to sample. |
TracesRate | float64 | 1 | Fraction of transactions sent. 0 means 1. |
BeforeSend | func(Event) Event | nil | Change the event or return nil to drop it. A panic in the hook drops the event. Event is map[string]any. |
ScrubKeys | []string | nil | Extra tag-key substrings to filter, case-insensitive. |
QueueSize | int | 100 | Items waiting to be sent; when full new items are dropped (Dropped() counts them). |
BatchSize | int | 20 | Events per request, 1 to 100. |
Retries | int | 4 | Retries for 429, 5xx and network errors; a negative value disables retries. |
Backoff | time.Duration | 500ms | Base delay, doubles per attempt with jitter. Retry-After on 429 is used instead (max 60 s). |
Timeout | time.Duration | 10s | Per-request timeout. |
Debug | bool | false | Log SDK problems to stderr. |
HTTPClient | *http.Client | new client | Use for proxies or custom TLS. |
Functions
| Function | Description |
|---|---|
Init(Options) error | Configure and start the sender goroutine. |
Capture(v any) | Report an error, a string or any value. Works with Capture(recover()). nil is ignored. |
CaptureError(err error) | Report an error with the stack at the call site. |
CaptureErrorTags(err, map[string]string) | The same with extra tags for this event. |
CaptureMessage(msg string) | Report a message as an event of type Message. |
CaptureTransaction(name string, d time.Duration, status string) | Report one timed operation. |
StartTransaction(name) *Txn | t.End("ok") or t.EndErr(err) records it once. |
Heartbeat(name, status string, intervalS int) | Check in. status is "ok" or "error"; intervalS 30 to 2,592,000 (0 = not set). Names must match [A-Za-z0-9._-]{1,64}, otherwise ignored. |
Monitor(name string, intervalS int, fn func() error) error | Run fn; heartbeat ok when it returns nil, error otherwise (the error is returned unchanged). A panic sends error and continues to panic. |
ReportPackages() int | Send the modules compiled into the binary (runtime/debug.ReadBuildInfo). Returns the number queued; 0 if build info is unavailable. |
ReportGoSum(path string) (int, error) | Parse a go.sum and send its modules (the /go.mod hash lines are ignored). |
ReportGoMod(path string) (int, error) | Parse the require directives of a go.mod and send them. |
SetTag(key, value string) / SetUser(id string) | Tag or identify every later event. |
Scrub(v any) any | Deep copy with sensitive values replaced by [Filtered]. |
Flush(timeout) bool | Wait until the queue is delivered. |
Close(timeout) bool | Flush and stop the sender. |
Dropped() int64 | Items dropped because the queue was full. |
Recover(next http.Handler) http.Handler | Middleware: times requests and captures panics. |
RecoverWith(next, RecoverOptions) http.Handler | The same with options (below). |
Every function is safe for concurrent use, returns promptly and recovers from its own panics.
net/http middleware
Recover records one transaction per request (status error for 5xx responses and panics) and captures panics, then re-panics so net/http logs the panic and closes the connection exactly as it would without the SDK. http.ErrAbortHandler is passed through without being reported.
Transaction names are METHOD pattern from the ServeMux pattern on Go 1.23+ (for example GET /items/{id}) and METHOD path on older versions. To avoid one transaction name per id with another router, give a name function:
h := linearjeph.RecoverWith(router, linearjeph.RecoverOptions{
IgnorePaths: []string{"/health"},
Name: func(r *http.Request) string { return r.Method + " " + routePattern(r) },
NoRepanic: false, // true: answer 500 instead of re-panicking
})Chi, Gin, Echo and Gorilla all work by wrapping the router as the http.Handler, or with their own middleware that calls CaptureError and StartTransaction.
Panics in goroutines
go func() {
defer func() { linearjeph.Capture(recover()) }()
work()
}()(This swallows the panic. Re-panic after Capture if the process should still crash.)
Cron jobs and heartbeats
func main() {
linearjeph.Init(linearjeph.Options{Key: os.Getenv("LINEARJEPH_KEY")})
err := linearjeph.Monitor("nightly-report", 86400, buildReport)
linearjeph.Flush(5 * time.Second)
if err != nil {
log.Fatal(err)
}
}The first check-in creates the monitor. A failed run, or no check-in within the interval plus 5 minutes, opens an incident and sends alerts.
Dependency audit
linearjeph.ReportPackages() // modules in the running binary
linearjeph.ReportGoSum("go.sum") // or from files, for example in CIEach call replaces the previously reported Go package list, so call it once per deploy.
Release tracking in CI
Inject the release at build time:
go build -ldflags "-X main.release=${GITHUB_REF_NAME}+${GITHUB_RUN_NUMBER}" ./cmd/appvar release = "dev"
// ...
linearjeph.Init(linearjeph.Options{Key: key, Release: release})Sampling, scrubbing and BeforeSend
linearjeph.Init(linearjeph.Options{
Key: key,
SampleRate: 0.5,
TracesRate: 0.1,
ScrubKeys: []string{"ssn"},
BeforeSend: func(e linearjeph.Event) linearjeph.Event {
if tags, ok := e["tags"].(map[string]string); ok {
tags["tenant"] = "acme"
}
return e // return nil to drop
},
})Tag values under keys containing password, secret, token, authorization, auth, cookie, api_key, session, csrf, bearer, credential or private_key (plus ScrubKeys) become [Filtered], and password=... or Bearer ... in messages is masked. The SDK never reads request headers, bodies or cookies. Sampling is applied before BeforeSend.
Troubleshooting
- Set
Debug: trueto see dropped requests. - A 401 prints "ingest key rejected" once and stops sending.
- Events missing at exit:
Flushwas not called, or the process ended throughos.Exit. - Stack frames from the Go standard library, the module cache and the SDK itself are marked not in-app, so issues group by your code.
- See Troubleshooting and the Ingest HTTP API.