Expand description
The counters over HTTP. Opt-in; binds nothing by default.
The counters, over HTTP: one opt-in read-only listener that
answers “is it slow or is it stuck” without perf and without a restart.
§What was missing
ServerMetrics has nineteen numbers
in it and exactly one reader: the heartbeat, which writes a line to the log
every sixty seconds when something changed. That is the right default and
it is not enough on its own. A heartbeat cannot be asked a question — an
operator watching a transfer that has not finished waits a minute to find
out whether bytes_out moved, and a graph over an hour of an incident has
to be reconstructed by hand out of journal lines. transfers_in_flight, the
one number that distinguishes slow from stuck, is the one most worth
sampling at a rate a human chooses.
§It does not open a port
ScrapeConfig::bind is an Option and it is None. Nothing listens
unless gunnar serve --metrics-bind <addr> says so, which is the same shape
--http-bind already uses (smart HTTP) and for the same reason: a second
listening port is a decision an operator makes, and a metrics surface that
bound itself by default would be a worse defect than the missing metrics
were.
There is no authentication on it, and that is stated rather than
discovered. The body is nineteen integers about this process — no
repository names, no principals, no references, no paths — so the surface is
deliberately not worth a credential, and a credential is exactly what an
operator cannot supply from a scraper’s config half the time. What that
costs is that anyone who can reach the port learns how busy the server is,
which is why Bound::serve writes a warn when the address is not
loopback: it must be a decision that was noticed.
§It costs no dependency
hyper 1, hyper-util and http-body-util, all of which tonic already resolves
for gRPC. cargo xtask guard measures the appliance graph before and after:
281 crates / 267 third-party, unchanged (MEASURED 2026-08-05, the reference desktop). It
is deliberately not behind the http feature — that feature is off in the
shipped gunnar-server atom, and an appliance is precisely where an operator
has the least ability to attach a debugger, so it is the build that must be
able to answer this question, not the one that may.
§It is not gunnar-http
gunnar-http is the git smart-HTTP transport: four fixed git URLs, an
authorisation decision per request, gzip, pkt-line. This shares its accept
loop’s shape and none of its body, and it lives here because putting it
there would mean an operator who wants counters compiles a git transport to
get them. The two loops are written once each; what one implementation forbids is a
second copy of a decision, and there is no decision in an accept loop.
Structs§
- Bound
- A bound scrape listener that has not started accepting yet.
- Scrape
Config - What
--metrics-bindwas given, if anything.
Constants§
- SCRAPE_
PATH - The one path that answers. Anything else is a
404.
Functions§
- bind
- Bind the scrape listener.