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 (*Collector) Record ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.