telemetry

package
v1.12.9 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package telemetry builds forge's OpenTelemetry tracing: config resolution, the shared resource, the sampler, the tracer provider and the HTTP server middleware.

Index

Constants

View Source
const (
	TemporalityCumulative = "cumulative"
	TemporalityDelta      = "delta"
)

Temporality values MetricsSettings carries.

View Source
const LifecycleKey = attribute.Key("forge.lifecycle")

LifecycleKey marks the root span of an app's boot or shutdown. The forge sampler always samples such a root unless sampling is turned off, because a boot happens once per process and the slow one is the one you need.

Variables

View Source
var ErrInvalidEndpoint = errors.New("telemetry: invalid OTLP endpoint")

ErrInvalidEndpoint is wrapped by NewProvider when the OTLP endpoint is not an http or https URL with a host.

View Source
var ErrTracingDisabled = errors.New("telemetry: tracing is disabled")

ErrTracingDisabled is returned by RegisterSpanProcessor when tracing is off.

Functions

func BuildResource

func BuildResource(ctx context.Context, name, version, environment string, extra map[string]string) (*resource.Resource, error)

BuildResource builds the one Resource every signal shares. Order matters: later sources override earlier ones, so the app's name is the fallback, OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES beat it, and attributes from forge config beat everything.

A detector failing returns a partial resource with resource.ErrPartialResource. That is not fatal; the caller logs it and carries on with what was detected.

func BuildSampler

func BuildSampler(s Settings) sdktrace.Sampler

BuildSampler maps a resolved sampler name to an SDK sampler.

func Excluded

func Excluded(path string, prefixes []string) bool

Excluded reports whether path starts with any of prefixes. The tracing and HTTP metrics middleware use it to skip paths such as "/_/".

func HTTPClient

func HTTPClient() *http.Client

HTTPClient returns a client whose requests are traced. Every client shares http.DefaultTransport's connection pool.

func InstrumentTransport

func InstrumentTransport(rt http.RoundTripper) http.RoundTripper

InstrumentTransport wraps rt so outbound requests get a client span and carry the trace headers. It captures the global tracer provider and propagator current at the call, so in a process with several apps the transport stays with whichever provider was current then. Build it once and keep the result.

func NewForgeSampler

func NewForgeSampler(inner sdktrace.Sampler, off bool, wants *atomic.Pointer[[]func() bool]) sdktrace.Sampler

NewForgeSampler wraps inner. wants holds the WantsUnsampled functions of the registered processors; the provider owns it and replaces it on register.

func NormalizeMethod

func NormalizeMethod(m string) (method, original string)

NormalizeMethod returns the semconv method value and, for a method outside the standard nine, the original. Arbitrary methods would otherwise create one span name and one metric series per value a client invents.

func PropagationMiddleware

func PropagationMiddleware() func(http.Handler) http.Handler

PropagationMiddleware only extracts the incoming trace context, so a traceparent still reaches outbound calls made with HTTPClient when tracing is turned off. It starts no span and writes no response header.

func RouteMatchMiddleware

func RouteMatchMiddleware(excludePaths []string) func(http.Handler) http.Handler

RouteMatchMiddleware only installs a fresh shared.RouteMatch holder, so the router can report the matched route to the stream observer. forge.New uses it when metrics are on but neither the tracing nor the HTTP metrics middleware is installed, since those install the holder otherwise. A path under excludePaths gets no holder, the same as the tracing and HTTP metrics middleware skip it, so a stream served there is not recorded.

func SamplerOff

func SamplerOff(s Settings) bool

SamplerOff reports whether the settings turn sampling off entirely.

func ServerMiddleware

func ServerMiddleware(tp trace.TracerProvider, s Settings) func(http.Handler) http.Handler

ServerMiddleware starts a server span for every request whose path is not excluded. The span is renamed to "METHOD /route/pattern" once the router has matched, which it reports through shared.RouteMatch.

Types

type Inputs

type Inputs struct {
	Code        shared.TracingConfig // from WithAppTracingConfig
	File        shared.TracingConfig // from the forge config "tracing" key
	Environment string
	Getenv      func(string) string
}

Inputs is everything Resolve reads.

type MetricsInputs

type MetricsInputs struct {
	Code   shared.MetricsExportConfig // from WithAppMetricsExportConfig
	File   shared.MetricsExportConfig // from the forge config "metrics_export" key
	Getenv func(string) string
}

MetricsInputs is everything ResolveMetrics reads.

type MetricsPusher

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

MetricsPusher pushes metrics over OTLP/HTTP on an interval between Start and Shutdown. It can be started again after a Shutdown, and the same producer serves every run.

func NewMetricsPusher

func NewMetricsPusher(s MetricsSettings, res *resource.Resource, producer sdkmetric.Producer,
	log logger.Logger) (*MetricsPusher, error)

NewMetricsPusher checks the endpoint and keeps what Start needs. Nothing is exported until Start.

func (*MetricsPusher) Settings

func (p *MetricsPusher) Settings() MetricsSettings

Settings returns the resolved settings the pusher was built with.

