telemetry

package
v1.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package telemetry holds the OpenTelemetry plumbing Nexus's stages share: the tracer, the span attribute keys, how an error is named, and the metric families recorded on a go-utils metrics sink.

Spans go to the global tracer provider, which forge.New installs. Without one they cost a no-op tracer call. Metrics are recorded only on a sink the caller hands over (nexus.WithMetrics), never on otel.Meter: a Forge app installs no global MeterProvider, so nothing recorded there is exported.

Index

Constants

View Source
const (
	MetricOperationDuration = "gen_ai.client.operation.duration"
	MetricTokenUsage        = "gen_ai.client.token.usage" // #nosec G101 -- a metric name, not a credential
	MetricFirstChunk        = "nexus_stream_time_to_first_chunk_seconds"
	MetricRequests          = "nexus_requests_total"
	MetricGuardrailBlocks   = "nexus_guardrail_blocks_total"
	MetricCacheLookups      = "nexus_cache_lookups_total"
	MetricUsageInsertErrors = "nexus_usage_insert_errors_total"
	MetricLimiterErrors     = "nexus_limiter_errors_total"
	MetricUsageUnpriced     = "nexus_usage_unpriced_total"
)

Metric names. The gen_ai ones are the OpenTelemetry GenAI client metrics. Forge exports names outside its semconv namespaces with its own prefix and no unit suffix, so these scrape as forge_gen_ai_client_operation_duration and forge_gen_ai_client_token_usage. The nexus ones carry their unit in the name and scrape as forge_<name>.

View Source
const (
	LabelOperation = "gen_ai.operation.name"
	LabelProvider  = "gen_ai.provider.name"
	LabelModel     = "gen_ai.request.model"
	LabelErrorType = "error.type"
	LabelTokenType = "gen_ai.token.type" // #nosec G101 -- a label key, not a credential
	LabelType      = "type"
	LabelOutcome   = "outcome"
	LabelCode      = "code"
	LabelPhase     = "phase"
	LabelGuard     = "guard"
	LabelKind      = "kind"
	LabelResult    = "result"
	// LabelProviderName is the provider's registered name on nexus metrics;
	// the gen_ai ones use LabelProvider.
	LabelProviderName = "provider"
)

Metric label keys. Forge turns the dots into underscores on the scrape.

View Source
const (
	GenAIOperationName         = attribute.Key("gen_ai.operation.name")
	GenAIProviderName          = attribute.Key("gen_ai.provider.name")
	GenAIRequestModel          = attribute.Key("gen_ai.request.model")
	GenAIRequestMaxTokens      = attribute.Key("gen_ai.request.max_tokens")
	GenAIRequestTemperature    = attribute.Key("gen_ai.request.temperature")
	GenAIRequestTopP           = attribute.Key("gen_ai.request.top_p")
	GenAIResponseModel         = attribute.Key("gen_ai.response.model")
	GenAIResponseID            = attribute.Key("gen_ai.response.id")
	GenAIResponseFinishReasons = attribute.Key("gen_ai.response.finish_reasons")
	GenAIUsageInputTokens      = attribute.Key("gen_ai.usage.input_tokens")
	GenAIUsageOutputTokens     = attribute.Key("gen_ai.usage.output_tokens")
	ErrorTypeKey               = attribute.Key("error.type")

	ProviderName    = attribute.Key("nexus.provider.name")
	RequestType     = attribute.Key("nexus.request.type")
	RequestID       = attribute.Key("nexus.request.id")
	TenantID        = attribute.Key("nexus.tenant.id")
	Outcome         = attribute.Key("nexus.outcome")
	RefusalCode     = attribute.Key("nexus.refusal.code")
	CacheHit        = attribute.Key("nexus.cache.hit")
	CacheKind       = attribute.Key("nexus.cache.kind")
	GuardrailPhase  = attribute.Key("nexus.guardrail.phase")
	GuardrailName   = attribute.Key("nexus.guardrail.name")
	GuardrailBlock  = attribute.Key("nexus.guardrail.blocked")
	GuardrailEdited = attribute.Key("nexus.guardrail.modified")
	UsageOutcome    = attribute.Key("nexus.usage.outcome")
	UsagePricing    = attribute.Key("nexus.usage.pricing_status")
	BatchJobID      = attribute.Key("nexus.batch.job.id")
	BatchItems      = attribute.Key("nexus.batch.items")
	BatchFailed     = attribute.Key("nexus.batch.failed")
	BatchStatus     = attribute.Key("nexus.batch.status")
)

