Documentation
¶
Overview ¶
Package langfuse implements WeKnora's Langfuse/LiteFuse LLM tracing client on top of the OpenTelemetry Go SDK. It records chat/embedding/rerank/VLM/ASR generations plus the surrounding agent/HTTP/asynq spans as OTLP/HTTP spans to a Langfuse v3+ or LiteFuse backend (POST /api/public/otel/v1/traces).
The integration is fully opt-in: when disabled (the default), every public entry point is a cheap no-op, so callers can wire them unconditionally. A W3C traceparent propagated from upstream callers (e.g. sop3) is inherited so WeKnora's trace shares the upstream trace id — correlating runs across services in the LiteFuse UI.
Index ¶
- func AsynqMiddleware() asynq.MiddlewareFunc
- func AttachTraceparent(ctx context.Context, traceparent string) context.Context
- func GinMiddleware() gin.HandlerFunc
- func InjectTracing(ctx context.Context, carrier types.LangfuseTracingCarrier)
- func SummarizeMemoryRecallOutput(meta map[string]interface{}, items []*types.MemoryItem) map[string]interface{}
- func SummarizePassagePreviews(candidates []*types.SearchResult, passages []string, limit int) []map[string]interface{}
- func SummarizeRankScores(results []map[string]interface{}, limit int) []map[string]interface{}
- func SummarizeRetrievalContextOutput(background string, interests, documents []string, items []*types.MemoryItem) map[string]interface{}
- func SummarizeRetrieveOutput(results []*types.RetrieveResult) map[string]interface{}
- func SummarizeSearchResults(results []*types.SearchResult, limit int) map[string]interface{}
- func TraceparentFromContext(ctx context.Context) string
- func TruncateRunes(s string, maxRunes int) string
- type Config
- type Generation
- type GenerationOptions
- type Manager
- func (m *Manager) Enabled() bool
- func (m *Manager) ResumeTrace(ctx context.Context, traceID, parentSpanID string) (context.Context, *Trace)
- func (m *Manager) Shutdown(ctx context.Context) error
- func (m *Manager) StartChildSpan(ctx context.Context, opts SpanOptions) (context.Context, *Span)
- func (m *Manager) StartGeneration(ctx context.Context, opts GenerationOptions) (context.Context, *Generation)
- func (m *Manager) StartSpan(ctx context.Context, opts SpanOptions) (context.Context, *Span)
- func (m *Manager) StartTrace(ctx context.Context, opts TraceOptions) (context.Context, *Trace)
- func (m *Manager) Tracer() trace.Tracer
- type Span
- type SpanOptions
- type TokenUsage
- type Trace
- type TraceOptions
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AsynqMiddleware ¶
func AsynqMiddleware() asynq.MiddlewareFunc
AsynqMiddleware is the worker-side counterpart of GinMiddleware. It:
Extracts the W3C traceparent stamped onto the task payload by InjectTracing and resumes the originating trace (so the Langfuse UI stitches the HTTP request and the async processing into one tree). For scheduled jobs with no upstream trace it opens a standalone trace named after the task type.
Opens a SPAN around the handler execution so every child generation (embedding / VLM / chat / rerank / ASR) auto-attaches to it.
Enriches the span with asynq's own metadata: task id, queue, retry count, payload size.
When the manager is disabled it degrades to a pass-through; failure of the Langfuse path never blocks task execution. Register once via mux.Use.
func AttachTraceparent ¶
AttachTraceparent resumes the originating trace from a W3C traceparent previously captured by TraceparentFromContext / InjectTracing. When ctx already has a *Trace (same-request background work), it is left unchanged so we do not replace a live local parent with a remote one.
This is the in-process counterpart of AsynqMiddleware's extract path: a later HTTP request (e.g. POST .../suggestions) has no GinMiddleware trace, and without this StartGeneration would auto-create an orphan root named after the LLM call.
func GinMiddleware ¶
func GinMiddleware() gin.HandlerFunc
GinMiddleware returns a Gin handler that opens a Langfuse trace for each incoming request that hits a traced path. The trace is auto-finished when the handler chain returns; individual LLM calls inside the handler attach their generations to this trace via the request context.
Only paths matching shouldTrace are traced — static assets, health checks and polling endpoints are noisy and uninteresting.
func InjectTracing ¶
func InjectTracing(ctx context.Context, carrier types.LangfuseTracingCarrier)
InjectTracing stamps the current W3C traceparent (plus a best-effort user/session label) from ctx onto the given payload, provided the payload embeds types.TracingContext (and thus implements LangfuseTracingCarrier).
The traceparent is produced by propagator.Inject from the active OTel span context (the HTTP root span opened by GinMiddleware). The asynq worker re-extracts it so worker-side spans are children of the same trace — giving LiteFuse one stitched tree across the HTTP request and the async processing. This also makes a sop3 run's traceparent propagate through to any asynq jobs WeKnora enqueues while serving sop3's agent-chat call.
Safe to call unconditionally: when Langfuse is disabled or no span is present on ctx, it writes a zero-valued TracingContext — which round-trips through JSON as absent fields and costs nothing.
func SummarizeMemoryRecallOutput ¶
func SummarizeMemoryRecallOutput(meta map[string]interface{}, items []*types.MemoryItem) map[string]interface{}
SummarizeMemoryRecallOutput builds Langfuse output for a memory.recall span.
func SummarizePassagePreviews ¶
func SummarizePassagePreviews( candidates []*types.SearchResult, passages []string, limit int, ) []map[string]interface{}
SummarizePassagePreviews builds rerank passage previews aligned with candidates.
func SummarizeRankScores ¶
SummarizeRankScores builds rerank model score rows for Langfuse output.
func SummarizeRetrievalContextOutput ¶
func SummarizeRetrievalContextOutput( background string, interests, documents []string, items []*types.MemoryItem, ) map[string]interface{}
SummarizeRetrievalContextOutput builds Langfuse output for retrieval conditioning.
func SummarizeRetrieveOutput ¶
func SummarizeRetrieveOutput(results []*types.RetrieveResult) map[string]interface{}
SummarizeRetrieveOutput builds Langfuse output for the retrieve span.
func SummarizeSearchResults ¶
func SummarizeSearchResults(results []*types.SearchResult, limit int) map[string]interface{}
SummarizeSearchResults builds a compact ranked preview for rerank spans.
func TraceparentFromContext ¶
TraceparentFromContext returns the W3C traceparent for the active span, or empty when Langfuse is disabled or ctx carries no span. Used to stamp the originating chat trace onto derived work (follow-up suggestions) that may run after the HTTP handler returns, or on a later request.
func TruncateRunes ¶
TruncateRunes shortens s to at most maxRunes runes for trace payloads.
Types ¶
type Config ¶
type Config struct {
// Enabled is the master switch. If false the entire package is a no-op.
Enabled bool
// Host is the Langfuse base URL, e.g. https://cloud.langfuse.com or
// https://us.cloud.langfuse.com or a self-hosted address.
Host string
// PublicKey / SecretKey are the project credentials used for Basic Auth.
PublicKey string
SecretKey string
// FlushAt flushes the queued events once the buffer reaches this size.
FlushAt int
// FlushInterval is the maximum time between automatic flushes.
FlushInterval time.Duration
// QueueSize bounds the in-memory buffer to avoid unbounded growth if the
// Langfuse endpoint is unreachable.
QueueSize int
// RequestTimeout is the HTTP timeout for a single ingestion batch.
RequestTimeout time.Duration
// Release / Environment are attached to every trace for filtering in the
// Langfuse UI (e.g. release="v0.4.2", environment="production").
Release string
Environment string
// SampleRate (0..1) controls trace sampling. 0 means "use 1.0".
SampleRate float64
// Debug enables verbose logging of batch send errors.
Debug bool
// contains filtered or unexported fields
}
Config holds the runtime configuration for the Langfuse client.
In practice users enable Langfuse purely through environment variables — Host / PublicKey / SecretKey — which matches every other Langfuse SDK and keeps WeKnora's YAML config free of secrets.
func LoadConfigFromEnv ¶
func LoadConfigFromEnv() Config
LoadConfigFromEnv builds a Config by reading the LANGFUSE_* environment variables, mirroring the official Python / JS SDK conventions.
type Generation ¶
type Generation struct {
ID string
// contains filtered or unexported fields
}
Generation represents a single model invocation (LLM / embedding / VLM / ASR).
func (*Generation) Finish ¶
func (g *Generation) Finish(output interface{}, usage *TokenUsage, err error)
Finish updates a generation with its final output, token usage and any error. A non-nil err marks the observation as ERROR.
func (*Generation) MarkCompletionStart ¶
func (g *Generation) MarkCompletionStart(t time.Time)
MarkCompletionStart records the time at which the first token was received in a streaming generation. Langfuse surfaces this as time-to-first-token.
type GenerationOptions ¶
type GenerationOptions struct {
Name string
Model string
Input interface{}
Metadata map[string]interface{}
ModelParameters map[string]interface{}
}
GenerationOptions configures a new generation observation.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager is the public façade of the langfuse package. A singleton is installed via Init(); callers should treat a nil *Manager as "disabled" and still invoke methods — every public method tolerates a nil receiver.
Internally the manager owns an OpenTelemetry TracerProvider backed by an OTLP/HTTP exporter pointing at the Langfuse v3+ / LiteFuse OTel endpoint. The handles (*Trace / *Span / *Generation) wrap OTel spans; spans are buffered by the BatchSpanProcessor and exported complete on End, so there is no per-flush-batch duplication of root spans (the bug the legacy hand-rolled translator had on long traces spanning multiple flushes).
func GetManager ¶
func GetManager() *Manager
GetManager returns the installed singleton, or nil if Init has not been called. Callers must tolerate a nil return.
func Init ¶
Init builds a Manager from cfg and installs it as the package-wide singleton. When cfg.Enabled is false this returns a disabled manager that behaves as a no-op for every public method.
func (*Manager) ResumeTrace ¶
func (m *Manager) ResumeTrace(ctx context.Context, traceID, parentSpanID string) (context.Context, *Trace)
ResumeTrace reconstructs a *Trace handle from an externally-provided W3C trace id (and optional parent span id), without creating a new root span — the originating process (e.g. an HTTP request that already opened a trace) owns the root. Used to graft async work onto an existing trace: it sets a remote SpanContext on ctx so any child span/generation started under it inherits the upstream trace id. When traceID is empty the returned *Trace is nil, signalling the caller should fall back to StartTrace.
func (*Manager) Shutdown ¶
Shutdown flushes pending spans and releases the exporter. Safe to call multiple times.
func (*Manager) StartChildSpan ¶
StartChildSpan records a low-level operation only when its caller is already traced. Polling and housekeeping must not create a new trace for every RPC; their operation-level caller owns the trace boundary instead.
func (*Manager) StartGeneration ¶
func (m *Manager) StartGeneration(ctx context.Context, opts GenerationOptions) (context.Context, *Generation)
StartGeneration opens a generation observation under the trace carried by ctx (or a newly auto-created trace). If a parent span is present on ctx, the generation attaches under it via the OTel span context.
func (*Manager) StartSpan ¶
StartSpan opens a child span under the trace/span carried by ctx. When no trace is present, OTel creates a fresh root (mirroring StartGeneration's auto-trace behaviour). Returns a ctx whose active span is this span.
func (*Manager) StartTrace ¶
StartTrace opens a root span. When ctx carries a remote SpanContext (from a W3C traceparent extracted by GinMiddleware), the root span inherits the upstream trace id — this is what makes a sop3 run and its WeKnora call land under the same trace in LiteFuse. The returned *Trace is non-nil even when disabled (methods are no-ops), so callers don't need nil checks.
type Span ¶
type Span struct {
ID string
// contains filtered or unexported fields
}
Span represents a logical unit of work that isn't itself an LLM call — for example an asynq task execution, a pipeline stage, or a document-processing step. Generations and nested spans attach as children via the OTel span context (parenting is automatic through trace.SpanFromContext).
func (*Span) Finish ¶
Finish updates a span with its final output, extra metadata and any error. A non-nil err marks the span as ERROR. Finish-time metadata is merged on top of the metadata set at StartSpan (finish keys win) rather than discarded, so fields only known at completion (outcome, duration_ms, tool_calls, …) are reported. If this span implicitly opened a root trace, that root is ended last so it is exported.
type SpanOptions ¶
SpanOptions configures a new SPAN observation.
type TokenUsage ¶
type TokenUsage struct {
Input int `json:"input,omitempty"`
Output int `json:"output,omitempty"`
Total int `json:"total,omitempty"`
CacheRead int `json:"cache_read_input_tokens,omitempty"`
CacheWrite int `json:"cache_creation_input_tokens,omitempty"`
CacheMiss int `json:"cache_miss_input_tokens,omitempty"`
Unit string `json:"unit,omitempty"`
}
TokenUsage captures the input/output/total token counts reported by the underlying model, in Langfuse's canonical schema. Set as the value of the langfuse.observation.usage_details span attribute (JSON-serialized).
type Trace ¶
type Trace struct {
ID string
// contains filtered or unexported fields
}
Trace represents an active root observation. A Trace is conceptually one "request" (e.g. a chat turn). Generations and spans attached to it roll up as children in the Langfuse UI. It wraps an OpenTelemetry root span; its ID is the OTel trace id (W3C 32-hex), which — when the request carried a traceparent header — is the upstream caller's trace id (sop3 correlation).
func TraceFromContext ¶
TraceFromContext is the public accessor used by HTTP middlewares and handlers that want to set the trace input/output on the active trace.
func (*Trace) Finish ¶
Finish updates the trace with its final output and merges any finish-time metadata into the metadata set at StartTrace. Safe to call on a disabled trace (no-op). Finish keys are merged on top of the open-time correlation fields (request_id, http.method, etc.) rather than overwriting them, so both the open's correlation and the finish outcome survive.