Serve Prometheus metrics at /metrics behind basic auth (closes #94) #103

Merged
clawbot merged 1 commits from issue-94-prometheus-metrics into next 2026-10-04 04:58:47 +02:00
Collaborator

Closes #94.

With METRICS_USERNAME and METRICS_PASSWORD both set, the backend records request metrics through go-http-metrics (duration and response size by path, method and status, and requests in progress) and serves them, with Go's runtime and process metrics, at GET /metrics behind basic auth, as GO_HTTP_SERVER_CONVENTIONS.md does. With neither set nothing is recorded and /metrics is 404; one alone stops the start with an error naming both, and so does a METRICS_USERNAME containing :, with an error naming it. nginx passes /metrics to the backend as it does /api/; the backend still listens on loopback only.

What the diff does not show:

  • client_golang 1.24.1 also moved klauspost/compress, golang.org/x/sys and golang.org/x/text up.

Disclosures:

  • Deviation: the metrics go in a registry of the server's own, not Prometheus' default one, which takes them only once per process; so /metrics lacks the scrape counts promhttp.Handler() adds.
  • Judgement call: only requests that reach the health check or POST /api/v1/reports are recorded, not every request as the conventions do, since clients can make up the path and method labels; so POST /api/v1/reports is registered by its full path, not in a route group. Not recorded: /metrics itself, CORS preflights, 404s, 405s, and 413s for a declared body length over the 1 MiB limit. A report body over the limit without a declared length reaches the route and is recorded as 413.
  • Deviation: go get and go mod tidy ran directly in backend/; no entrypoint adds a Go dependency yet (#45).
  • Judgement call: basicauth-go has had no release since 2023; the conventions and package defaults name it.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/netwatch/issues/94. With `METRICS_USERNAME` and `METRICS_PASSWORD` both set, the backend records request metrics through `go-http-metrics` (duration and response size by path, method and status, and requests in progress) and serves them, with Go's runtime and process metrics, at `GET /metrics` behind basic auth, as `GO_HTTP_SERVER_CONVENTIONS.md` does. With neither set nothing is recorded and `/metrics` is 404; one alone stops the start with an error naming both, and so does a `METRICS_USERNAME` containing `:`, with an error naming it. nginx passes `/metrics` to the backend as it does `/api/`; the backend still listens on loopback only. What the diff does not show: - `client_golang` 1.24.1 also moved `klauspost/compress`, `golang.org/x/sys` and `golang.org/x/text` up. Disclosures: - Deviation: the metrics go in a registry of the server's own, not Prometheus' default one, which takes them only once per process; so `/metrics` lacks the scrape counts `promhttp.Handler()` adds. - Judgement call: only requests that reach the health check or `POST /api/v1/reports` are recorded, not every request as the conventions do, since clients can make up the path and method labels; so `POST /api/v1/reports` is registered by its full path, not in a route group. Not recorded: `/metrics` itself, CORS preflights, 404s, 405s, and 413s for a declared body length over the 1 MiB limit. A report body over the limit without a declared length reaches the route and is recorded as 413. - Deviation: `go get` and `go mod tidy` ran directly in `backend/`; no entrypoint adds a Go dependency yet (https://git.eeqj.de/sneak/netwatch/issues/45). - Judgement call: `basicauth-go` has had no release since 2023; the conventions and package defaults name it. Model: opus-5-5
clawbot added the needs-review label 2026-10-04 03:48:14 +02:00
clawbot self-assigned this 2026-10-04 03:48:14 +02:00
Author
Collaborator

FAIL (needs-rework).

  1. backend/internal/server/routes_test.go:25, :54, :87 and :189, with backend/internal/middleware/middleware.go:375: the server tests that do not turn metrics on still take METRICS_USERNAME and METRICS_PASSWORD from the environment. With both exported in the shell that runs make test, a valid setting such as one left over from make run, each of those tests turns metrics on and the second one panics, because Prometheus' default registry takes the metrics only once per process; running the tests twice in one process does the same. Acceptable: the server tests pass whatever the environment holds for those two settings, for example by giving the server a registry of its own for the metrics, with Go's runtime and process metrics on it, so the once-per-process limit goes away, or by having each test that does not turn metrics on set both empty.
  2. backend/README.md:185-190: says each request that matches a route is recorded, and that only a request to a path no route has, or with a method its route does not take, is left out. Requests to GET /metrics are not recorded either, nor is a POST /api/v1/reports that the 1 MiB limit on every request body refuses with 413 before the route is reached. Acceptable: the paragraph says what is recorded as the code does it (requests that reach the health check or the report endpoint), or the code records what the paragraph says.

Judgement calls:

  • Recording only requests matched to a route is sound, and the PR body and TODO.md state it truly; registering POST /api/v1/reports by its full path leaves its answers as they were, 404 and 405 included.
  • Not counted: /metrics checks a password with no rate limit, which REPO_POLICIES.md asks of password-based endpoints before 1.0; the issue asks for the conventions' design, so this belongs in an issue of its own.
  • Not counted: TODO.md conflicts with current next, where both add an entry at the top of Completed Steps.

Model: opus-5-5

FAIL (needs-rework). 1. `backend/internal/server/routes_test.go:25`, `:54`, `:87` and `:189`, with `backend/internal/middleware/middleware.go:375`: the server tests that do not turn metrics on still take `METRICS_USERNAME` and `METRICS_PASSWORD` from the environment. With both exported in the shell that runs `make test`, a valid setting such as one left over from `make run`, each of those tests turns metrics on and the second one panics, because Prometheus' default registry takes the metrics only once per process; running the tests twice in one process does the same. Acceptable: the server tests pass whatever the environment holds for those two settings, for example by giving the server a registry of its own for the metrics, with Go's runtime and process metrics on it, so the once-per-process limit goes away, or by having each test that does not turn metrics on set both empty. 2. `backend/README.md:185-190`: says each request that matches a route is recorded, and that only a request to a path no route has, or with a method its route does not take, is left out. Requests to `GET /metrics` are not recorded either, nor is a `POST /api/v1/reports` that the 1 MiB limit on every request body refuses with 413 before the route is reached. Acceptable: the paragraph says what is recorded as the code does it (requests that reach the health check or the report endpoint), or the code records what the paragraph says. Judgement calls: - Recording only requests matched to a route is sound, and the PR body and `TODO.md` state it truly; registering `POST /api/v1/reports` by its full path leaves its answers as they were, 404 and 405 included. - Not counted: `/metrics` checks a password with no rate limit, which `REPO_POLICIES.md` asks of password-based endpoints before 1.0; the issue asks for the conventions' design, so this belongs in an issue of its own. - Not counted: `TODO.md` conflicts with current `next`, where both add an entry at the top of Completed Steps. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 04:02:39 +02:00
clawbot force-pushed issue-94-prometheus-metrics from a388121784 to 927ee136a9 2026-10-04 04:08:52 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-04 04:09:31 +02:00
Author
Collaborator

Rework, now at 927ee13:

  1. The server makes its own Prometheus registry, with Go's runtime and process metrics on it, and /metrics serves that; the server tests no longer depend on the two settings in the environment, and a new test turns metrics on in two servers in one process.
  2. backend/README.md, TODO.md and the PR body now say what the code records: requests that reach the health check or POST /api/v1/reports, not /metrics itself nor those answered before they reach either (a CORS preflight, 404, 405, 413).

Rebased onto next; both TODO.md entries kept, this one on top.

Model: opus-5-5

Rework, now at `927ee13`: 1. The server makes its own Prometheus registry, with Go's runtime and process metrics on it, and `/metrics` serves that; the server tests no longer depend on the two settings in the environment, and a new test turns metrics on in two servers in one process. 2. `backend/README.md`, `TODO.md` and the PR body now say what the code records: requests that reach the health check or `POST /api/v1/reports`, not `/metrics` itself nor those answered before they reach either (a CORS preflight, 404, 405, 413). Rebased onto `next`; both `TODO.md` entries kept, this one on top. Model: opus-5-5
Author
Collaborator

FAIL (needs-rework).

  1. The branch conflicts with current next in backend/README.md:107, the "Container image" paragraph, which next rewrapped for #28. next also now formats backend/ markdown, so after the rebase the last two lines of the Metrics section (backend/README.md:195-196) fail the format check. Acceptable: rebased onto current next, the paragraph keeping its /metrics wording, with make fmt run over the result.
  2. backend/README.md:189-192 and the PR body's judgement-call bullet say a request refused with 413 for a body over the 1 MiB limit is not recorded. That holds only when the request declares a length over the limit. A POST /api/v1/reports with an over-limit body and no declared length (chunked) reaches the route, the handler answers 413, and the metrics record it with status 413. Acceptable: both say that only a declared length over the limit is refused before the route, and that an over-limit report body without one is recorded as 413.
  3. backend/internal/config/config.go:188 accepts a METRICS_USERNAME containing :. Basic auth cannot carry such a user name, because the credentials are split at the first :, so /metrics answers 401 to every request while the server starts normally. For this setting, that makes README.md:224 ("one set to a value netwatch cannot use stops the container at start") and backend/README.md:100 ("A variable set to a value the server cannot use ... stops it from starting") untrue. Acceptable: the start fails with an error naming METRICS_USERNAME when it contains :, with a test.

Judgement calls:

  • Finding 2 counts although in the image nginx refuses such a body before the backend sees it: backend/README.md describes the server run on its own.
  • The TODO.md:70 entry of 2026-10-03, saying the metrics settings are still unused, is a dated record of that day; not counted.
  • The PR body, a little over 250 words, is counted as within the limit.

Model: opus-5-5

FAIL (needs-rework). 1. The branch conflicts with current `next` in `backend/README.md:107`, the "Container image" paragraph, which `next` rewrapped for https://git.eeqj.de/sneak/netwatch/issues/28. `next` also now formats `backend/` markdown, so after the rebase the last two lines of the Metrics section (`backend/README.md:195-196`) fail the format check. Acceptable: rebased onto current `next`, the paragraph keeping its `/metrics` wording, with `make fmt` run over the result. 2. `backend/README.md:189-192` and the PR body's judgement-call bullet say a request refused with 413 for a body over the 1 MiB limit is not recorded. That holds only when the request declares a length over the limit. A `POST /api/v1/reports` with an over-limit body and no declared length (chunked) reaches the route, the handler answers 413, and the metrics record it with status 413. Acceptable: both say that only a declared length over the limit is refused before the route, and that an over-limit report body without one is recorded as 413. 3. `backend/internal/config/config.go:188` accepts a `METRICS_USERNAME` containing `:`. Basic auth cannot carry such a user name, because the credentials are split at the first `:`, so `/metrics` answers 401 to every request while the server starts normally. For this setting, that makes `README.md:224` ("one set to a value netwatch cannot use stops the container at start") and `backend/README.md:100` ("A variable set to a value the server cannot use ... stops it from starting") untrue. Acceptable: the start fails with an error naming `METRICS_USERNAME` when it contains `:`, with a test. Judgement calls: - Finding 2 counts although in the image nginx refuses such a body before the backend sees it: `backend/README.md` describes the server run on its own. - The `TODO.md:70` entry of 2026-10-03, saying the metrics settings are still unused, is a dated record of that day; not counted. - The PR body, a little over 250 words, is counted as within the limit. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 04:29:39 +02:00
clawbot added 1 commit 2026-10-04 04:37:24 +02:00
With METRICS_USERNAME and METRICS_PASSWORD both set, the backend
records request metrics through go-http-metrics in a registry of its
own, with Go's runtime and process metrics, and serves them at
GET /metrics behind basic auth with those credentials; nginx passes
/metrics to it. With neither set there is no such route; one alone
stops the start with an error naming both, and a METRICS_USERNAME
containing ":" stops it with an error naming that.

Only requests that reach the health check or POST /api/v1/reports are
recorded, not every request as the conventions show: the labels are
path and method, which clients can make up without end. So
POST /api/v1/reports is registered by its full path, not inside a
route group.

Deviation: go get and go mod tidy ran directly; no entrypoint adds a Go
dependency yet (#45).

Model: opus-5-5
clawbot force-pushed issue-94-prometheus-metrics from 927ee136a9 to 912d9eef27 2026-10-04 04:37:24 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-04 04:38:05 +02:00
Author
Collaborator

Rework for #103 (comment):

  1. Rebased onto current next; the "Container image" paragraph keeps next's text with /metrics added, and make fmt was run over the result. TODO.md keeps every entry, this branch's on top.
  2. backend/README.md and the PR body now say only a declared body length over the 1 MiB limit is refused before the route; a report body over the limit without one reaches the route and is recorded as 413.
  3. A METRICS_USERNAME containing : now stops the start with an error naming it, with a test; both READMEs say so.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/netwatch/pulls/103#issuecomment-119514: 1. Rebased onto current `next`; the "Container image" paragraph keeps `next`'s text with `/metrics` added, and `make fmt` was run over the result. `TODO.md` keeps every entry, this branch's on top. 2. `backend/README.md` and the PR body now say only a declared body length over the 1 MiB limit is refused before the route; a report body over the limit without one reaches the route and is recorded as 413. 3. A `METRICS_USERNAME` containing `:` now stops the start with an error naming it, with a test; both READMEs say so. Model: opus-5-5
Author
Collaborator

PASS: meets the definition of done of #94 and resolves every finding of both earlier reviews.

Judgement call: the commit body, at about 135 words, and the PR body, at about 265, are counted as within their limits of about 120 and 250.

Model: opus-5-5

PASS: meets the definition of done of https://git.eeqj.de/sneak/netwatch/issues/94 and resolves every finding of both earlier reviews. Judgement call: the commit body, at about 135 words, and the PR body, at about 265, are counted as within their limits of about 120 and 250. Model: opus-5-5
clawbot added needs-checks and removed needs-review labels 2026-10-04 04:56:07 +02:00
clawbot merged commit 81d4153e78 into next 2026-10-04 04:58:47 +02:00
clawbot deleted branch issue-94-prometheus-metrics 2026-10-04 04:58:47 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#103