Go SDK
Go 1.22+, zero-dependency (stdlib only). Functional options for config, http.RoundTripper instrumentation, and non-blocking background delivery. Run IDs are available immediately.
Install
go get github.com/agent-ping/agent-ping-go
Package is agentping.
Quickstart
package main
import (
"context"
"os"
"github.com/agent-ping/agent-ping-go"
)
func main() {
_ = agentping.Init(agentping.WithAPIKey(os.Getenv("AGENTPING_API_KEY")))
defer agentping.Shutdown(context.Background())
run := agentping.NewRun("support-triage",
agentping.WithCustomerID("acme-corp"),
)
_ = run.Event("log", map[string]any{"message": "classifying ticket"})
_ = run.Event("llm_call", map[string]any{
"provider": "anthropic",
"model": "claude-sonnet-4-5",
"input_tokens": 1024,
"output_tokens": 312,
"latency_ms": 1430,
})
_ = run.Finish(agentping.FinishStatusSuccess,
agentping.WithScores(map[string]any{"confidence": 0.93}),
)
}
run.ID is populated synchronously on return. POST /v1/runs dispatches in the background.
Auto-instrumentation
Go has no equivalent global-rewrite mechanism. The SDK ships http.RoundTripper wrappers and helpers that build a ready-to-use *http.Client:
import (
"net/http"
"github.com/agent-ping/agent-ping-go"
"github.com/agent-ping/agent-ping-go/instrumentation"
)
run := agentping.NewRun("answer-bot")
httpClient := instrumentation.AnthropicHTTPClient(http.DefaultTransport, run)
openaiClient := instrumentation.OpenAIHTTPClient(http.DefaultTransport, run)
Pass the client to the Anthropic or OpenAI SDK. For finer control, use the raw transport:
client := anthropic.NewClient(
option.WithHTTPClient(&http.Client{
Transport: instrumentation.NewAnthropicTransport(http.DefaultTransport, run),
}),
)
The transport captures provider, model, token counts from the response body and emits llm_call. Cost is computed server-side.
Heartbeats
_ = agentping.Heartbeat("daily-summary", agentping.HeartbeatStatusOK,
agentping.WithCostUSD(0.084),
agentping.WithDurationMs(12_300),
agentping.WithHeartbeatMetadata(map[string]any{"rows": 421}),
)
Same table as full runs.
Streaming
Streaming is wrapped at the http.RoundTripper layer. The wrapper installs an io.ReadCloser that observes chunks, accumulates token counts, and emits a single llm_call on body close. Reads are never delayed.
A mid-stream error emits a failed event with partial counts.
Context propagation
// Env var, picked up by agentping.NewRun automatically:
// AGENTPING_PARENT_RUN=run_eu_018f3a2b9c1d7e8fa4b9c2d7e8f1a3b6
// Explicit option:
run := agentping.NewRun("price-fetcher",
agentping.WithParentRunID("run_eu_018f3a2b9c1d7e8fa4b9c2d7e8f1a3b6"),
)
Explicit option wins.
Configuration
| Option | Default | Description |
|---|---|---|
WithAPIKey |
AGENTPING_API_KEY env |
apk_<region>_<32 hex> |
WithBaseURL |
derived from the key region (https://<region>.ingest.agentping.io); AGENTPING_BASE_URL also overrides |
Override for self-hosting or testing |
WithQueueSize |
1000 | Max envelopes in memory |
WithFlushInterval |
2s | Background drain interval |
WithBatchSize |
50 | Max events per HTTP POST |
WithHTTPClient |
&http.Client{} |
Inject your own (useful for tests) |
Shutdown
No atexit-style hook (not idiomatic Go). Shutdown(ctx) drains the queue under the caller's context:
func main() {
_ = agentping.Init(agentping.WithAPIKey(os.Getenv("AGENTPING_API_KEY")))
defer agentping.Shutdown(context.Background())
// your agent code
}
Skip Shutdown and in-flight events may be lost on process exit.
Source
github.com/agent-ping/agent-ping-go. Public surface in agentping.go.