func (*MetricsPusher) Shutdown

func (p *MetricsPusher) Shutdown(ctx context.Context) error

Shutdown collects and exports one last time and stops pushing, waiting at most five seconds or until ctx is done. It does nothing when the pusher isn't running, and Start may be called again afterwards.

func (*MetricsPusher) Start

func (p *MetricsPusher) Start(ctx context.Context) error

Start builds the OTLP exporter and a periodic reader over the producer, and pushes every interval until Shutdown. A pusher that is already running is left as it is. The MeterProvider that holds them is never installed as the OTel global, so only what the producer returns is pushed and a push always carries the series a scrape shows.

otlpmetrichttp reads its own OTEL_EXPORTER_OTLP_METRICS_* settings for what is not passed here, such as the timeout, compression and TLS certificates.

type MetricsSettings

type MetricsSettings struct {
	Enabled     bool   // push runs
	Endpoint    string // full OTLP/HTTP metrics URL
	Headers     map[string]string
	Interval    time.Duration
	Temporality string // TemporalityCumulative or TemporalityDelta
	Warnings    []string
}

MetricsSettings is the resolved metrics push configuration.

func ResolveMetrics

func ResolveMetrics(in MetricsInputs) MetricsSettings

ResolveMetrics applies the precedence code, forge config, OTEL_* env, default. Push runs only when an endpoint resolves and nothing turned it off.

type Provider

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

Provider owns the app's tracer provider.

func NewProvider

func NewProvider(ctx context.Context, s Settings, res *resource.Resource, log logger.Logger) (*Provider, error)

NewProvider builds the tracer provider and installs it, with the propagators, as the OTel globals. With no endpoint the provider records spans but exports nothing; processors added later still see them.

func (*Provider) RegisterSpanProcessor

func (p *Provider) RegisterSpanProcessor(sp sdktrace.SpanProcessor) error

RegisterSpanProcessor adds a span processor after construction. A processor with a WantsUnsampled method also receives spans the sampler would drop, for as long as the method returns true; those spans are never exported. It returns ErrTracingDisabled when tracing is off.

func (*Provider) Resource

func (p *Provider) Resource() *resource.Resource

Resource returns the shared resource.

func (*Provider) Settings

func (p *Provider) Settings() Settings

Settings returns the resolved settings the provider was built with.

func (*Provider) Shutdown

func (p *Provider) Shutdown(ctx context.Context) error

Shutdown flushes queued spans, waiting at most five seconds or until ctx is done.

func (*Provider) TracerProvider

func (p *Provider) TracerProvider() trace.TracerProvider

TracerProvider returns the provider spans should be started from.

type Settings

type Settings struct {
	Enabled        bool
	Endpoint       string // full OTLP/HTTP traces URL; empty means no export
	Headers        map[string]string
	SamplerName    string
	SampleRatio    float64
	Propagators    []string
	ExcludePaths   []string
	ResponseHeader string
	// SpanLabels labels each sampled request's goroutine with span_id and
	// span_name for the CPU profiler. Resolve never sets it; forge.New copies
	// it from the profiling settings.
	SpanLabels bool
	Resource   map[string]string
	Warnings   []string
}

Settings is the resolved tracing configuration.

func Resolve

func Resolve(in Inputs) Settings

Resolve applies the precedence code, forge config, OTEL_* env, default.

type StatusRecorder

type StatusRecorder struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

StatusRecorder captures the response status and body size without hiding the optional interfaces SSE and WebSocket handlers need. The tracing middleware and the HTTP server metrics middleware both wrap the writer in one.

func NewStatusRecorder

func NewStatusRecorder(w http.ResponseWriter) *StatusRecorder

NewStatusRecorder wraps w.

func (*StatusRecorder) BytesWritten

func (r *StatusRecorder) BytesWritten() int64

BytesWritten returns the response body bytes written so far.

func (*StatusRecorder) Flush

func (r *StatusRecorder) Flush()

Flush flushes through http.ResponseController, so a writer below that only exposes Unwrap still gets flushed. A successful flush sends the headers, so it commits 200 when no status was written yet.

func (*StatusRecorder) Hijack

func (r *StatusRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error)

Hijack hijacks through http.ResponseController. It records 101 only when the hijack succeeded. When no writer below supports it, the error wraps http.ErrNotSupported.

func (*StatusRecorder) Status

func (r *StatusRecorder) Status() int

Status returns the status sent, or 200 if the handler wrote nothing.

func (*StatusRecorder) Unwrap

func (r *StatusRecorder) Unwrap() http.ResponseWriter

Unwrap lets http.ResponseController reach the underlying writer.

func (*StatusRecorder) Write

func (r *StatusRecorder) Write(b []byte) (int, error)

func (*StatusRecorder) WriteHeader

func (r *StatusRecorder) WriteHeader(code int)

WriteHeader records the first final status and forwards every call. A 1xx informational response such as 103 Early Hints is passed on but not recorded, because the handler sends the real status after it. 101 is the exception: it ends the HTTP exchange, so it is final.

Jump to

Keyboard shortcuts

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