Span attribute keys. The gen_ai ones follow the OpenTelemetry GenAI semantic conventions; the nexus ones are this module's own.

View Source
const (
	OperationChat       = "chat"
	OperationEmbeddings = "embeddings"
)

GenAI operation names.

View Source
const InstrumentationName = "github.com/xraph/nexus"

InstrumentationName is the instrumentation scope on every span Nexus starts.

View Source
const OtherModel = "other"

OtherModel stands in for a model name its provider does not list.

Variables

View Source
var (
	// OperationDurationBuckets are the bounds the GenAI conventions advise
	// for gen_ai.client.operation.duration, in seconds.
	OperationDurationBuckets = []float64{0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 10.24, 20.48, 40.96, 81.92}
	// TokenUsageBuckets are the bounds the GenAI conventions advise for
	// gen_ai.client.token.usage, in tokens.
	TokenUsageBuckets = []float64{1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864}
	// FirstChunkBuckets span a fast model's first token to a reasoning
	// model's long think, in seconds.
	FirstChunkBuckets = []float64{0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60}
)

Histogram bounds, in the metric's unit.

Functions

func Detach

func Detach(ctx context.Context) context.Context

Detach returns a fresh context that carries nothing but ctx's span context. Work that has to outlive ctx (storing a usage record, charging tokens, writing a stream to the cache) starts from it: it is not canceled with the request and inherits none of its values, yet its spans still land in the request's trace.

func ErrorType

func ErrorType(err error) string

ErrorType names err for error.type and the exception event: the context error it is, or the Go type of the innermost error in its chain. It never returns the error's text, which can quote a prompt, a key or a provider's reply. A nil err is "".

func Fail

func Fail(span trace.Span, err error) string

Fail marks span as failed: error.type, an exception event that carries only exception.type, and an error status whose description is that type. It returns the type. The error's text never reaches the span.

func GenAIProvider

func GenAIProvider(name string) string

GenAIProvider returns gen_ai.provider.name for a Nexus provider name.

func Tracer

func Tracer() trace.Tracer

Tracer returns the tracer Nexus starts its spans with. It reads the global tracer provider on every call, so whichever provider is installed when the span starts is the one that records it.

Types

type Counter

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

Counter is a counter declared with label keys. A nil *Counter records nothing.

func NewCounter

func NewCounter(m gometrics.Metrics, name, help string, keys ...string) *Counter

NewCounter declares a counter on m. A nil m returns nil.

func (*Counter) Inc

func (c *Counter) Inc(values ...string)

Inc adds one to the series for values, given in the declared key order.

type Histogram

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

Histogram is a histogram declared with label keys. A nil *Histogram records nothing.

func NewHistogram

func NewHistogram(m gometrics.Metrics, name, help, unit string, buckets []float64, keys ...string) *Histogram

NewHistogram declares a histogram on m. A nil m returns nil.

func (*Histogram) Observe

func (h *Histogram) Observe(v float64, values ...string)

Observe records v on the series for values, given in the declared key order.

Directories

Path Synopsis
Package telemetrytest records the spans and metrics Nexus emits, so a test can assert on them without a Forge app.
Package telemetrytest records the spans and metrics Nexus emits, so a test can assert on them without a Forge app.

Jump to

Keyboard shortcuts

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