Documentation
¶
Overview ¶
Package neatlogs is the Go SDK for Neatlogs — OpenTelemetry-based tracing for Go LLM agents.
It exports spans over OTLP/HTTP to the Neatlogs ingestion endpoint ({endpoint}/v1/traces) and normalizes their attributes into the neatlogs.* namespace shared with the Python and TypeScript SDKs.
There are two ways spans reach Neatlogs:
Active wrapping. Call WrapGenAI on a google.golang.org/genai client to trace each GenerateContent / GenerateContentStream / EmbedContent / CountTokens call with full request/response detail (including message text) on the span.
Passive passthrough. Init registers a *global* OpenTelemetry TracerProvider, so any OTel-native framework — notably Google ADK — emits spans that flow through Neatlogs automatically. ADK uses the OTel GenAI semantic conventions, which the SDK maps onto neatlogs.* keys. Note that ADK records prompt/completion text on the OTel logs signal rather than on spans, so the ADK passthrough captures model, token usage, tool calls and finish reasons, but not message text.
Typical usage:
ctx := context.Background()
shutdown, err := neatlogs.Init(ctx, neatlogs.Config{
APIKey: os.Getenv("NEATLOGS_API_KEY"),
WorkflowName: "my-agent",
})
if err != nil { log.Fatal(err) }
defer shutdown(ctx)
Index ¶
- func Flush(ctx context.Context) error
- func Identify(ctx context.Context, opts IdentifyOptions) context.Context
- func Trace(ctx context.Context, name string) (context.Context, trace.Span, func())
- type Config
- type GenAIModels
- func (g *GenAIModels) CountTokens(ctx context.Context, model string, contents []*genai.Content, ...) (*genai.CountTokensResponse, error)
- func (g *GenAIModels) EmbedContent(ctx context.Context, model string, contents []*genai.Content, ...) (*genai.EmbedContentResponse, error)
- func (g *GenAIModels) GenerateContent(ctx context.Context, model string, contents []*genai.Content, ...) (*genai.GenerateContentResponse, error)
- func (g *GenAIModels) GenerateContentStream(ctx context.Context, model string, contents []*genai.Content, ...) iter.Seq2[*genai.GenerateContentResponse, error]
- func (g *GenAIModels) Raw() *genai.Models
- type IdentifyOptions
- type Option
- type ShutdownFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Flush ¶
Flush forces a synchronous export of all buffered spans. Safe to call even when the SDK is not initialized (it is a no-op then).
func Identify ¶
func Identify(ctx context.Context, opts IdentifyOptions) context.Context
Identify returns a copy of ctx carrying the given session + end-user identity. It is the single entry point for session/end-user on the Go SDK. Pass the returned context into Trace and/or your wrapped LLM calls; the (auto-)root span picks the identity up. Only set fields are bound, so calling Identify again overrides individual fields without clearing the others.
func Trace ¶
Trace opens a WORKFLOW root span named `name` and returns the child context, the span, and an end func the caller must invoke exactly once (usually via defer). It is the Go equivalent of Python's `with neatlogs.trace(...)` and TypeScript's `neatlogs.trace({...}, fn)`.
Session and end-user identity are NOT passed as arguments here — they ride on the context. Set them once at the request/turn boundary with Identify, then pass that context in:
ctx = neatlogs.Identify(ctx, neatlogs.IdentifyOptions{
SessionID: "chat_123", EndUserID: "user_456",
EndUserMetadata: map[string]any{"plan": "pro"},
})
ctx, span, end := neatlogs.Trace(ctx, "chat_turn") // reads identity from ctx
defer end()
Identity (session + end-user bound via Identify) is stamped on the root span by the identityProcessor, which reads it from the span's start context — so it applies to this WORKFLOW root, the WrapGenAI auto-root, and ADK passthrough spans uniformly. Trace itself only opens the span.
Types ¶
type Config ¶
type Config struct {
// APIKey authenticates with Neatlogs. Falls back to NEATLOGS_API_KEY.
// If empty after that fallback, export is disabled and spans are dropped.
APIKey string
// Endpoint is the Neatlogs ingestion base URL (without the /v1/traces
// path). Falls back to NEATLOGS_ENDPOINT, then the staging default.
Endpoint string
// WorkflowName labels this service/run. Defaults to the executable name.
WorkflowName string
// Tags are attached to every span as a resource attribute.
Tags []string
// Debug enables verbose diagnostics on stderr.
Debug bool
// DisableExport drops all spans instead of sending them. Useful in tests.
DisableExport bool
}
Config controls SDK initialization. All fields are optional except APIKey (which may also be supplied via the NEATLOGS_API_KEY environment variable).
type GenAIModels ¶
type GenAIModels struct {
// contains filtered or unexported fields
}
GenAIModels mirrors the call surface of (*genai.Client).Models, tracing each call. It is returned by WrapGenAI and is a drop-in replacement: the method signatures match google.golang.org/genai exactly, so existing call sites change by one line (the client they call) and nothing else.
func WrapGenAI ¶
func WrapGenAI(client *genai.Client) *GenAIModels
WrapGenAI wraps a genai.Client so its model calls emit Neatlogs spans.
client, _ := genai.NewClient(ctx, &genai.ClientConfig{APIKey: key})
gc := neatlogs.WrapGenAI(client)
resp, _ := gc.GenerateContent(ctx, "gemini-2.5-flash", contents, cfg)
Spans carry full request/response detail — input/output messages, tool definitions and calls, invocation parameters, token usage and finish reason — keyed in the neatlogs.* namespace. The Vertex AI backend is detected from the client config and tagged distinctly from the Gemini API.
func (*GenAIModels) CountTokens ¶
func (g *GenAIModels) CountTokens(ctx context.Context, model string, contents []*genai.Content, config *genai.CountTokensConfig) (*genai.CountTokensResponse, error)
CountTokens traces a token-counting call.
func (*GenAIModels) EmbedContent ¶
func (g *GenAIModels) EmbedContent(ctx context.Context, model string, contents []*genai.Content, config *genai.EmbedContentConfig) (*genai.EmbedContentResponse, error)
EmbedContent traces an embedding call.
func (*GenAIModels) GenerateContent ¶
func (g *GenAIModels) GenerateContent(ctx context.Context, model string, contents []*genai.Content, config *genai.GenerateContentConfig) (*genai.GenerateContentResponse, error)
GenerateContent traces a single content-generation call.
func (*GenAIModels) GenerateContentStream ¶
func (g *GenAIModels) GenerateContentStream(ctx context.Context, model string, contents []*genai.Content, config *genai.GenerateContentConfig) iter.Seq2[*genai.GenerateContentResponse, error]
GenerateContentStream traces a streaming generation, accumulating chunks to reconstruct the response when the stream is fully consumed.
func (*GenAIModels) Raw ¶
func (g *GenAIModels) Raw() *genai.Models
Raw returns the underlying genai.Models for any method this wrapper does not trace (e.g. cached-content operations), so callers are never blocked.
type IdentifyOptions ¶
IdentifyOptions carries the request-scoped identity for Identify. All fields are optional; only set ones are bound onto the context.
type Option ¶
type Option func(*initOptions)
Option customizes Init. Options are for advanced/testing use; the common path needs only Config.
func WithExporter ¶
func WithExporter(exp sdktrace.SpanExporter) Option
WithExporter overrides the OTLP/HTTP exporter with a custom SpanExporter. The SDK still wraps it so attributes are normalized to neatlogs.* before export. Useful for tests (in-memory exporter) or alternate sinks (stdout). When set, Config.Endpoint/APIKey are ignored for transport, but DisableExport still suppresses all export.
type ShutdownFunc ¶
ShutdownFunc flushes pending spans and releases SDK resources. Call it (often via defer) before the process exits so buffered spans are not lost.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
contrib
|
|
|
adk
module
|
|
|
examples
|
|
|
genai
command
Command genai demonstrates tracing a Google Gemini call with neatlogs-go via the active WrapGenAI wrapper (the path for apps that call the genai SDK directly, without a framework like ADK).
|
Command genai demonstrates tracing a Google Gemini call with neatlogs-go via the active WrapGenAI wrapper (the path for apps that call the genai SDK directly, without a framework like ADK). |
|
internal
|
|
|
attributes
Package attributes defines the canonical neatlogs.* span attribute keys the SDK's own wrappers emit, plus a JSON-driven Mapper (see mapper.go) that normalizes attributes from any source — OpenTelemetry GenAI semconv (as emitted by Google ADK and others), OpenInference, Traceloop — into the same neatlogs.* namespace.
|
Package attributes defines the canonical neatlogs.* span attribute keys the SDK's own wrappers emit, plus a JSON-driven Mapper (see mapper.go) that normalizes attributes from any source — OpenTelemetry GenAI semconv (as emitted by Google ADK and others), OpenInference, Traceloop — into the same neatlogs.* namespace. |