promapi

package
v0.9.1225 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package promapi is the shared Prometheus HTTP-API client core (v0.9.1150) — envelope decoding + a bounded GET, with nothing in it that knows about clusters, metrics pages, or Coremetry's read model.

Why a package and not a helper in internal/vmetrics: the SAME wire contract now has two consumers with different jobs — internal/thanos (multi-cluster pod/host metrics for /clusters) and internal/vmetrics (the metric read backend, Faz 1). The decoding rules that matter are the non-obvious ones, and each was a bug somewhere first:

  • status != "success" carries errorType/error INSTEAD of data, so a 200 with a broken query is an ERROR, not an empty result. Treating it as empty is the "no data" lie.
  • sample values arrive as JSON STRINGS ("1.5", "NaN", "+Inf"), never numbers. A struct with float64 silently fails to unmarshal.
  • non-finite values are legal Prometheus output (staleness markers, 0/0 in a recording rule). They must be DROPPED, not coerced to 0 — v0.9.1149 taught us a %f-formatted +Inf travels all the way into a prompt.

DELIBERATELY NOT a refactor of internal/thanos. thanos' doQuery stays exactly where it is: it is load-bearing on a surface with no test harness for a live Querier, and the spec for this release scoped the blast radius to the new reader. This package is the copy-the-pattern half of "copy the pattern, share the core" — new callers use it, the old one is left alone until something else forces it to move.

Index

Constants

View Source
const MaxBodyBytes = 8 << 20

MaxBodyBytes — 8MB read ceiling. A bounded vector is a few hundred KB; anything past this means the shield upstream failed and we would rather fail than allocate.

View Source
const MaxSeriesParsed = 1000

MaxSeriesParsed is the defensive backstop behind whatever cardinality shield the query itself carries (topk / a bounded selector): even a misbehaving backend can't hand us more rows than this. Mirrors thanos.maxSeriesParsed.

Variables

This section is empty.

Functions

func BuildURL

func BuildURL(baseURL, path string, params url.Values) string

BuildURL joins base + path + encoded params. Pure — the trailing-slash case is table-tested; "https://vm/" + "/api/v1/labels" must not produce a double slash, because some reverse proxies 404 on it.

func DecodeStrings

func DecodeStrings(label string, body []byte) ([]string, error)

DecodeStrings parses a labels / label-values body — data is a plain string array. `"data": null` decodes to an empty slice, not an error: a metric with no labels is a legitimate answer.

func Do

func Do(ctx context.Context, req Request) ([]byte, error)

Do performs the GET and returns the raw body. HTTP >= 300 is an error carrying the first 200 bytes of the body — a 401 from VM says which auth it wanted, and hiding that costs an operator an hour.

func FirstN

func FirstN(s string, n int) string

FirstN truncates for error messages. Rune-safe: slicing bytes mid-rune puts U+FFFD in an operator-visible string (the v0.9.842 truncate trap).

func QueryStrings

func QueryStrings(ctx context.Context, req Request) ([]string, error)

QueryStrings = Do + DecodeStrings.

func Sample

func Sample(raw []json.RawMessage) (tsSec float64, val float64, ok bool)

Sample decodes one [timestamp, "value"] pair.

ok=false means the pair is UNUSABLE and the caller must skip the point: malformed JSON, wrong arity, or a non-finite value. Prometheus emits NaN / +Inf / -Inf as ordinary strings and they are not exceptional — a counter divided by a zero interval, a staleness marker. Coercing them to 0 draws a line to the floor that the operator reads as a real measurement, and a formatted ±Inf leaks into every downstream string (v0.9.1149). Dropping leaves a gap, which is what a gap is.

Types

type Request

type Request struct {
	Label    string
	BaseURL  string
	Path     string
	Params   url.Values
	AuthType string // "" / "none" / "bearer"
	Token    string
	SkipTLS  bool
}

Request is one Prometheus-API GET. Label names the backend in every error message ("victoriametrics") — an error that reads "connection refused" without saying WHOSE connection sends the operator hunting.

type Series

type Series struct {
	Metric map[string]string   `json:"metric"`
	Value  []json.RawMessage   `json:"value"`
	Values [][]json.RawMessage `json:"values"`
}

Series is one result row of /api/v1/query (Value filled, instant vector) or /api/v1/query_range (Values filled, range matrix). json.RawMessage because element 0 is a number and element 1 is a string — see Sample.

func DecodeSeries

func DecodeSeries(label string, body []byte) ([]Series, error)

DecodeSeries parses a query / query_range body into series. Pure — table-tested in promapi_test.go.

func QuerySeries

func QuerySeries(ctx context.Context, req Request) ([]Series, error)

QuerySeries = Do + DecodeSeries.

Jump to

Keyboard shortcuts

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