chronexis

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: MIT Imports: 11 Imported by: 0

README

chronexis-go

Crash capture and reporting SDK for Go services. Wraps your HTTP handlers, catches panics, and reports the full stack trace to Chronexis for AI-driven root-cause diagnosis — without crashing your process or blocking your request path.

Install

go get github.com/Alraies97/chronexis-go

Quickstart

handler := chronexis.Middleware(
    "your-api-key",
    "https://your-chronexis-host/v1/traces",
)(yourExistingHandler)

http.ListenAndServe(":8080", handler)

That's it — any panic inside yourExistingHandler is now caught, reported asynchronously, and the original request still fails with a 500, same as before.

Manual capture (non-HTTP code paths)

For background jobs, goroutines, or cron tasks with no incoming request:

chronexis.Init("your-api-key", "https://your-chronexis-host/v1/traces")

func runJob() {
    if err := doWork(); err != nil {
        chronexis.CaptureError(err)
    }
}

Graceful shutdown

Reports are sent asynchronously in the background. Flush before your process exits so nothing queued gets lost:

service := chronexis.New(apiKey, ingestURL)
// ... use service.Flush(ctx) during shutdown, e.g. after http.Server.Shutdown

Options

Option Default Purpose
WithTimeout(d) 5s Per-request HTTP timeout
WithMaxRetries(n) 2 Total send attempts before giving up
WithBaseRetryDelay(d) 250ms Initial backoff delay (doubles each retry)
WithBufferSize(n) 256 Pending reports queued before new ones are dropped
WithWorkers(n) 4 Concurrent goroutines sending queued reports
WithOnCapture(fn) none Hook called synchronously the moment a crash is captured
WithHTTPClient(c) *http.Client Inject a custom client (testing, proxies)

Design notes

  • Never blocks the request path. Sends happen on a bounded worker pool; if the buffer is full, reports are dropped and logged locally rather than stalling your service.
  • Retries with exponential backoff, capped, so a transient network blip doesn't lose a report but a persistent outage doesn't retry forever.
  • OnCapture fires regardless of network outcome — your own logging or alerting doesn't depend on Chronexis's uptime.
  • A 429 pauses sending rather than consuming retries. The pause length comes from Retry-After (integer seconds, then an HTTP-date, then a retry_after JSON body field), defaulting to 60s — the server's minute window — when none of those parse. Values above 24 hours are rejected as implausible rather than clamped; 24h is the ceiling because a daily-quota 429 pauses until UTC midnight.

Changelog

See CHANGELOG.md. v0.2.2 raises the Retry-After ceiling to 24 hours so a daily-quota 429 is honored instead of rejected. v0.2.1 fixes two bugs found by the Chronexis conformance suite — a panicking OnCapture callback could crash the caller, and Flush() could report success before a payload was actually delivered.

License

See LICENSE.

Documentation

Index

Constants

View Source
const Version = "0.2.2"

Variables

This section is empty.

Functions

func CaptureError

func CaptureError(err error)

func Middleware

func Middleware(apiKey, ingestURL string, opts ...Option) func(http.Handler) http.Handler

Types

type HTTPDoer

type HTTPDoer interface {
	Do(req *http.Request) (*http.Response, error)
}

type OnCaptureFunc

type OnCaptureFunc func(payload map[string]interface{})

type OnDropFunc added in v0.2.0

type OnDropFunc func(payload map[string]interface{}, reason string)

OnDropFunc is called whenever a captured payload is dropped instead of delivered — either the send buffer was full ("buffer_full"), or the service is paused after a 429 response ("rate_limited"). It runs on a worker goroutine; a panic inside fn is recovered so a misbehaving callback can never kill a worker.

type Option

type Option func(*Service)

func WithBaseRetryDelay

func WithBaseRetryDelay(d time.Duration) Option

func WithBufferSize

func WithBufferSize(n int) Option

func WithHTTPClient

func WithHTTPClient(c HTTPDoer) Option

func WithMaxRetries

func WithMaxRetries(n int) Option

func WithOnCapture

func WithOnCapture(fn OnCaptureFunc) Option

func WithOnDrop added in v0.2.0

func WithOnDrop(fn OnDropFunc) Option

func WithTimeout

func WithTimeout(d time.Duration) Option

func WithWorkers

func WithWorkers(n int) Option

type Service

type Service struct {
	// contains filtered or unexported fields
}

func Default added in v0.1.1

func Default() *Service

func Init

func Init(apiKey, ingestURL string, opts ...Option) *Service

func New

func New(apiKey, ingestURL string, opts ...Option) *Service

func (*Service) Close

func (s *Service) Close()

Close stops accepting new sends and blocks until all workers exit after draining the queue. If the service is currently paused after a 429, every remaining queued payload drains as an immediate drop rather than being sent — Close does not wait out the pause. The number of payloads dropped this way is logged once as a single aggregate line before Close returns.

func (*Service) Flush

func (s *Service) Flush(ctx context.Context) error

Flush blocks until every payload accepted before this call was resolved -- delivered, permanently dropped (buffer full at capture time, or rate-limited), or failed after exhausting retries -- or until ctx is done. It snapshots the accepted count at call time, so payloads captured concurrently with or after the call are not waited on; that's what makes "before this call" well-defined for concurrent callers.

If the service is currently paused after a 429, payloads dequeued during the call drain immediately as drops rather than being sent — Flush does not wait out the pause, it only waits for that drop itself to be recorded as resolved, which happens essentially immediately (no sleep on that path). A caller that needs an actual pause to clear before exiting should check separately rather than relying on Flush for that.

The number of payloads dropped as rate-limited during the call is logged once as a single aggregate line, not once per payload.

Directories

Path Synopsis
examples
basic command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL