Instrument
Go
Instrument Go services with metrics, traces, logs, errors, and request-scoped customer identity.
Use the Go SDK for server-side traces, metrics, structured logs, errors, diagnostic events, and customer identity.
Install and start
go get github.com/anectico/anectico/sdks/go@main
ctx := context.Background()
client, err := anectico.New(
anectico.WithAPIKey(os.Getenv("ANECTICO_API_KEY")),
anectico.WithServiceName("orders-api"),
anectico.WithEnvironment("production"),
)
if err != nil {
return err
}
if err := client.Start(ctx); err != nil {
return err
}
defer func() {
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = client.Stop(shutdownCtx)
}()
Keep one client for the application. A client per request prevents batching and correlation.
Stop marks the client non-running and lets its first caller perform the final
flush, bounded by both that caller’s context and ShutdownTimeout. Concurrent
callers wait for that same flush and receive the same terminal result. A
waiting caller whose own context expires returns its context error without
canceling the shared shutdown; a later call after completion returns the
completed result. Starting the client again waits for an in-flight stop and
begins a fresh lifecycle.
Handle SIGTERM and os.Interrupt with a bounded shutdown context, and check
the Stop error before the process exits. Do not rely on a deferred stop after
os.Exit, because deferred functions do not run. SIGKILL cannot be caught,
so no SDK can guarantee a final telemetry flush when the process is killed
that way; leave enough orchestrator termination grace for the configured
shutdown deadline.
Use a project-scoped key with ingest:write. Add analytics:write when calling Identify, Group,
or diagnostic-event methods, as this guide does. Do not give an application key read or management
scopes.
Trace work and capture errors
requestCtx := anectico.ContextWithDistinctID(ctx, userID)
traceCtx, span := client.StartSpan(requestCtx, "process-order")
defer span.End()
if err := processOrder(traceCtx); err != nil {
client.CaptureError(traceCtx, err, anectico.WithTag("component", "checkout"))
return err
}
Pass the returned context through downstream calls. Request-scoped identity is concurrency-safe and
takes precedence over process identity. Use client.Identify only for a single-user process or an
explicit identity merge, and reset identity on logout in stateful client applications. Reset
also clears groups, global error-user context, and uncaptured breadcrumbs; telemetry captured before
the boundary remains queued with its original attribution.
Record an application metric
client.RecordMetric("checkout.queue_depth", float64(queueDepth), map[string]string{
"region": "eu-west",
"worker_pool": "payments",
})
RecordMetric records a gauge value and reuses the instrument by name. Use client.Meter() to
create an explicit counter or histogram. Keep labels low-cardinality; do not add customer, order,
request, trace, or session IDs.
HTTP and gRPC propagation
Use the SDK’s HTTP transport or gRPC interceptors with the request context so W3C traceparent and
the anectico.distinct_id baggage member continue to trusted downstream services. At inbound public
boundaries, do not accept customer identity baggage unless a trusted gateway has removed and
recreated client-supplied headers.
The unary and streaming gRPC client interceptors preserve existing application
metadata and inject the newly started client span plus identity baggage.
Streaming spans remain active until EOF, the one response of a client-streaming
call, a failed stream operation, or caller-context cancellation. A successful
CloseSend only closes the send side; it does not end the span before the
response status arrives.
Client gRPC transport failures remain error-status spans and do not create
duplicate Issues. On instrumented internal RPCs, the server interceptor captures
one Issue occurrence only for unexpected server failures such as
ResourceExhausted, Internal, or DataLoss; cancellation, deadlines, and
expected caller/control statuses remain spans only. The SDK marks
non-canonical transport spans with anectico.issue.suppressed=true, which remains
effective when exporter batches separate the transport span from its
error.capture child. A successful server capture also correlates the parent
with its error.id. If capture is disabled, sampled out, fails, or returns no
ID, the actionable server transport span remains eligible as the fallback
Issue. For external dependencies, capture one typed domain error after retries
are exhausted when the failure should become an Issue.
Both the package-level anectico.WrapHTTPClient / anectico.WrapHTTPTransport
helpers and the corresponding client-bound methods mark every generated
outbound HTTP client span with anectico.issue.suppressed=true. Failed and canceled
round trips remain visible with their original span status, propagation, and
HTTP metrics, but these transport spans do not create stackless duplicate
Issues. When an HTTP dependency failure is actionable, classify it at the
application or domain boundary after retries are exhausted and call
CaptureError once with an explicit typed error.
For net/http, derive the Anectico request context from r.Context() and pass it through handlers,
database operations, and outbound requests. Equivalent instrumentation packages are available for
gRPC and supported framework adapters.
For Gin, add instrumentation/gin.Middleware(client) after Gin’s recovery middleware (the order
already provided by gin.Default()). Anectico captures c.Errors and recovered handler panics while
Gin retains control of the recovery response. A recovered panic keeps an error-marked request span
in the trace and creates one canonical, stacked error.capture Issue occurrence—not a duplicate
Issue for each span. The opposite middleware order also captures panics, but Gin’s standard recovery
discards the original panic value before Anectico can read it; the captured event therefore has a
generic message and the original handler stack.
Structured logs
The client exposes an slog logger and the process-level LogEvent convenience method. Use the
logger’s context-aware methods for request work so records inherit the active trace and customer
identity.
client.Logger().LogAttrs(
traceCtx,
slog.LevelInfo,
"order processed",
slog.String("order_id", orderID),
)
LogEvent uses a background context and therefore cannot inherit request-scoped correlation.
Keep secrets, authorization headers, and unfiltered request bodies out of attributes.
Record AI calls
Optional OpenAI and Anthropic instrumentation packages record model, tokens, latency, and calculated
cost. OpenAI supports unary and Chat Completion streaming calls; Anthropic supports non-streaming
calls. OpenAI streams retain the provider’s Next/Current/Err/Close flow and request the final
usage chunk for exact accounting. Content capture is off by default; enabling it can send prompt and
completion text as span events.
Verify and recover
Send one request with ContextWithDistinctID, then open Customers and confirm the trace, log, and
test error appear under the same customer. If they do not, enable SDK debug logging, check the key,
endpoint, and project, and confirm Stop completes before the shutdown deadline.