Backend observability: fx logs bypass slog, Identify() is dead, Sentry/Prometheus config is parsed but unwired #27
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The backend parses configuration for three observability features that do not exist, and part of its own logging escapes the structured logger. Verified on
mainatfbfe1df.1. fx's own logging bypasses slog entirely
backend/cmd/netwatch-server/main.go:29-41callsfx.New(...)with nofx.WithLogger(...). fx therefore falls back to its built-in console logger, writing unstructured plain text to stderr for every provide, invoke, and lifecycle hook, plus all shutdown output.CODE_STYLEGUIDE.md: "For services/servers, log JSON to stdout... Use structured logging whenever possible." Today a production deployment's log stream is a mix of clean JSON frominternal/loggerand unparseable plain text from fx.Side effect:
go.uber.org/zap v1.26.0(go.mod:26) is linked into the binary purely as fx's default logger backend. No application code imports it. Bridging fx to slog removes zap's runtime role.2.
logger.Identify()is dead codeinternal/logger/logger.go:79-85definesIdentify(), which logs appname, version, and buildarch. Grepping the backend finds only the definition — no call site.CODE_STYLEGUIDE_GO.md: "Embed the git commit hash into the binary and include it in startup logs and in health check output." The version does reach the logs by accident viainternal/server/http.go:29-33("http begin listen" carriesversionandbuildarch), butappnamenever does, and the intended identification line never fires.3. Three config values are parsed and never read
internal/config/config.goloadsSENTRY_DSN,METRICS_USERNAME, andMETRICS_PASSWORDinto theConfigstruct. Nothing reads any of them.GO_HTTP_SERVER_CONVENTIONS.mdlists these as mandatory libraries and specifies the wiring:github.com/getsentry/sentry-go— conditional init onSENTRY_DSN,sentryhttpmiddleware withRepanic: true,sentry.Flush(2*time.Second)on shutdown.github.com/prometheus/client_golang+github.com/slok/go-http-metrics+github.com/99designs/basicauth-go—Metrics()middleware and a basic-auth-protectedGET /metrics.None are in
go.mod.internal/middleware/middleware.gohas noMetrics()orMetricsAuth().internal/server/routes.goregisters no/metricsroute. TheServerstruct (server.go:37-47) omits thesentryEnabledfield the conventions doc specifies.backend/README.md:61already lists Prometheus metrics as an open TODO.4. Healthcheck JSON keys violate the snake_case rule
internal/healthcheck/healthcheck.go:39-40emitsuptimeHumananduptimeSeconds.CODE_STYLEGUIDE_GO.md: "Use snake_case for JSON keys."GO_HTTP_SERVER_CONVENTIONS.mdindependently specifiesuptime_secondsanduptime_human. Both authorities agree; the code disagrees with both.Also divergent, same file: the type is
Responserather thanHealthcheckResponse, the method isCheck()rather thanHealthcheck(), andmaintenance_modeis absent (there is noMAINTENANCE_MODEconfig at all).Correct and not to be regressed: the endpoint path
/.well-known/healthcheck,Content-Type: application/json; charset=utf-8,"status":"ok", HTTP 200, and the git hash reaching the output viaVersion.Definition of done
fx.WithLoggerbridges fx's lifecycle logging into the existing slog logger, so the entire process emits one coherent structured stream. Verify by running the binary non-TTY and confirming every startup and shutdown line is valid JSON.logger.Identify()is called at startup (frommain.goor an fxOnStart), or deleted if genuinely unwanted. Do not leave it dead.uptime_seconds,uptime_human. Rename the type and method to match the conventions doc while you are in the file.SENTRY_DSN/METRICS_USERNAME/METRICS_PASSWORDconfig entries so the config surface stops advertising features that do not exist./metricsbehind basic auth is cheap, self-hosted, and immediately useful for a monitoring tool. Sentry adds an external dependency and an outbound network egress to a third party for a service with no users yet — if you want it later it is a small, isolated addition.backend/README.md's config table lists exactly the variables that are actually honoured — no more, no fewer. It currently documents 3 of the 6 defined.cd backend && make checkpasses; rootmake checkpasses.TODO.mdupdated in the same commit.(closes #N).Notes on scope and sequencing
1.0.0milestone. It is real compliance debt, but it does not block a first tag, and #25 may reduce its urgency further. Attach it to the milestone if #25 resolves toward shipping the backend.Recovererpanic-logging fix — that belongs to #23, which is already in that file.Implementation requirements
GO_HTTP_SERVER_CONVENTIONS.mdfor fx wiring, middleware shape, and the metrics route pattern.maketargets only; never rawgoinvocations.Warning before anyone adopts
simplelog: v1.0.0 deadlocks, and the fix tag is unresolvableThis issue notes that
CODE_STYLEGUIDE_GO.mdmandates importingsneak.berlin/go/simplelogfor logging defaults, and that netwatch instead has a hand-rolledinternal/logger. I recorded that as a documented conflict withGO_HTTP_SERVER_CONVENTIONS.md, which mandates the hand-rolled package.Verified: netwatch does not depend on simplelog today. No entry in
backend/go.modorbackend/go.sum, no import anywhere in the Go source. So the following does not affect this repo right now — but it directly affects anyone who acts on the styleguide's instruction, which is a live possibility while this issue is open.The hazard, from elsewhere in the org
simplelog v1.0.0deadlocks on its first log line in any non-TTY context. For this repo that would be catastrophic and near-invisible in testing:internal/loggeralready does TTY detection, so a developer running the binary in a terminal would see nothing wrong, and it would hang on first log in Docker, in CI, and under systemd — every context that actually matters.1.0.1, without the leadingv. Go's module resolver cannot resolve that tag, so the obvious remedy — asking forv1.0.1— fails.v1.0.1-0.20260208172955-9121da9aaed2.What this means for this issue
If the logging half of this issue is ever implemented — swapping
internal/loggerforsimplelogto satisfyCODE_STYLEGUIDE_GO.md— then:v1.0.1-0.20260208172955-9121da9aaed2exactly. Do not takev1.0.0, and do not assumev1.0.1resolves.My standing recommendation is unchanged and this reinforces it: the two authoritative documents conflict, the code currently follows
GO_HTTP_SERVER_CONVENTIONS.md, andinternal/loggerworks. There is no reason to churn it. Adopting a dependency whose latest release tag deadlocks in exactly this service's deployment mode, to satisfy a styleguide line that another authoritative document contradicts, would be a poor trade.Recording it here so the decision is made with the hazard visible rather than discovered afterwards.