Documentation
¶
Overview ¶
Package metrics implements the Prometheus custom Collector that exposes the billing families from state.GlobalState.
Two rules a change here must not break:
- Never a CounterVec. It resets to zero on restart, and the agent restores cumulative state from its WAL — a reset makes rate() go negative and corrupts billing.
- Snapshot live rows and settled buckets under one lock, and aggregate per label tuple before emitting; Prometheus rejects duplicate label sets in one scrape.
docs/adr/0007-custom-collector-over-countervec.md
Index ¶
Constants ¶
const ( MetricBytesTotal = "lachesis_bytes_total" MetricPacketsTotal = "lachesis_packets_total" )
MetricBytesTotal is the TOTAL tier — everything the node observed, summed over tenants (including "unknown"): live rows + all settled. No tenant dimension; immortal. It is also the metric name consumed by a second package — the loadtest harness scrapes it as a liveness check (internal/loadtest) — so both the Desc here and that scraper reference this const instead of re-typing the string.
const ( MetricTenantBytesTotal = "lachesis_tenant_bytes_total" MetricTenantPacketsTotal = "lachesis_tenant_packets_total" )
MetricTenantBytesTotal / MetricTenantPacketsTotal are the TENANT tier — live rows + tenant-settled per (tenant, zone, external_network, direction). Immortal: the settled accumulator absorbs server and port deaths, so a tenant's series never decreases across VM churn.
const ( MetricServerBytesTotal = "lachesis_server_bytes_total" MetricServerPacketsTotal = "lachesis_server_packets_total" )
MetricServerBytesTotal is the SERVER tier — Σ live rows + server-settled per (server, tenant, zone, external_network, direction). Monotone for exactly the server's lifetime: the server-settled absorber holds folded port bytes (a portless-but-alive server flat-lines, like a stopped VM), and the series ends when the server leaves the Nova list. Plain period subtraction is safe within the lifetime; never increase()/rate() for money.
const ( MetricPortBytesTotal = "lachesis_port_bytes_total" MetricPortPacketsTotal = "lachesis_port_packets_total" )
MetricPortBytesTotal is the PORT tier — the mortal leaf, one series per Neutron port. A port's series stops when the port is deleted, and a detached-then-reattached port's series restarts from a fresh kernel counter — billing exactness lives one tier up; this family is the per-port drill-down view.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector emits the four-layer billing hierarchy — total → tenant → server → port byte/packet counters — from a state.GlobalState, plus a handful of internal-health gauges.
Full rationale: docs/architecture/billing.md
func New ¶
func New(st *state.GlobalState, sc ScraperStats, resolver TenantResolver) *Collector
New constructs a Collector. A nil resolver falls back to UnknownTenant{} so a missed wiring degrades to "unknown" labels rather than a nil-pointer panic inside the locked Collect loop on the first scrape.
func (*Collector) Collect ¶
func (c *Collector) Collect(ch chan<- prometheus.Metric)
Collect implements prometheus.Collector. It copies live flows and settled buckets in one RLock via SnapshotWithSettled — a torn read would double-count or drop a concurrent fold — then emits lock-free over the copies, so it cannot deadlock against the scraper writer.
Emitted value per tier: tenant = live + tenant-settled; total = the tenant tier summed over tenants; server = live + server-settled; port = live rows only, the mortal leaf.
docs/architecture/billing.md
func (*Collector) Describe ¶
func (c *Collector) Describe(ch chan<- *prometheus.Desc)
Describe implements prometheus.Collector.
type ScraperStats ¶
ScraperStats is the read-only subset of [scraper.Scraper] that the Collector exposes as internal-health metrics. Keeping it as an interface (rather than a concrete pointer) lets the metrics package stay independent of the scraper's internals.
type TenantResolver ¶
type TenantResolver interface {
Resolve(key bpf.FlowKey) metadata.Attribution
}
TenantResolver maps a bpf.FlowKey to its full label attribution — tenant_id, server_id, and the zone-gated external_network label — in one lookup (metadata.Attribution). Implementations must be safe for concurrent use and must not allocate: Resolve runs per live row inside Collect. The agent wires metadata.Resolver; UnknownTenant is the unwired fallback.
type UnknownTenant ¶
type UnknownTenant struct{}
UnknownTenant is the stub TenantResolver wired before the Neutron-backed `mac_tenant_map` reader is available. It returns the metadata.UnknownTenantID / metadata.NoExternalNetwork sentinels for every key — the same labels a metadata.Resolver emits on a lookup miss, so Prometheus `rate()` queries spanning the cold-start transition see one continuous series. No ServerID: unresolved flows never enter the per-server family.
func (UnknownTenant) Resolve ¶
func (UnknownTenant) Resolve(bpf.FlowKey) metadata.Attribution
Resolve implements TenantResolver.