stats

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package stats collects what the server is doing, without getting in its way.

Every rule in here follows from one constraint: the query path must never wait on anything that exists only to be watched. A resolver that stalls because a monitor stopped reading has been made worse by being observed, and the observation is worth less than the answers. So counters are atomic rather than locked, the top-N lists are sorted when they are read rather than kept sorted while they are written, latency is sampled rather than recorded, and the event broadcast drops rather than blocks.

The package imports nothing from this repository. It describes query outcomes in plain types, so nothing about DNS leaks into it and nothing about it leaks into the resolver.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Collector

type Collector struct {

	// CacheEntries reports how many entries the cache currently holds, or is
	// nil when there is no cache. It is a gauge rather than a counter, so
	// unlike everything else here it cannot be accumulated from events and has
	// to be asked for.
	//
	// Set it once before the first query and never after. It is read without a
	// lock, on the assumption that it is wired up during startup like every
	// other part of the server.
	CacheEntries func() int
	// contains filtered or unexported fields
}

Collector accumulates events. It is safe for concurrent use and the zero value is not usable; call New.

func New

func New() *Collector

New returns a Collector whose uptime starts now.

func (*Collector) Recent

func (c *Collector) Recent(n int) []Event

Recent returns up to n of the most recent events, newest first.

func (*Collector) Record

func (c *Collector) Record(e Event)

Record accounts for one query outcome.

It is called once per query from the worker that answered it, so everything it does is either an atomic add, a sharded map update, or a send that cannot block. Nothing in here waits on anything.

func (*Collector) Snapshot

func (c *Collector) Snapshot() Snapshot

Snapshot renders the current state.

Everything expensive in this package happens here: three top-N lists get sorted and the reservoir gets copied and sorted. That is deliberate, and it is why Record can be as cheap as it is. Snapshot is called a few times a second by something drawing a screen; Record is called by every query.

The result is a value, not a view. Nothing in it aliases the collector, so a consumer can hold one for as long as it likes.

func (*Collector) Subscribe

func (c *Collector) Subscribe() (<-chan Event, func())

Subscribe returns a stream of events and a function that ends it.

The stream starts empty: it carries what happens from here, and a consumer that wants the recent past asks Recent for it. The cancel function may be called more than once and from any goroutine.

func (*Collector) Subscribers

func (c *Collector) Subscribers() int

Subscribers reports how many streams are attached. It exists for tests and for a shutdown line, and is a reading over an interval rather than at an instant.

type CountedItem

type CountedItem struct {
	Name  string
	Count uint64
}

CountedItem is one row of a top-N list.

The tier file uses this type in Snapshot without ever defining it. It is defined here as a name and a count, with the key rendered to text at snapshot time rather than at count time, which is what lets client addresses stay netip.Addr on the path where that matters.

type Event

type Event struct {
	At       time.Time
	Client   netip.Addr
	Name     string
	Type     uint16
	Rcode    uint8
	Blocked  bool
	CacheHit bool
	Stale    bool
	Duration time.Duration
}

Event is a single query outcome. Consumers subscribe to a stream of these.

type Snapshot

type Snapshot struct {
	Uptime         time.Duration
	QueriesTotal   uint64
	QueriesBlocked uint64
	CacheHits      uint64
	CacheMisses    uint64
	CacheEntries   int
	StaleServed    uint64
	UpstreamErrors uint64
	LatencyP50     time.Duration
	LatencyP99     time.Duration
	TopClients     []CountedItem
	TopDomains     []CountedItem
	TopBlocked     []CountedItem

	// EventsDropped and NamesDropped are not in the tier file's definition.
	// They are here because both of the mechanisms above discard data on
	// purpose, and a system that silently drops things is indistinguishable
	// from one that was never busy. A number nobody can read is a number nobody
	// checks.
	//
	// EventsDropped counts events a subscriber was too slow to receive.
	// NamesDropped counts sightings left out of the top-N lists because a
	// counter shard was full.
	EventsDropped uint64
	NamesDropped  uint64
}

Snapshot is an immutable point-in-time view. Consumers poll this.

Jump to

Keyboard shortcuts

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