metrics

package module
v1.110.6 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 17 Imported by: 0

README

Archived. Hanzo Metrics is superseded by hanzoai/o11y, which serves metrics, logs and traces from one subsystem at /v1/o11y/*. Nothing new should depend on this repository; it is kept read-only for history. What follows describes the retired product.

NOTICE says where each of the eleven routes went, what was measured before the eight duplicate doors were deleted, and why the last commit written here is obsolete rather than pending. hanzoai/cloud was the only importer and no longer imports it.

metrics

Hanzo Metrics

High-performance time-series metrics database.

Overview

Hanzo Metrics is a fast, cost-effective time-series database optimized for monitoring AI infrastructure. Store billions of data points with excellent compression and query performance for your observability needs.

Features

  • High Performance: Fast ingestion and queries
  • Efficient Storage: 10x compression vs alternatives
  • PromQL Compatible: Use familiar Prometheus queries
  • Long-term Storage: Cost-effective retention
  • High Availability: Clustering and replication
  • Multi-tenancy: Isolated tenant data

Quick Start

docker run -p 8428:8428 hanzo/metrics

Documentation

See the documentation for detailed guides and API reference.

License

MIT License - see LICENSE for details.

Documentation

Overview

HIP-0106 native observability subsystem — New/Mount composition-root form.

import "github.com/hanzoai/metrics"
metrics.Mount(app, metrics.Deps{Logger: log, DataDir: dir, Brand: brand, Org: principal.Org})

One subsystem serves all three signals — metrics, logs, traces — under /v1/{metrics,logs,traces}/* on the shared zip.App. Storage is native and WAL-durable; ingest for metrics is luxfi/metric.MetricBatch (the ZAP MsgMetricBatch payload). Every request is scoped to a tenant the AUTHENTICATING boundary resolved — Deps.Org, never a header this package reads itself — so the same binary serves any tenant with hard data isolation. There is no prometheus, no Grafana, no scrape endpoint, no /api/ path.

This package imports ONLY zap-proto/zip + luxfi (no hanzoai/cloud): it depends on what it uses — a logger, a data dir, a brand label and the tenant decision — which it declares in its own Deps. The composition root (cmd/cloud) constructs those and calls Mount explicitly; there is no global registry and no init() side effect.

Package metrics is the native, ZAP-native, prometheus-free time-series store for the Hanzo cloud. It replaces the vendored Grafana/Prometheus observability backends with a small in-process store that ingests luxfi/metric.MetricBatch (the same wire shape the ZAP MsgMetricBatch transport carries) and serves range queries under /v1/metrics/*.

The storage API is deliberately tiny (Append + Query + SeriesCount) so a durable per-tenant backend (DataDir-backed, columnar) can replace the in-memory map without changing mount.go or ingest.go. There is ZERO prometheus here.

Index

Constants

View Source
const MsgMetricBatch uint16 = 2

MsgMetricBatch is the canonical ZAP MsgType for metric batches — it matches luxfi/metric.MsgMetricBatch and o11y/pkg/zapmetricreceiver so any luxfi/metric ZAP exporter ingests here unchanged.

View Source
const Version = "0.4.0"

Version is surfaced on the /health routes.

Variables

This section is empty.

Functions

func Mount

func Mount(app *zip.App, deps Deps) error

Mount registers the native observability routes on the shared cloud App.

Types

type Deps added in v1.110.2

type Deps struct {
	// Logger is the canonical Hanzo logger; Mount derives a scoped child.
	Logger luxlog.Logger
	// DataDir is the per-deployment data root; per-org WALs land under it.
	DataDir string

	// Brand is the deployment's own label. It is NOT a tenant on the HTTP
	// surface — see Org — and it stopped being one there. It remains the
	// default on the ZAP receiver, which binds only when O11Y_ZAP_PORT is set,
	// is not internet-reachable, and admits only peers already on the cluster
	// network; a batch from such a peer that names no org is this deployment's
	// own telemetry. An anonymous HTTP caller is not that, which is the whole
	// difference.
	Brand string

	// Org is THE tenant decision, and it is not ours to make.
	//
	// This subsystem used to read X-Org-Id itself and fall back to the brand.
	// That is a header a client sends, so the tenant boundary was whatever the
	// caller typed: an anonymous request could name any org and read — or write
	// — that org's metrics, logs and traces. Measured against production before
	// the fix: POST /v1/logs/write with an invented X-Org-Id answered
	// {"written":1}, and GET /v1/logs/query with the same header read it back.
	//
	// The rule the rest of the fleet applies is that an org is trustworthy only
	// alongside a VALIDATED principal, and it lives in exactly one place —
	// cloud's principal.OrgOf, whose own doc warns that a second hand-rolled
	// check is drift waiting to happen. This field is how that one rule reaches
	// here without this module importing cloud: the boundary that authenticates
	// hands down the predicate, and every route asks it.
	//
	// It returns ok=false for an unauthenticated or org-less caller, and the
	// route answers 403. There is no brand fallback: a default tenant for
	// callers who proved nothing is the hole itself.
	Org func(*zip.Ctx) (string, bool)
}

Deps is the NARROW dependency surface this subsystem declares — only what it uses. The composition root builds it from Config and passes it to Mount. No hanzoai/cloud import, no god-struct: a subsystem depends on what it needs, nothing more.

type LogRecord added in v0.2.0

type LogRecord struct {
	TsNs   int64             `json:"t"`
	Level  string            `json:"level,omitempty"`
	Body   string            `json:"body"`
	Labels map[string]string `json:"labels,omitempty"`
}

LogRecord is one structured log line — the native, prometheus-free, Loki-free log signal. Bodies are stored verbatim; labels are the indexed dimensions.

type LogStore added in v0.2.0

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

LogStore is the native log store: an append-only bounded ring with label + time-range + case-insensitive substring query. Durable via the shared WAL.

func NewLogStore added in v0.2.0

func NewLogStore() *LogStore

NewLogStore returns an empty store retaining up to 1Mi records in memory.

func (*LogStore) Append added in v0.2.0

func (s *LogStore) Append(lr LogRecord)

Append stores one log record (and durably logs it when durability is on).

func (*LogStore) Count added in v0.2.0

func (s *LogStore) Count() int

Count reports the number of records held.

func (*LogStore) EnableDurability added in v0.2.0

func (s *LogStore) EnableDurability(path string) error

EnableDurability opens and replays a WAL at path (e.g. <DataDir>/logs/logs.wal).

func (*LogStore) Query added in v0.2.0

func (s *LogStore) Query(matchers map[string]string, startNs, endNs int64, contains string, limit int) []LogRecord

Query returns up to limit records (newest first) matching labels, the [startNs,endNs] range, and an optional case-insensitive substring of Body.

type Registry added in v0.3.0

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

Registry lazily creates per-tenant store sets. Each tenant's WALs live under <DataDir>/orgs/<org>/o11y/ (the HIP-0302 per-org convention), so one tenant's metrics/logs/traces never mingle with another's — the same binary serves lux.cloud and zoo.cloud with hard data isolation. A single-tenant deployment simply uses one org (the deployment brand).

func NewRegistry added in v0.3.0

func NewRegistry(dataDir string) *Registry

NewRegistry returns a registry rooted at dataDir ("" = in-memory, no durability).

func (*Registry) For added in v0.3.0

func (r *Registry) For(org string) *tenantSet

For returns the store set for org, creating it (and enabling per-org WAL durability when dataDir is set) on first use. An empty org collapses to "default".

func (*Registry) Tenants added in v0.3.0

func (r *Registry) Tenants() []string

Tenants returns the org slugs that currently have stores (for /health/admin).

type Sample

type Sample struct {
	TsNs  int64   `json:"t"`
	Value float64 `json:"v"`
}

Sample is a single timestamped value. Ts is nanoseconds since the Unix epoch to match luxfi/metric.MetricBatch.TimestampNs.

type Series

type Series struct {
	Name    string            `json:"name"`
	Labels  map[string]string `json:"labels,omitempty"`
	Samples []Sample          `json:"samples"`
}

Series is a named, labeled append-only stream of samples.

type Span added in v0.2.0

type Span struct {
	TraceID string            `json:"traceId"`
	SpanID  string            `json:"spanId"`
	Parent  string            `json:"parentId,omitempty"`
	Name    string            `json:"name"`
	StartNs int64             `json:"startNs"`
	EndNs   int64             `json:"endNs"`
	Attrs   map[string]string `json:"attrs,omitempty"`
}

Span is one unit of a distributed trace — the native, prometheus-free, Tempo-free trace signal. Times are nanoseconds since the Unix epoch.

type Store

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

Store is the native in-memory time-series store. Each series is bounded to maxPerSeries samples (oldest evicted first). Safe for concurrent use.

func NewStore

func NewStore() *Store

NewStore returns an empty store with a default per-series retention of 64Ki samples (a real deployment sets this from config / per-tenant quota).

func (*Store) Append

func (s *Store) Append(name string, labels map[string]string, smp Sample)

Append adds one sample to the series identified by (name, labels), creating the series on first write and evicting the oldest sample past retention. When durability is enabled the sample is also written to the WAL.

func (*Store) EnableDurability added in v0.2.0

func (s *Store) EnableDurability(path string) error

EnableDurability opens a write-ahead log at path and replays it into the store so samples survive restart. Replayed samples are not re-logged. Pass a per-deployment path (e.g. <DataDir>/metrics/metrics.wal).

func (*Store) IngestBatch

func (s *Store) IngestBatch(b *metric.MetricBatch) int

IngestBatch writes every sample in a luxfi/metric.MetricBatch into the store. This is the exact wire type the ZAP MsgMetricBatch transport carries, so the same code path serves both the HTTP /v1/metrics/batch endpoint and a future ZAP receiver. Counter/gauge values land directly; histogram/summary families contribute derived <name>_sum and <name>_count series. Returns samples written.

func (*Store) Query

func (s *Store) Query(name string, matchers map[string]string, startNs, endNs int64) []Series

Query returns copies of every series whose Name equals name (or all, if name is "") and whose labels are a superset of matchers, with samples restricted to [startNs, endNs] (a zero bound is treated as unbounded).

func (*Store) SeriesCount

func (s *Store) SeriesCount() int

SeriesCount reports the number of distinct series held (surfaced on /health).

type TraceStore added in v0.2.0

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

TraceStore is the native span store: an append-only bounded ring with a trace-id index for waterfall lookup and time-range listing. Durable via WAL.

func NewTraceStore added in v0.2.0

func NewTraceStore() *TraceStore

NewTraceStore returns an empty store retaining up to 1Mi spans in memory.

func (*TraceStore) Append added in v0.2.0

func (s *TraceStore) Append(sp Span)

Append stores one span (and durably logs it when durability is on).

func (*TraceStore) ByTrace added in v0.2.0

func (s *TraceStore) ByTrace(traceID string) []Span

ByTrace returns every span belonging to a trace id (the waterfall).

func (*TraceStore) Count added in v0.2.0

func (s *TraceStore) Count() int

Count reports the number of spans held.

func (*TraceStore) EnableDurability added in v0.2.0

func (s *TraceStore) EnableDurability(path string) error

EnableDurability opens and replays a WAL at path (e.g. <DataDir>/traces/traces.wal).

func (*TraceStore) Recent added in v0.2.0

func (s *TraceStore) Recent(startNs, endNs int64, limit int) []Span

Recent returns up to limit spans (newest first) starting within [startNs,endNs].

type WAL added in v0.2.0

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

WAL is a simple append-only write-ahead log of length-prefixed records. It gives the in-memory stores durability: every write is appended here and the log is replayed on startup. This is intentionally a single flat segment — a production deployment adds rotation/compaction behind the same Append/Replay API without touching callers.

func OpenWAL added in v0.2.0

func OpenWAL(path string) (*WAL, error)

OpenWAL opens (creating parent dirs and the file as needed) an append log.

func (*WAL) Append added in v0.2.0

func (w *WAL) Append(rec []byte) error

Append writes one length-prefixed record and flushes it to disk.

func (*WAL) Close added in v0.2.0

func (w *WAL) Close() error

Close flushes and closes the log.

func (*WAL) Replay added in v0.2.0

func (w *WAL) Replay(fn func([]byte)) error

Replay invokes fn for every record from the start, then positions the file at the end so subsequent Appends extend the log. Call once on startup.

Jump to

Keyboard shortcuts

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